1import { useMemo } from "react";
2import { Button, DataTableViewOptions } from "@marzneshin/components";
3import { useTranslation } from "react-i18next";
4import { useQuery } from "@tanstack/react-query";
5import { EntityTableContext } from "./contexts";
6import { TableFiltering, DataTablePagination, EntityDataTable } from "./components";
7import {
8 type UseRowSelectionReturn,
9 useFiltering,
10 usePagination,
11 type FetchEntityReturn,
12 useEntityTable,
13 useVisibility,
14 useSorting,
15 type SortableQueryKey,
16 type QueryKey,
17 type EntityQueryKeyType,
18} from "./hooks";
19
20export interface EntityTableProps<T> {
21 fetchEntity: ({ queryKey }: EntityQueryKeyType) => FetchEntityReturn<T>;
22 columnsFn: any;
23 filteredColumn: string;
24 entityKey: string;
25 rowSelection?: UseRowSelectionReturn;
26 manualSorting?: boolean;
27 onCreate: () => void;
28 onEdit: (entity: T) => void;
29 onOpen: (entity: T) => void;
30 onDelete: (entity: T) => void;
31}
32
33export function EntityTable<T>({
34 fetchEntity,
35 columnsFn,
36 filteredColumn,
37 rowSelection,
38 entityKey,
39 manualSorting = false,
40 onCreate,
41 onEdit,
42 onOpen,
43 onDelete,
44}: EntityTableProps<T>) {
45 const { t } = useTranslation();
46 const filtering = useFiltering({ column: filteredColumn });
47 const sorting = useSorting();
48 const visibility = useVisibility();
49 const { onPaginationChange, pageIndex, pageSize } = usePagination();
50 const sortedQuery: SortableQueryKey = [
51 entityKey,
52 pageIndex,
53 pageSize,
54 filtering.columnFilters,
55 sorting.sorting[0]?.id ? sorting.sorting[0].id : "created_at",
56 sorting.sorting[0]?.desc,
57 ];
58 const query: QueryKey = [
59 entityKey,
60 pageIndex,
61 pageSize,
62 filtering.columnFilters,
63 ];
64
65 const { data, isFetching } = useQuery({
66 queryFn: fetchEntity,
67 queryKey: manualSorting ? sortedQuery : query,
68 initialData: { entity: [], pageCount: 1 },
69 });
70
71 const columns = columnsFn({ onEdit, onDelete, onOpen });
72 const table = useEntityTable({
73 data,
74 columns,
75 pageSize,
76 pageIndex,
77 rowSelection,
78 visibility,
79 sorting,
80 onPaginationChange,
81 });
82
83 const contextValue = useMemo(
84 () => ({ table, data: data.entity, filtering, isLoading: isFetching }),
85 [table, data.entity, filtering, isFetching],
86 );
87
88 return (
89 <EntityTableContext.Provider value={contextValue}>
90 <div className="flex flex-col">
91 <div className="flex items-center py-4">
92 <TableFiltering />
93 <DataTableViewOptions table={table} />
94 {onCreate && (
95 <Button aria-label={`create-${entityKey}`} onClick={onCreate}>
96 {t("create")}
97 </Button>
98 )}
99 </div>
100 <div className="w-full rounded-md border">
101 <EntityDataTable columns={columns} onRowClick={onOpen} />
102 <DataTablePagination />
103 </div>
104 </div>
105 </EntityTableContext.Provider>
106 );
107}