1import { FC, useEffect, useState } from "react";
2import { Button, DataTableViewOptions } from "@marzneshin/components";
3import { useTranslation } from "react-i18next";
4import { useQuery } from "@tanstack/react-query";
5import { EntityTableContext } from "./entity-table-provider";
6import { EntityDataTable } from "./table"
7import { DataTablePagination } from "./table-pagination"
8import { TableFiltering } from "./table-filtering";
9import {
10 UseRowSelectionReturn,
11 UseDialogProps,
12 useFiltering,
13 useDialog,
14 usePagination,
15 FetchEntityReturn,
16 useEntityTable,
17 useVisibility,
18 useSorting,
19 SortableQueryKey,
20 QueryKey,
21 EntityQueryKeyType,
22} from "./hooks";
23
24interface EntityTableProps<T> {
25 fetchEntity: ({ queryKey }: EntityQueryKeyType) => FetchEntityReturn<T>;
26 MutationDialog: FC<UseDialogProps<T>>;
27 DeleteConfirmationDialog: FC<UseDialogProps<T>>;
28 SettingsDialog: FC<UseDialogProps<T | any>>;
29 columnsFn: any;
30 filteredColumn: string;
31 entityKey: string
32 rowSelection?: UseRowSelectionReturn
33 manualSorting?: boolean
34}
35
36export function EntityTable<T>({
37 fetchEntity,
38 MutationDialog,
39 DeleteConfirmationDialog,
40 SettingsDialog,
41 columnsFn,
42 filteredColumn,
43 rowSelection,
44 entityKey,
45 manualSorting = false
46}: EntityTableProps<T>) {
47 const [mutationDialogOpen, setMutationDialogOpen] = useDialog();
48 const [deleteDialogOpen, setDeleteDialogOpen] = useDialog();
49 const [settingsDialogOpen, setSettingsDialogOpen] = useDialog();
50 const [selectedEntity, selectEntity] = useState<T | null>(null);
51
52 const onEdit = (entity: T) => {
53 selectEntity(entity);
54 setMutationDialogOpen(true);
55 };
56
57 const onDelete = (entity: T) => {
58 selectEntity(entity);
59 setDeleteDialogOpen(true);
60 };
61
62 const onCreate = () => {
63 selectEntity(null);
64 setMutationDialogOpen(true);
65 };
66
67 const onOpen = (entity: T) => {
68 selectEntity(entity);
69 setSettingsDialogOpen(true);
70 };
71
72 const { t } = useTranslation()
73 const filtering = useFiltering({ column: filteredColumn })
74 const sorting = useSorting()
75 const visibility = useVisibility()
76 const { onPaginationChange, pageIndex, pageSize } = usePagination();
77 const sortedQuery: SortableQueryKey = [
78 entityKey,
79 pageIndex,
80 pageSize,
81 filtering.columnFilters,
82 sorting.sorting[0]?.id ? sorting.sorting[0].id : "created_at",
83 sorting.sorting[0]?.desc]
84 const query: QueryKey = [entityKey, pageIndex, pageSize, filtering.columnFilters]
85
86 const { data, isLoading } = useQuery({
87 queryFn: fetchEntity,
88 queryKey: manualSorting ? sortedQuery : query,
89 initialData: { entity: [], pageCount: 1 }
90 });
91
92 const columns = columnsFn({ onEdit, onDelete, onOpen })
93 const table = useEntityTable({
94 data,
95 columns,
96 pageSize,
97 pageIndex,
98 rowSelection,
99 visibility,
100 sorting,
101 onPaginationChange
102 })
103
104 useEffect(() => table.setPageIndex(1), [filtering.columnFilters, table])
105
106 // TODO: Move the selectedEntity to context
107 return (
108 <EntityTableContext.Provider value={{ table, data: data.entity, filtering, isLoading }}>
109 <SettingsDialog
110 open={settingsDialogOpen}
111 onOpenChange={setSettingsDialogOpen}
112 entity={selectedEntity}
113 />
114 <DeleteConfirmationDialog
115 open={deleteDialogOpen}
116 onOpenChange={setDeleteDialogOpen}
117 entity={selectedEntity}
118 />
119 <MutationDialog
120 open={mutationDialogOpen}
121 onOpenChange={setMutationDialogOpen}
122 entity={selectedEntity}
123 />
124 <div className="flex flex-col">
125 <div className="flex items-center py-4">
126 <TableFiltering />
127 <DataTableViewOptions table={table} />
128 {onCreate && (
129 <Button
130 aria-label={`create-${entityKey}`}
131 onClick={onCreate}>
132 {t('create')}
133 </Button>
134 )}
135 </div>
136 <div className="w-full rounded-md border">
137 <EntityDataTable
138 columns={columns}
139 onRowClick={onOpen}
140 />
141 <DataTablePagination />
142 </div>
143 </div>
144 </EntityTableContext.Provider>
145 );
146}
147
148export * from './hooks'