table.js 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import { useShallow } from 'zustand/react/shallow';
  2. import { useTranslation } from 'react-i18next';
  3. import { Text } from 'app/design/typography';
  4. import { View, Row, ScrollView } from 'app/design/view';
  5. import UniList from 'app/ui/atoms/unilist';
  6. import Loading from 'app/ui/atoms/loading';
  7. import GridRow from './row';
  8. import { useGrid } from './context';
  9. /**
  10. * Sticky-width header + virtualized body. Horizontal ScrollView lets wide
  11. * UNA grids scroll instead of squashing text columns.
  12. */
  13. export default function GridTable({ rows, query }) {
  14. const { t } = useTranslation();
  15. const { status, hasNextPage, isFetchingNextPage, isRefetching, handleEndReached, reloadGrid } = query;
  16. const { columns, tableMinWidth, isSortable, sortRows } = useGrid(
  17. useShallow((state) => ({
  18. columns: state.columns,
  19. tableMinWidth: state.tableMinWidth,
  20. isSortable: state.isSortable,
  21. sortRows: state.sortRows,
  22. }))
  23. );
  24. return (
  25. <ScrollView
  26. horizontal
  27. className="w-full"
  28. contentContainerClassName="w-full min-w-full"
  29. showsHorizontalScrollIndicator
  30. >
  31. <View
  32. className="w-full border border-border/60 rounded-lg"
  33. style={{ width: '100%', minWidth: tableMinWidth }}
  34. >
  35. <Row className="w-full items-center gap-2 px-2 py-2 border-b border-border/60">
  36. {columns.map((column, index) => (
  37. <View
  38. key={column.name + index}
  39. style={column.style}
  40. className={`justify-center py-1 min-w-0 ${column.align}`}
  41. >
  42. <Text
  43. className="font-bold text-secondary-foreground text-left"
  44. numberOfLines={1}
  45. >
  46. {column.label}
  47. </Text>
  48. </View>
  49. ))}
  50. </Row>
  51. {(!rows || rows.length === 0) && status === 'success' && !hasNextPage && (
  52. <View className="items-center px-2 pt-4 pb-4">
  53. <Text className="text-secondary-foreground text-center">{t('Nothing to show')}</Text>
  54. </View>
  55. )}
  56. <UniList
  57. height={400}
  58. sortable={isSortable}
  59. onSort={sortRows}
  60. data={rows}
  61. onEndReached={handleEndReached}
  62. refreshing={isRefetching}
  63. onRefresh={reloadGrid}
  64. ListFooterComponent={hasNextPage && isFetchingNextPage ? (
  65. <View className="p-4 items-center">
  66. <Loading size="small" />
  67. </View>
  68. ) : null}
  69. renderItem={({ item }) => <GridRow item={item} />}
  70. />
  71. </View>
  72. </ScrollView>
  73. );
  74. }