Skip to content

Commit

Permalink
feat: updated DataGrid with more functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinGhadyani-Okta committed Jun 12, 2023
1 parent 92dd0d2 commit 17d0e1f
Show file tree
Hide file tree
Showing 2 changed files with 713 additions and 11 deletions.
165 changes: 157 additions & 8 deletions packages/odyssey-react-mui/src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,28 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

import MaterialReactTable from "material-react-table";
import { memo } from "react";
import { Typography } from "@mui/material";
import MaterialReactTable, {
MRT_ColumnFiltersState,
MRT_FilterOptionMenu,
MRT_FullScreenToggleButton,
MRT_RowSelectionState,
MRT_ShowHideColumnsButton,
MRT_TableInstance,
MRT_Virtualizer,
} from "material-react-table";
import {
FunctionComponent,
memo,
UIEvent,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";

export type { MRT_ColumnDef as DataGridColumnType } from "material-react-table";
export type { MRT_ColumnDef as DataGridColumn } from "material-react-table";

type DefaultMaterialReactTableData = Record<string, unknown>;

Expand All @@ -23,28 +41,159 @@ type MaterialReactTableProps<TData extends DefaultMaterialReactTableData> =
export type DataGridProps<TData extends DefaultMaterialReactTableData> = {
columns: MaterialReactTableProps<TData>["columns"];
data: MaterialReactTableProps<TData>["data"];
fetchMoreData?: () => void;
getRowId?: MaterialReactTableProps<TData>["getRowId"];
hasError?: boolean;
hasRowSelection?: boolean;
initialState?: MaterialReactTableProps<TData>["initialState"];
isFetching?: boolean;
onGlobalFilterChange?: MaterialReactTableProps<TData>["onGlobalFilterChange"];
onPaginationChange?: MaterialReactTableProps<TData>["onPaginationChange"];
onRowSelectionChange?: MaterialReactTableProps<TData>["onRowSelectionChange"];
tableState?: MaterialReactTableProps<TData>["state"];
// rowsPerPageOptions?: MaterialReactTableProps<TData>["muiTablePaginationProps"]['rowsPerPageOptions'];
state?: MaterialReactTableProps<TData>["state"];
ToolbarButtons?: FunctionComponent<
{ table: MRT_TableInstance<TData> } & unknown
>;
};

// Once the user has scrolled within this many pixels of the bottom of the table, fetch more data if we can.
const scrollAmountBeforeFetchingData = 400;

const DataGrid = <TData extends DefaultMaterialReactTableData>({
columns,
data,
fetchMoreData,
getRowId,
hasError,
hasRowSelection,
onRowSelectionChange,
tableState,
initialState,
isFetching,
onGlobalFilterChange,
onPaginationChange,
onRowSelectionChange: onRowSelectionChangeProp,
state,
ToolbarButtons,
}: DataGridProps<TData>) => {
const tableContainerRef = useRef<HTMLDivElement>(null);

const rowVirtualizerInstanceRef =
useRef<MRT_Virtualizer<HTMLDivElement, HTMLTableRowElement>>(null);

const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
[]
);

const [globalFilter, setGlobalFilter] = useState<string>();

useEffect(() => {
if (globalFilter) {
onGlobalFilterChange?.(globalFilter);
}
}, [globalFilter, onGlobalFilterChange]);

const totalFetchedRows = data.length ?? 0;

const fetchMoreOnBottomReached = useCallback(
(containerRefElement?: HTMLDivElement | null) => {
if (containerRefElement) {
const { scrollHeight, scrollTop, clientHeight } = containerRefElement;

if (
scrollHeight - scrollTop - clientHeight <
scrollAmountBeforeFetchingData &&
!isFetching
) {
fetchMoreData?.();
}
}
},
[fetchMoreData, isFetching]
);

useEffect(() => {
try {
// Scroll to top of table when sorting or filters change.
rowVirtualizerInstanceRef.current?.scrollToIndex?.(0);
} catch (error) {
console.error(error);
}
}, [columnFilters, globalFilter]);

// Check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data.
useEffect(() => {
fetchMoreOnBottomReached(tableContainerRef.current);
}, [fetchMoreOnBottomReached]);

const renderBottomToolbarCustomActions = useCallback(
() =>
fetchMoreData ? (
<Typography>Fetched {totalFetchedRows} total rows</Typography>
) : (
<Typography>{totalFetchedRows} rows</Typography>
),
[fetchMoreData, totalFetchedRows]
);

// table: MRT_TableInstance<TData>
const renderTopToolbarCustomActions = useCallback<
Exclude<
MaterialReactTableProps<TData>["renderTopToolbarCustomActions"],
undefined
>
>(
({ table }) => <>{ToolbarButtons && <ToolbarButtons table={table} />}</>,
[ToolbarButtons]
);

const [rowSelection, setRowSelection] = useState<MRT_RowSelectionState>({});

useEffect(() => {
onRowSelectionChangeProp?.(rowSelection);
}, [onRowSelectionChangeProp, rowSelection]);

const modifiedState = useMemo(
() => ({
...state,
rowSelection,
}),
[rowSelection, state]
);

return (
<MaterialReactTable
columns={columns}
data={data}
enableMultiRowSelection={hasRowSelection}
enablePagination={false}
enableRowSelection={hasRowSelection}
enableRowVirtualization={data.length > 50}
enableSorting={false}
getRowId={getRowId}
onRowSelectionChange={onRowSelectionChange}
state={tableState}
initialState={initialState}
muiTableContainerProps={{
onScroll: (event: UIEvent<HTMLDivElement>) =>
fetchMoreOnBottomReached(event.target as HTMLDivElement),
ref: tableContainerRef,
sx: { maxHeight: String(500 / 14).concat("rem") },
}}
muiToolbarAlertBannerProps={
hasError
? {
children: "Error loading data.",
color: "error",
}
: undefined
}
onColumnFiltersChange={setColumnFilters}
onGlobalFilterChange={setGlobalFilter}
onPaginationChange={onPaginationChange}
onRowSelectionChange={setRowSelection}
renderBottomToolbarCustomActions={renderBottomToolbarCustomActions}
renderTopToolbarCustomActions={renderTopToolbarCustomActions}
rowVirtualizerInstanceRef={rowVirtualizerInstanceRef}
rowVirtualizerProps={{ overscan: 4 }}
state={modifiedState}
/>
);
};
Expand Down
Loading

0 comments on commit 17d0e1f

Please sign in to comment.