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