gitscope
← marzneshin / v0.6.5 / dashboard/src/libs/entity-table/selectable-entity-table.tsx
https://dev.kronoz.win/r/marzneshin.git
dashboard/src/libs/entity-table/selectable-entity-table.tsx · TypeScript
Blame Raw
  1import { useEffect, useMemo } from "react";
  2import { DataTableViewOptions } from "./components";
  3import { useQuery } from "@tanstack/react-query";
  4import { RowSelectionState, ColumnDef } from "@tanstack/react-table";
  5import { EntityTableContext } from "./contexts";
  6import { TableSearch, DataTablePagination, EntityDataTable } from "./components";
  7import {
  8    type UseRowSelectionReturn,
  9    usePrimaryFiltering,
 10    usePagination,
 11    type FetchEntityReturn,
 12    useEntityTable,
 13    useVisibility,
 14    useSorting,
 15    type SelectableQueryKey,
 16    type SelectableEntityQueryKeyType,
 17    useFilters,
 18} from "./hooks";
 19
 20export interface SelectableEntityTableProps<T extends { id: number }> {
 21    fetchEntity: ({ queryKey }: SelectableEntityQueryKeyType) => FetchEntityReturn<T>;
 22    columns: ColumnDef<T>[];
 23    primaryFilter: string;
 24    parentEntityKey: string;
 25    parentEntityId: string | number;
 26    entityKey: string;
 27    rowSelection: UseRowSelectionReturn;
 28    entitySelection: {
 29        selectedEntity: number[];
 30        setSelectedEntity: (s: number[]) => void;
 31    }
 32    existingEntityIds: number[];
 33}
 34
 35export function SelectableEntityTable<T extends { id: number }>({
 36    fetchEntity,
 37    columns,
 38    primaryFilter,
 39    rowSelection,
 40    entitySelection,
 41    entityKey,
 42    parentEntityKey,
 43    parentEntityId,
 44    existingEntityIds,
 45}: SelectableEntityTableProps<T>) {
 46    const columnPrimaryFilter = usePrimaryFiltering({ column: primaryFilter });
 47    const filters = useFilters();
 48    const sorting = useSorting();
 49    const visibility = useVisibility();
 50    const { selectedRow, setSelectedRow } = rowSelection;
 51    const { setSelectedEntity } = entitySelection;
 52    const { onPaginationChange, pageIndex, pageSize } = usePagination();
 53    const query: SelectableQueryKey = [
 54        parentEntityKey,
 55        parentEntityId,
 56        entityKey,
 57        {
 58            page: pageIndex,
 59            size: pageSize,
 60        },
 61        columnPrimaryFilter.columnFilters,
 62        {
 63            sortBy: sorting.sorting[0]?.id || "created_at",
 64            desc: sorting.sorting[0]?.desc || true,
 65        },
 66        { filters: filters.columnsFilter }
 67    ];
 68
 69    const { data, isFetching } = useQuery({
 70        queryFn: fetchEntity,
 71        queryKey: query,
 72        initialData: { entities: [], pageCount: 1 },
 73    });
 74
 75    const table = useEntityTable({
 76        data,
 77        columns,
 78        pageSize,
 79        pageIndex,
 80        rowSelection,
 81        visibility,
 82        sorting,
 83        onPaginationChange,
 84    });
 85
 86    useEffect(() => {
 87        setSelectedRow((selected) => {
 88            const updatedSelected: RowSelectionState = { ...selected };
 89            for (const [i, fetchedEntity] of data.entities.entries()) {
 90                if (existingEntityIds.includes(fetchedEntity.id)) {
 91                    updatedSelected[i] = true;
 92                } else {
 93                    updatedSelected[i] = false;
 94                }
 95            }
 96            return updatedSelected;
 97        });
 98
 99    }, [data, setSelectedRow, existingEntityIds]);
100
101    useEffect(() => {
102        const selectedRowId = Object.keys(selectedRow).filter(key => selectedRow[key] === true).map(Number);
103
104        setSelectedEntity(
105            selectedRowId
106                .map(id => data.entities[id]?.id)
107                .filter(id => id !== null && id !== undefined)
108        );
109    }, [data, setSelectedEntity, setSelectedRow, existingEntityIds, selectedRow]);
110
111
112    const contextValue = useMemo(
113        () => ({ table, data: data.entities, primaryFilter: columnPrimaryFilter, filters, isLoading: isFetching }),
114        [table, data.entities, filters, columnPrimaryFilter, isFetching],
115    );
116
117    return (
118        <EntityTableContext.Provider value={contextValue}>
119            <div className="flex flex-col">
120                <div className="flex flex-col md:flex-row-reverse items-center py-4 gap-2 w-full">
121                    <div className="flex flex-row items-center w-full">
122                        <DataTableViewOptions table={table} />
123                    </div>
124                    <TableSearch />
125                </div>
126                <div className="w-full rounded-md border">
127                    <EntityDataTable columns={columns} />
128                    <DataTablePagination table={table} />
129                </div>
130            </div>
131        </EntityTableContext.Provider>
132    );
133}