Viewing File: /home/markqprx/iniasli.pro/client/data-table.tsx
import React, {
cloneElement,
ComponentProps,
ReactElement,
ReactNode,
useState,
} from 'react';
import {TableDataItem} from '../ui/tables/types/table-data-item';
import {BackendFilter} from './filters/backend-filter';
import {MessageDescriptor} from '../i18n/message-descriptor';
import {ColumnConfig} from './column-config';
import {useTrans} from '../i18n/use-trans';
import {useBackendFilterUrlParams} from './filters/backend-filter-url-params';
import {
GetDatatableDataParams,
useDatatableData,
} from './requests/paginated-resources';
import {DataTableContext} from './page/data-table-context';
import {AnimatePresence, m} from 'framer-motion';
import {ProgressBar} from '../ui/progress/progress-bar';
import {Table, TableProps} from '../ui/tables/table';
import {DataTablePaginationFooter} from './data-table-pagination-footer';
import {DataTableHeader} from './data-table-header';
import {FilterList} from './filters/filter-list/filter-list';
import {SelectedStateDatatableHeader} from '@common/datatable/selected-state-datatable-header';
import clsx from 'clsx';
import {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';
import {BackendFiltersUrlKey} from '@common/datatable/filters/backend-filters-url-key';
import {opacityAnimation} from '@common/ui/animation/opacity-animation';
import {FilterListSkeleton} from '@common/datatable/filters/filter-list/filter-list-skeleton';
export interface DataTableProps<T extends TableDataItem> {
filters?: BackendFilter[];
filtersLoading?: boolean;
columns: ColumnConfig<T>[];
searchPlaceholder?: MessageDescriptor;
queryParams?: Record<string, string | number | undefined | null>;
endpoint: string;
resourceName?: ReactNode;
emptyStateMessage: ReactElement<{isFiltering: boolean}>;
actions?: ReactNode;
enableSelection?: boolean;
selectionStyle?: TableProps<T>['selectionStyle'];
selectedActions?: ReactNode;
onRowAction?: TableProps<T>['onAction'];
tableDomProps?: ComponentProps<'table'>;
children?: ReactNode;
collapseTableOnMobile?: boolean;
cellHeight?: string;
}
export function DataTable<T extends TableDataItem>({
filters,
filtersLoading,
columns,
searchPlaceholder,
queryParams,
endpoint,
actions,
selectedActions,
emptyStateMessage,
tableDomProps,
onRowAction,
enableSelection = true,
selectionStyle = 'checkbox',
children,
cellHeight,
collapseTableOnMobile = true,
}: DataTableProps<T>) {
const isMobile = useIsMobileMediaQuery();
const {trans} = useTrans();
const {encodedFilters} = useBackendFilterUrlParams(filters);
const [params, setParams] = useState<GetDatatableDataParams>({perPage: 15});
const [selectedRows, setSelectedRows] = useState<(string | number)[]>([]);
const query = useDatatableData<T>(
endpoint,
{
...params,
...queryParams,
[BackendFiltersUrlKey]: encodedFilters,
},
undefined,
() => setSelectedRows([]),
);
const isFiltering = !!(params.query || params.filters || encodedFilters);
const pagination = query.data?.pagination;
return (
<DataTableContext.Provider
value={{
selectedRows,
setSelectedRows,
endpoint,
params,
setParams,
query,
}}
>
{children}
<AnimatePresence initial={false} mode="wait">
{selectedRows.length ? (
<SelectedStateDatatableHeader
selectedItemsCount={selectedRows.length}
actions={selectedActions}
key="selected"
/>
) : (
<DataTableHeader
searchPlaceholder={searchPlaceholder}
searchValue={params.query}
onSearchChange={query => setParams({...params, query})}
actions={actions}
filters={filters}
filtersLoading={filtersLoading}
key="default"
/>
)}
</AnimatePresence>
{filters && (
<div className="mb-14">
<AnimatePresence initial={false} mode="wait">
{filtersLoading && encodedFilters ? (
<FilterListSkeleton />
) : (
<m.div key="filter-list" {...opacityAnimation}>
<FilterList filters={filters} />
</m.div>
)}
</AnimatePresence>
</div>
)}
<div
className={clsx(
'relative rounded-panel',
(!isMobile || !collapseTableOnMobile) && 'border',
)}
>
{query.isFetching && (
<ProgressBar
isIndeterminate
className="absolute left-0 top-0 z-10 w-full"
aria-label={trans({message: 'Loading'})}
size="xs"
/>
)}
<div className="relative overflow-x-auto md:overflow-hidden">
<Table
{...tableDomProps}
columns={columns}
data={pagination?.data || []}
sortDescriptor={params}
onSortChange={descriptor => {
setParams({...params, ...descriptor});
}}
selectedRows={selectedRows}
enableSelection={enableSelection}
selectionStyle={selectionStyle}
onSelectionChange={setSelectedRows}
onAction={onRowAction}
collapseOnMobile={collapseTableOnMobile}
cellHeight={cellHeight}
/>
</div>
{(query.isFetched || query.isPlaceholderData) &&
!pagination?.data.length ? (
<div className="pt-50">
{cloneElement(emptyStateMessage, {
isFiltering,
})}
</div>
) : undefined}
<DataTablePaginationFooter
query={query}
onPageChange={page => setParams({...params, page})}
onPerPageChange={perPage => setParams({...params, perPage})}
/>
</div>
</DataTableContext.Provider>
);
}
Back to Directory
File Manager