index.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import {
  2. AllCommunityModule,
  3. ClientSideRowModelModule,
  4. ModuleRegistry,
  5. TextFilterModule,
  6. themeQuartz,
  7. } from "ag-grid-community";
  8. import { AgGridReact } from "ag-grid-react";
  9. import type { ReactNode } from "react";
  10. import { useCallback, useMemo, useRef, useState } from "react";
  11. import { Card } from "../Card";
  12. import { Paginator } from "../Paginator";
  13. import { Skeleton } from "../Skeleton";
  14. import styles from "./index.module.scss";
  15. import type { TableGridProps } from "./table-grid-props";
  16. // Register all Community features
  17. ModuleRegistry.registerModules([
  18. AllCommunityModule,
  19. TextFilterModule,
  20. ClientSideRowModelModule,
  21. ]);
  22. const SkeletonCellRenderer = (props: { value?: ReactNode }) => {
  23. if (!props.value) {
  24. return (
  25. <div className={styles.defaultCellContainer}>
  26. <div className={styles.skeletonContainer}>
  27. <Skeleton fill />
  28. </div>
  29. </div>
  30. );
  31. }
  32. return <div className={styles.defaultCellContainer}>{props.value}</div>;
  33. };
  34. const DEFAULT_COL_DEF = {
  35. cellRenderer: SkeletonCellRenderer,
  36. flex: 1,
  37. };
  38. export const TableGrid = <TData extends Record<string, unknown>>({
  39. rowData,
  40. columnDefs,
  41. loading,
  42. cardProps,
  43. pagination,
  44. ...props
  45. }: TableGridProps<TData>) => {
  46. const gridRef = useRef<AgGridReact<TData>>(null);
  47. const [pageSize, setPageSize] = useState(10);
  48. const [currentPage, setCurrentPage] = useState(1);
  49. const [totalPages, setTotalPages] = useState(1);
  50. const mappedColDefs = useMemo(() => {
  51. return columnDefs.map((colDef) => {
  52. return {
  53. ...colDef,
  54. // the types in ag-grid are `any` for the cellRenderers which is throwing an error here
  55. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  56. cellRenderer: loading
  57. ? (colDef.loadingCellRenderer ?? SkeletonCellRenderer)
  58. : colDef.cellRenderer,
  59. };
  60. });
  61. }, [columnDefs, loading]);
  62. const onPaginationChanged = useCallback(() => {
  63. const api = gridRef.current?.api;
  64. if (!api) return;
  65. setPageSize(api.paginationGetPageSize());
  66. setCurrentPage(api.paginationGetCurrentPage() + 1);
  67. setTotalPages(api.paginationGetTotalPages());
  68. }, []);
  69. const onPageChange = useCallback((newPage: number) => {
  70. gridRef.current?.api.paginationGoToPage(newPage - 1);
  71. }, []);
  72. const tableGrid = (
  73. <AgGridReact<TData>
  74. className={styles.tableGrid}
  75. // @ts-expect-error empty row data, which is throwing an error here btu required to display 1 row in the loading state
  76. rowData={loading ? [[]] : rowData}
  77. defaultColDef={DEFAULT_COL_DEF}
  78. columnDefs={mappedColDefs}
  79. theme={themeQuartz}
  80. domLayout="autoHeight"
  81. pagination={pagination ?? false}
  82. paginationPageSize={pageSize}
  83. suppressPaginationPanel
  84. onPaginationChanged={onPaginationChanged}
  85. ref={gridRef}
  86. {...props}
  87. />
  88. );
  89. if (!cardProps && !pagination) {
  90. return tableGrid;
  91. }
  92. return (
  93. <Card
  94. footer={
  95. pagination && (
  96. <Paginator
  97. numPages={totalPages}
  98. currentPage={currentPage}
  99. onPageChange={onPageChange}
  100. pageSize={pageSize}
  101. onPageSizeChange={setPageSize}
  102. />
  103. )
  104. }
  105. {...cardProps}
  106. >
  107. {tableGrid}
  108. </Card>
  109. );
  110. };