1import { useMemo } from "react";
2import { Button } from "@marzneshin/common/components";
3import { DataTableViewOptions } from "./components";
4import { useTranslation } from "react-i18next";
5import { useQuery } from "@tanstack/react-query";
6import { ColumnDef } from "@tanstack/react-table";
7import { EntityTableContext } from "./contexts";
8import { TableSearch, DataTablePagination, EntityDataTable } from "./components";
9import {
10 usePrimaryFiltering,
11 usePagination,
12 useEntityTable,
13 useVisibility,
14 useSorting,
15 type UseRowSelectionReturn,
16 type FetchEntityReturn,
17 type QueryKey,
18 type EntityQueryKeyType,
19 useFilters,
20} from "./hooks";
21
22export interface EntityTableProps<T> {
23 columns: ColumnDef<T>[];
24 primaryFilter: string;
25 entityKey: string;
26 rowSelection?: UseRowSelectionReturn;
27 fetchEntity: ({ queryKey }: EntityQueryKeyType) => FetchEntityReturn<T>;
28 onCreate?: () => void;
29 onOpen?: (entity: any) => void;
30}
31
32export function EntityTable<T>({
33 fetchEntity,
34 columns,
35 primaryFilter,
36 rowSelection,
37 entityKey,
38 onCreate,
39 onOpen,
40}: EntityTableProps<T>) {
41 const { t } = useTranslation();
42 const columnPrimaryFilter = usePrimaryFiltering({ column: primaryFilter });
43 const filters = useFilters();
44 const sorting = useSorting();
45 const visibility = useVisibility();
46 const { onPaginationChange, pageIndex, pageSize } = usePagination();
47
48 const query: QueryKey = [
49 entityKey,
50 {
51 page: pageIndex,
52 size: pageSize,
53 },
54 columnPrimaryFilter.columnFilters,
55 {
56 sortBy: sorting.sorting[0]?.id || "created_at",
57 desc: sorting.sorting[0]?.desc || true,
58 },
59 { filters: filters.columnsFilter }
60 ];
61
62 const { data, isFetching } = useQuery({
63 queryFn: fetchEntity,
64 queryKey: query,
65 initialData: { entities: [], 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.entities, primaryFilter: columnPrimaryFilter, filters, isLoading: isFetching }),
81 [table, data.entities, filters, columnPrimaryFilter, isFetching],
82 );
83
84 return (
85 <EntityTableContext.Provider value={contextValue}>
86 <div className="flex w-full 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 <TableSearch />
97 </div>
98 <div className="w-full rounded-md border">
99 <EntityDataTable columns={columns} onRowClick={onOpen} />
100 <DataTablePagination table={table} />
101 </div>
102 </div>
103 </EntityTableContext.Provider>
104 );
105}