import React, { useEffect, useMemo, useRef, useState } from "react"; import { Animated, ActivityIndicator, FlatList, ScrollView, } from "react-native"; import { useMediaQuery } from "react-responsive"; import { useFlexLayout, usePagination, useRowSelect, useTable, } from "react-table"; import { useSticky } from "react-table-sticky"; import theme from "mazlo-theme"; import { default as useMazloPagination } from "../../hooks/usePagination"; import useRouterState from "../../hooks/useRouterState"; import { Checkbox } from "../Checkbox"; import { Image } from "../Image"; import { Pagination } from "../Pagination"; import { Text } from "../Text"; import { View } from "../View"; import TableRow from "./TableRow"; import styles from "./styles"; export type Column = { accessor: (() => string) | string; align?: string; id?: string; columns?: Column[]; Header?: (() => string) | string | React.ReactNode; Cell?: (({ cell }) => string) | React.ReactNode; sort?: boolean; sticky?: "left" | "right"; width?: number; minWidth?: number; maxWidth?: number; }; type Props = { columns: Column[]; count?: number; data: any[] | undefined; loading?: boolean; onTableChange?: (params: any) => void; onRowClick?: (rowData: any) => void; rowLinkProps?: (rowData: any) => Record; selectedPageIndex?: number; selectRows?: boolean; total?: number; }; const headerProps = (props, { column }) => getStyles(props, column.align, column.width); const cellProps = (props, { cell }) => getStyles(props, cell.column.align, cell.column.width, cell.column.overflow); const getStyles = (props, align = "left", width = 150, overflow = "hidden") => { return [ props, { style: { justifyContent: "center", alignItems: align === "right" ? "flex-end" : "flex-start", flex: null, flexGrow: width, flexShrink: 0, flexBasis: "auto", overflow, }, }, { style: { ...styles.td, }, }, ]; }; const Table = ({ columns, count, data, loading, onRowClick, onTableChange, rowLinkProps, selectedPageIndex = 0, selectRows = false, total, }: Props) => { const defaultColumn = useMemo( () => ({ width: 150, Cell: ({ cell: { value } }) => {value}, }), [] ); const { onPageChange } = useMazloPagination(); const isTablet = useMediaQuery({ minWidth: theme.breakpoints.sm, }); const { getTableProps, getTableBodyProps, headerGroups, prepareRow, page, pageCount, gotoPage, selectedFlatRows, totalColumnsWidth, state: { pageIndex, selectedRowIds }, } = useTable( { columns, data, defaultColumn, initialState: { pageIndex: selectedPageIndex }, manualPagination: true, pageCount: count ? Math.ceil(total / count) : 0, }, useFlexLayout, usePagination, useRowSelect, useSticky, (hooks) => { if (selectRows) { hooks.visibleColumns.push((initialColumns) => [ { id: "selection", Header: , sort: false, sticky: "left", width: 28, Cell: ({ row }) => { const { onChange, ...rest } = row.getToggleRowSelectedProps(); return ; }, }, ...initialColumns, ]); } } ); const [sort, setSort] = useRouterState("sort"); useEffect(() => { if (onTableChange) { onTableChange({ count, selectedRows: selectedFlatRows, sort }); } }, [count, onTableChange, selectedFlatRows, selectedRowIds, sort]); useEffect(() => { onPageChange(pageIndex); }, [pageIndex]); const [tableWidth, setTableWidth] = useState(0); const scrollOffset = useRef(new Animated.Value(0)); const scrollEvent = useRef( Animated.event( [ { nativeEvent: { contentOffset: { x: scrollOffset.current }, }, }, ], { useNativeDriver: false } ) ); const { style: tableStyle, ...tableProps } = getTableProps(); const { style: tbodyStyle = null, ...tbodyProps } = getTableBodyProps(); if (loading) { return ; } return ( <> totalColumnsWidth ? { flex: 1 } : null } style={styles.tableContainer} scrollEventThrottle={16} onLayout={(e) => setTableWidth(e.nativeEvent.layout.width)} onScroll={scrollEvent.current} > {headerGroups.map((headerGroup, headerGroupIndex) => { const { style: headerGroupStyle, ...headerGroupProps } = headerGroup.getHeaderGroupProps(); return ( {headerGroup.headers.map((column, columnIndex) => { const { style: headerStyle, ...props } = column.getHeaderProps(headerProps); return ( { if (sort === column.id) { setSort(`-${column.id}`); } else if (sort === `-${column.id}`) { setSort(""); } else { setSort(column.id); } gotoPage(0); // if you sort, go back to first page } : null } style={[ headerStyle, styles.th, column.align === "right" ? { justifyContent: "flex-end" } : null, ]} > {column.render("Header")} {!!column.sort && ( )} ); })} ); })} item.original?.id || item.id} extraData={isTablet} style={[tbodyStyle, styles.tbody]} renderItem={({ item: row, index: rowIndex }) => { prepareRow(row); const { key: rowKey, ...rowProps } = row.getRowProps(); return ( {row.cells.map((cell, cellIndex) => { const value = cell.render("Cell"); const { style: cellStyle, ...props } = cell.getCellProps( cellProps ); return ( {value} {!!props["data-sticky-last-left-td"] && ( )} {!!props["data-sticky-first-right-td"] && ( )} ); })} ); }} /> {!!count && ( { gotoPage(i); }} /> )} ); }; export default Table;