1import { useMemo } from "react";
2import { Button } from "@marzneshin/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 DoubleEntityQueryKey,
18 type DoubleEntityQueryKeyType,
19 useFilters,
20} from "./hooks";
21
22export interface DoubleEntityTableProps<T> {
23 columns: ColumnDef<T>[];
24 primaryFilter: string;
25 entityKey: string;
26 entityId: number;
27 rowSelection?: UseRowSelectionReturn;
28 fetchEntity: ({ queryKey }: DoubleEntityQueryKeyType) => FetchEntityReturn<T>;
29 onCreate?: () => void;
30 onOpen?: (entity: any) => void;
31}
32
33export function DoubleEntityTable<T>({
34 fetchEntity,
35 columns,
36 primaryFilter,
37 rowSelection,
38 entityKey,
39 entityId,
40 onCreate,
41 onOpen,
42}: DoubleEntityTableProps<T>) {
43 const { t } = useTranslation();
44 const columnPrimaryFilter = usePrimaryFiltering({ column: primaryFilter });
45 const filters = useFilters();
46 const sorting = useSorting();
47 const visibility = useVisibility();
48 const { onPaginationChange, pageIndex, pageSize } = usePagination();
49
50 const query: DoubleEntityQueryKey = [
51 entityKey,
52 entityId,
53 {
54 page: pageIndex,
55 size: pageSize,
56 },
57 columnPrimaryFilter.columnFilters,
58 {
59 sortBy: sorting.sorting[0]?.id || "created_at",
60 desc: sorting.sorting[0]?.desc || true,
61 },
62 { filters: filters.columnsFilter }
63 ];
64
65 const { data, isFetching } = useQuery({
66 queryFn: fetchEntity,
67 queryKey: query,
68 initialData: { entities: [], pageCount: 1 },
69 });
70
71 const table = useEntityTable({
72 data,
73 columns,
74 pageSize,
75 pageIndex,
76 rowSelection,
77 visibility,
78 sorting,
79 onPaginationChange,
80 });
81
82 const contextValue = useMemo(
83 () => ({ table, data: data.entities, primaryFilter: columnPrimaryFilter, filters, isLoading: isFetching }),
84 [table, data.entities, filters, columnPrimaryFilter, isFetching],
85 );
86
87 return (
88 <EntityTableContext.Provider value={contextValue}>
89 <div className="flex flex-col">
90 <div className="flex flex-col md:flex-row-reverse items-center py-4 gap-2 w-full">
91 <div className="flex flex-row items-center w-full">
92 <DataTableViewOptions table={table} />
93 {onCreate && (
94 <Button aria-label={`create-${entityKey}`} onClick={onCreate}>
95 {t("create")}
96 </Button>
97 )}
98 </div>
99 <TableSearch />
100 </div>
101 <div className="w-full rounded-md border">
102 <EntityDataTable columns={columns} onRowClick={onOpen} />
103 <DataTablePagination table={table} />
104 </div>
105 </div>
106 </EntityTableContext.Provider>
107 );
108}