import * as React from 'react'; import get from 'lodash/get'; import { useObservableState, useSubscription, useObservableEagerState } from 'observable-hooks'; import { debounceTime, skip } from 'rxjs'; import { useTheme } from 'styled-components/native'; import Box from '@wcpos/components/src/box'; import ErrorBoundary from '@wcpos/components/src/error-boundary'; import Loader from '@wcpos/components/src/loader'; import Suspense from '@wcpos/components/src/suspense'; import Table, { TableContextProps, CellRenderer } from '@wcpos/components/src/table'; import Text from '@wcpos/components/src/text'; import type { ProductDocument, OrderDocument, CustomerDocument, TaxRateDocument, } from '@wcpos/database'; import { useReplicationState, Query, useInfiniteScroll } from '@wcpos/query'; import logger from '@wcpos/utils/src/logger'; import EmptyTableRow from './empty-table-row'; import SyncButton from './sync-button'; import TextCell from './text-cell'; import { useT } from '../../../contexts/translations'; import { useUISettings, UISettingID } from '../contexts/ui-settings'; import { useCollectionReset } from '../hooks/use-collection-reset'; type DocumentType = ProductDocument | OrderDocument | CustomerDocument | TaxRateDocument; interface CommonTableProps { id: UISettingID; query: Query; cells: Record>; renderItem?: (props: any) => JSX.Element; noDataMessage: string; estimatedItemSize: number; extraContext?: Partial>; footer?: React.ReactNode; } /** * */ const DataTableFooter = ({ query, children, count }) => { const theme = useTheme(); const { sync, active$, total$ } = useReplicationState(query); const { clear } = useCollectionReset(query.collection.name); const loading = useObservableState(active$, false); const total = useObservableState(total$, 0); const t = useT(); return ( {children} {t('Showing {count} of {total}', { count, total, _tags: 'core' })} ); }; /** * Loading row should be separate from the table component to check loading state from the DataTable */ const LoadingRow = ({ query }) => { const { active$ } = useReplicationState(query); const loading = useObservableState(active$, false); return ; }; /** * */ const DataTable = ({ id, query, cells, renderItem, noDataMessage = 'No record found', estimatedItemSize, extraContext, footer, }: CommonTableProps) => { const { uiSettings, getUILabel } = useUISettings(id); const columns = useObservableEagerState(uiSettings.columns$); const result = useInfiniteScroll(query); const { sortBy, sortDirection } = useObservableState(query.params$, query.getParams()); const listRef = React.useRef(); /** * */ const cellRenderer = React.useCallback>( ({ item, column, index }) => { const Cell = get(cells, [column.key]); if (Cell) { return ( ); } return ; }, [cells] ); /** * */ const context = React.useMemo(() => { return { columns: columns.filter((column) => column.show), sort: result.searchActive ? null : ({ sortBy, sortDirection }) => query.sort(sortBy, sortDirection), sortBy, sortDirection, cellRenderer, headerLabel: ({ column }) => getUILabel(column.key), query, ...extraContext, }; }, [ columns, result.searchActive, sortBy, sortDirection, cellRenderer, query, extraContext, getUILabel, ]); /** * If the query params change, we should scroll to top * - debounceTime so we don't flash the old results */ useSubscription(query.params$.pipe(skip(1), debounceTime(10)), () => { if (listRef?.current) { listRef.current?.scrollToOffset({ offset: 0, animated: false }); } }); /** * */ return ( } onEndReached={() => result.nextPage()} onEndReachedThreshold={0.5} footer={} ListFooterComponent={} /> ); }; export default DataTable;