Skip to content

Commit

Permalink
Standard Table (#23)
Browse files Browse the repository at this point in the history
Co-authored-by: João Paulo <[email protected]>
  • Loading branch information
joaorodrs and João Paulo authored Apr 26, 2024
1 parent 35d6c27 commit cf302b3
Show file tree
Hide file tree
Showing 7 changed files with 375 additions and 217 deletions.
122 changes: 122 additions & 0 deletions src/components/DataTable/DataTable.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { useCallback, useEffect, useState } from "react";
import { ComponentMeta } from "@storybook/react";
import DataTable, { Pagination } from "./DataTable";
import { HStack, IconButton } from "@chakra-ui/react";
import { MdArrowRightAlt, MdDelete } from "react-icons/md";
import { format, parseISO } from "date-fns";

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

const firstPage = {
data: [
{
name: "John",
email: "[email protected]",
created_at: new Date().toISOString(),
},
{
name: "Patrick",
email: "[email protected]",
created_at: new Date().toISOString(),
},
],
pagination: {
total: 4,
perPage: 2,
page: 1,
lastPage: 2,
},
};

const secondPage = {
data: [
{
name: "James",
email: "[email protected]",
created_at: new Date().toISOString(),
},
{
name: "Neymar",
email: "[email protected]",
created_at: new Date().toISOString(),
},
],
pagination: {
total: 4,
perPage: 2,
page: 2,
lastPage: 2,
},
};

const getColumns = () => [
{
Header: "Name",
accessor: "name",
},
{
Header: "Email",
accessor: "email",
},
{
Header: "Created at",
accessor: (row: { created_at: string }) =>
format(parseISO(row.created_at), "Pp"),
id: "createdAt",
},
{
Header: "Actions",
Cell: () => (
<HStack>
<IconButton
aria-label="Edit user"
icon={<MdArrowRightAlt size={22} />}
/>
<IconButton aria-label="Delete user" icon={<MdDelete size={22} />} />
</HStack>
),
},
];

export const Primary = () => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<typeof firstPage["data"]>([]);
const [pagination, setPagination] = useState<Pagination>({} as Pagination);
const [page, setPage] = useState(1);

const loadData = useCallback(async () => {
setLoading(true);
const dataToUse: { [x: number]: typeof firstPage } = {
1: firstPage,
2: secondPage,
};

await sleep(1000);
setData(dataToUse[page].data);
setPagination(dataToUse[page].pagination);
setLoading(false);
}, [page]);

useEffect(() => {
loadData();
}, [loadData]);

return (
<DataTable
data={data}
columns={getColumns()}
perPage={2}
pagination={pagination}
page={page}
onChangePage={setPage}
isLoading={loading}
/>
);
};

const config = {
title: "DataTable",
component: DataTable,
} as ComponentMeta<typeof DataTable>;

export default config;
10 changes: 5 additions & 5 deletions src/components/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { useTable } from "react-table";
import PerfectScrollbar from "react-perfect-scrollbar";
import { Container } from "./styles";

type Pagination = {
export type Pagination = {
total: number;
perPage: number;
page: number;
Expand Down Expand Up @@ -85,6 +85,8 @@ function DataTable({
background="gray.200"
color="gray.600"
fontSize="sm"
borderRadius="var(--chakra-radii-md)"
borderBottomRadius={0}
>
<HStack width="100%">
<InputGroup>
Expand Down Expand Up @@ -186,6 +188,8 @@ function DataTable({
background="gray.200"
color="gray.600"
fontSize="sm"
borderRadius="var(--chakra-radii-md)"
borderTopRadius={0}
>
<p>
{page} - {totalPages} of {pagination.total}
Expand All @@ -200,8 +204,6 @@ function DataTable({
aria-label="Go to previous page"
icon={<ChevronLeftIcon />}
disabled={page === 1}
colorScheme="brand"
variant="outline"
/>
<IconButton
aria-label="Go to next page"
Expand All @@ -211,8 +213,6 @@ function DataTable({
}}
icon={<ChevronRightIcon />}
disabled={page === pagination.lastPage}
colorScheme="brand"
variant="outline"
/>
</Stack>
</Box>
Expand Down
114 changes: 114 additions & 0 deletions src/components/StandardTable/StandardTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import DataTable from "@/components/DataTable";

import { useMutation, useQuery, useQueryClient } from "react-query";
import api from "@/services/api";
import { Dispatch, SetStateAction, useCallback, useState } from "react";
import { toast } from "react-toastify";
import ConfirmDialog from "@/components/ConfirmDialog";

export type ColumnsProps = {
currentCell: any;
currentText: string;
setCurrentCell: Dispatch<SetStateAction<null>>;
setCurrentText: Dispatch<SetStateAction<string>>;
onClickDelete: (id: string) => void;
page: number;
searchTerm: string;
appliedFilters: any;
};

type Props = {
endpoint: string;
columns: (args: ColumnsProps) => void;
appliedFilters: any;
onClickFilter: () => void;
};

const StandardTable = ({
endpoint,
columns,
appliedFilters,
onClickFilter,
}: Props) => {
const perPage = 5;
const [page, setPage] = useState(1);
const [searchTerm, setSearchTerm] = useState("");
const [currentCell, setCurrentCell] = useState(null);
const [currentText, setCurrentText] = useState("");
const [idToDelete, setIdToDelete] = useState<string | null>(null);
const queryClient = useQueryClient();
const { mutateAsync, isLoading: isLoadingDeletion } = useMutation(() =>
api.delete(`/${endpoint}/${idToDelete}`)
);

const { data, isLoading, error } = useQuery(
[endpoint, page, searchTerm, appliedFilters],
() =>
api
.get(endpoint, {
params: {
q: searchTerm,
page,
perPage,
order: "created_at",
...appliedFilters,
},
})
.then((response) => response.data)
);

const onSearchDebounced = useCallback((searchTerm: string) => {
setSearchTerm(searchTerm);
}, []);

const onConfirmDeletion = async () => {
try {
await mutateAsync();
queryClient.invalidateQueries([endpoint, page, searchTerm]);
setIdToDelete(null);
toast.success("Item inativado com sucesso!");
} catch (error: any) {
toast.error(error.response?.data.message);
}
};

if (error) {
return <div>Houve um erro: "{(error as { message: string }).message}"</div>;
}

return (
<>
<ConfirmDialog
isOpen={!!idToDelete}
onConfirm={onConfirmDeletion}
onClose={() => setIdToDelete(null)}
isLoading={isLoadingDeletion}
/>
<DataTable
columns={columns({
currentCell,
currentText,
onClickDelete: (id) => {
setIdToDelete(id);
},
setCurrentCell,
setCurrentText,
page,
searchTerm,
appliedFilters,
})}
data={data?.data}
pagination={data?.pagination}
page={page}
onChangePage={setPage}
perPage={perPage}
isLoading={isLoading}
onSearchDebounced={onSearchDebounced}
inputPlaceholder="Procure por nome..."
onClickFilter={onClickFilter}
/>
</>
);
};

export default StandardTable;
1 change: 1 addition & 0 deletions src/components/StandardTable/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./StandardTable";
Loading

0 comments on commit cf302b3

Please sign in to comment.