Skip to content

Commit

Permalink
Refactor ListItem to allow filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
EduardoPicolo committed Aug 28, 2022
1 parent 4011075 commit e615f29
Show file tree
Hide file tree
Showing 24 changed files with 271 additions and 248 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# testing
/coverage
/metrics
# *.spec.*

# next.js
/.next/
Expand Down
2 changes: 1 addition & 1 deletion src/components/ActionButtons/ActionButton.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
type ReactElement = import("react").ReactElement

interface ActionButton<Item> {
onClick: (() => void | Promise<void>) | ((item: Item) => void | Promise<void>)
onClick: (item: Item) => void | Promise<void>
label?: string
}
4 changes: 2 additions & 2 deletions src/components/Forms/CategoriaForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
} from "@chakra-ui/react"

interface CategoriaFormProps {
defaultValues?: IProblemCategory | undefined
defaultValues?: CategoriaProblema | undefined
onSubmit:
| ((data: IProblemCategoryPayload) => void)
| ((data: CategoriaProblemaPayload) => void)
| ((data: ProblemTypePayload) => void)
}

Expand Down
6 changes: 3 additions & 3 deletions src/components/Forms/CidadeForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import {
} from "@chakra-ui/react"

interface CidadeFormProps {
defaultValues?: ICity | undefined
onSubmit: (data: ICityPayload) => void
defaultValues?: City | undefined
onSubmit: (data: CityPayload) => void
}

export const CidadeForm = ({ defaultValues, onSubmit }: CidadeFormProps) => {
const {
register,
handleSubmit,
formState: { errors, isSubmitting }
} = useForm<ICityPayload>({
} = useForm<CityPayload>({
defaultValues
})

Expand Down
4 changes: 2 additions & 2 deletions src/components/Forms/UserForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {

interface UserFormProps {
defaultValues?: User | undefined
onSubmit: (data: CreateUserPayload) => void
onSubmit: (data: RegisterUserPayload) => void
}

export const UserForm = ({ defaultValues, onSubmit }: UserFormProps) => {
Expand All @@ -23,7 +23,7 @@ export const UserForm = ({ defaultValues, onSubmit }: UserFormProps) => {
handleSubmit,
watch,
formState: { errors, isSubmitting }
} = useForm<CreateUserPayload>({
} = useForm<RegisterUserPayload>({
defaultValues: {
...defaultValues,
password: ""
Expand Down
26 changes: 14 additions & 12 deletions src/components/List/List.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { render } from "@testing-library/react"

import { EditButton } from "@components/ActionButtons/EditButton"
import { ListItem } from "@components/ListItem"
import { Item } from "@components/ListItem"

import { List } from "./index"
import { ListView } from "./index"

const mockedData = [
{
Expand All @@ -16,9 +16,19 @@ const mockedData = [
}
]

const renderItem = (item: typeof mockedData[number]) => (
<Item title={item.title} description={item.description}>
<Item.Actions item={item}>
<EditButton onClick={jest.fn()} />
</Item.Actions>
</Item>
)

describe("List", () => {
it("should render with loading state", async () => {
const { getAllByTestId } = render(<List isLoading>{undefined}</List>)
const { getAllByTestId } = render(
<ListView isLoading items={mockedData} render={renderItem} />
)

const skeletons = getAllByTestId("list-item-skeleton")

Expand All @@ -27,15 +37,7 @@ describe("List", () => {

it("should render with data", async () => {
const { getAllByText } = render(
<List isLoading>
{mockedData?.map?.((item, key) => (
<ListItem title={item.title} description={item.description} key={key}>
<ListItem.Actions item={item}>
<EditButton onClick={jest.fn()} />
</ListItem.Actions>
</ListItem>
))}
</List>
<ListView isLoading={false} items={mockedData} render={renderItem} />
)

expect(getAllByText(/Title \d/i)).toBeTruthy()
Expand Down
35 changes: 20 additions & 15 deletions src/components/List/index.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import { ReactElement } from "react"
import { StackProps, VStack } from "@chakra-ui/react"
import { Fade, List, ListItem, ListProps } from "@chakra-ui/react"

import { ListItemProps } from "@components/ListItem"
import { ListItemSkeleton } from "@components/ListItem/LIstItemSkeleton"
import { ItemProps } from "@components/ListItem"
import { ListItemSkeleton } from "@components/ListItem/ListItemSkeleton"

interface ListProps<Data> extends StackProps {
interface ListViewProps<Data> extends ListProps {
items: Data[] | undefined
render: (item: Data) => ReactElement<ItemProps<Data>>
isLoading: boolean
children:
| ReactElement<ListItemProps<Data>>
| ReactElement<ListItemProps<Data>>[]
| undefined
}

export const List = <Data,>({
children,
export const ListView = <Data,>({
items,
render,
isLoading,
...props
}: ListProps<Data>) => {
}: ListViewProps<Data>) => {
return (
<VStack align="stretch" spacing={6} {...props}>
{children}
{isLoading && <ListItemSkeleton />}
</VStack>
<List spacing={6} {...props}>
{items?.map((item, key) => (
<Fade in key={key}>
<ListItem>{render(item)}</ListItem>
</Fade>
))}

{isLoading &&
Array.from({ length: 4 }, (_, key) => <ListItemSkeleton key={key} />)}
</List>
)
}
37 changes: 0 additions & 37 deletions src/components/ListItem/LIstItemSkeleton.tsx

This file was deleted.

14 changes: 7 additions & 7 deletions src/components/ListItem/ListItem.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { render, waitFor } from "@testing-library/react"
import { DeleteButton } from "@components/ActionButtons/DeleteButton"
import { EditButton } from "@components/ActionButtons/EditButton"

import { ListItem } from "./index"
import { Item } from "./index"

const callback = jest.fn((item) => item)
const mockedProps = {
Expand All @@ -13,10 +13,10 @@ const mockedProps = {
}
}

describe("ListItem", () => {
describe("Item", () => {
it("should render with the passed props", async () => {
const { getByText } = render(
<ListItem
<Item
title={mockedProps.item.title}
description={mockedProps.item.description}
/>
Expand All @@ -33,15 +33,15 @@ describe("ListItem", () => {

it("should have actions", async () => {
const { getByRole } = render(
<ListItem
<Item
title={mockedProps.item.title}
description={mockedProps.item.description}
>
<ListItem.Actions item={mockedProps.item}>
<Item.Actions item={mockedProps.item}>
<EditButton onClick={callback} />
<DeleteButton onClick={callback} />
</ListItem.Actions>
</ListItem>
</Item.Actions>
</Item>
)

const actionsBar = getByRole("menubar")
Expand Down
27 changes: 27 additions & 0 deletions src/components/ListItem/ListItemSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Fade, Flex, HStack, Skeleton, VStack } from "@chakra-ui/react"

export const ListItemSkeleton = () => (
<Fade in data-testid="list-item-skeleton">
<Flex
w="100%"
justifyContent="space-between"
alignItems="center"
pb={2}
bg="white"
borderRadius="md"
padding={4}
boxShadow="medium"
height="92px"
>
<VStack spacing={2} alignItems="start">
<Skeleton height="24px" w={175} />
<Skeleton height="16px" w={280} />
</VStack>
<HStack spacing={4} alignSelf="end">
<Skeleton height="40px" width="40px" alignSelf="end" />
<Skeleton height="40px" width="40px" alignSelf="end" />
<Skeleton height="40px" width="40px" alignSelf="end" />
</HStack>
</Flex>
</Fade>
)
51 changes: 27 additions & 24 deletions src/components/ListItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React, { ReactElement } from "react"
import { Box, Fade, Flex } from "@chakra-ui/react"
import { Box, Flex } from "@chakra-ui/react"

import type { ActionsProps } from "@components/ListItem/ListItemActions"
import { Actions } from "@components/ListItem/ListItemActions"

export interface ListItemProps<Data> {
export interface ItemProps<Data> {
title: string | JSX.Element
description: string | JSX.Element
children?: ReactElement<ActionsProps<Data>>
}

export const Divider = {
export const customDivider = {
content: "''",
position: "absolute",
bottom: "0",
Expand All @@ -19,33 +19,36 @@ export const Divider = {
backgroundColor: "#e6e6e6"
}

export const ListItem = <Data,>({
export const Item = <Data,>({
title,
description,
children
}: ListItemProps<Data>) => {
}: ItemProps<Data>) => {
return (
<Fade in>
<Flex
w="100%"
justifyContent="space-between"
position="relative"
bg="white"
borderRadius="md"
padding={5}
boxShadow="medium"
>
<Box alignSelf="center">
<Box fontWeight="medium" mb={1} position="relative" _before={Divider}>
{title}
</Box>
<Box color="GrayText">{description}</Box>
<Flex
w="100%"
justifyContent="space-between"
position="relative"
bg="white"
borderRadius="md"
padding={5}
boxShadow="medium"
>
<Box alignSelf="center">
<Box
fontWeight="medium"
mb={1}
position="relative"
_before={customDivider}
>
{title}
</Box>
<Box color="GrayText">{description}</Box>
</Box>

<Box alignSelf="end">{children}</Box>
</Flex>
</Fade>
<Box alignSelf="end">{children}</Box>
</Flex>
)
}

ListItem.Actions = Actions
Item.Actions = Actions
Empty file removed src/pages/api/.gitkeep
Empty file.
Loading

0 comments on commit e615f29

Please sign in to comment.