Skip to content

Commit

Permalink
implement usePersistedGridState into current grids
Browse files Browse the repository at this point in the history
  • Loading branch information
rdonigian committed Nov 7, 2024
1 parent a479c21 commit cf430c7
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 142 deletions.
15 changes: 15 additions & 0 deletions src/components/Grid/useDataGridSource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
useGridApiContext,
useGridApiRef,
} from '@mui/x-data-grid-pro';
import { GridInitialStatePro } from '@mui/x-data-grid-pro/models/gridStatePro';
import { groupBy, Nil, setOf } from '@seedcompany/common';
import {
useDebounceFn,
Expand All @@ -39,6 +40,7 @@ import type { Get, Paths, SetNonNullable } from 'type-fest';
import { type PaginatedListInput, type SortableListInput } from '~/api';
import type { Order } from '~/api/schema/schema.graphql';
import { lowerCase, upperCase } from '~/common';
import { usePersistedGridState } from '~/hooks/usePersistedGridState';
import { convertMuiFiltersToApi, FilterShape } from './convertMuiFiltersToApi';

type ListInput = SetNonNullable<
Expand Down Expand Up @@ -99,13 +101,18 @@ export const useDataGridSource = <
initialInput,
keyArgs = defaultKeyArgs,
apiRef: apiRefInput,
sessionStorageProps: sessionStateProps,
}: {
query: DocumentNode<Output, Vars>;
variables: NoInfer<Vars & { input?: Input }>;
listAt: Path;
initialInput?: Partial<Omit<NoInfer<Input>, 'page'>>;
keyArgs?: string[];
apiRef?: MutableRefObject<GridApiPro>;
sessionStorageProps: {
key: string;
defaultValue: GridInitialStatePro;
};
}) => {
const initialInputRef = useLatest(initialInput);
// eslint-disable-next-line react-hooks/rules-of-hooks -- we'll assume this doesn't change between renders
Expand Down Expand Up @@ -418,6 +425,12 @@ export const useDataGridSource = <
}
});

const [savedGridState = {}, onStateChange] = usePersistedGridState({
key: sessionStateProps.key,
apiRef: apiRef,
defaultValue: sessionStateProps.defaultValue,
});

// DataGrid needs help when `rows` identity changes along with picking up
// sorting responsibility ('client').
// Help it out by asking it to sort (again?) when we give it a different,
Expand All @@ -433,10 +446,12 @@ export const useDataGridSource = <
rows,
loading,
rowCount: total,
initialState: savedGridState,
sortModel: view.sortModel,
filterModel: view.filterModel,
hideFooterPagination: true,
onFetchRows: onFetchRows.run,
onStateChange,
onSortModelChange,
onFilterModelChange,
paginationMode: total != null ? 'server' : 'client', // Not used, but prevents row count warning.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@ import {
GridToolbarFilterButton,
useGridApiRef,
} from '@mui/x-data-grid-pro';
import { GridInitialStatePro } from '@mui/x-data-grid-pro/models/gridStatePro';
import { entries } from '@seedcompany/common';
import { useDebounceFn } from 'ahooks';
import { isEqual } from 'lodash';
import { useEffect, useMemo, useRef } from 'react';
import { useMemo } from 'react';
import { extendSx } from '~/common';
import {
getInitialVisibility,
Expand All @@ -21,7 +18,6 @@ import {
Toolbar,
useFilterToggle,
} from '~/components/Grid';
import { useSessionStorage } from '~/hooks/useSessionStorage';
import {
CollapseAllButton,
ExpandAllButton,
Expand Down Expand Up @@ -120,12 +116,6 @@ export const ProgressReportsExpandedGrid = (
props: Omit<ProgressReportsGridProps, 'columns'>
) => {
const apiRef = useGridApiRef();
const [savedGridState, setSavedGridState] =
useSessionStorage<GridInitialStatePro>(
`progress-reports-grid-state`,
initialState
);
const prevState = useRef<GridInitialStatePro | null>(null);

const { expanded, onMouseDown, onRowClick } = useExpandedSetup();

Expand All @@ -137,22 +127,6 @@ export const ProgressReportsExpandedGrid = (
}),
[onMouseDown]
);

const onStateChange = useDebounceFn(
() => {
const gridState = apiRef.current.exportState();
if (!isEqual(gridState, prevState.current)) {
prevState.current = gridState;
setSavedGridState(gridState);
}
},
{ wait: 500, maxWait: 500 }
);

useEffect(() => {
apiRef.current.restoreState(savedGridState);
}, [savedGridState, apiRef]);

return (
<ExpansionContext.Provider value={expanded}>
<ProgressReportsGrid
Expand All @@ -164,7 +138,6 @@ export const ProgressReportsExpandedGrid = (
initialState={initialState}
slotProps={slotProps}
onRowClick={onRowClick}
onStateChange={onStateChange.run}
getRowHeight={(params) =>
expanded.has(params.id) ? 'auto' : COLLAPSED_ROW_HEIGHT
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export interface ProgressReportsGridProps extends DataGridProps {

export const ProgressReportsGrid = ({
quarter,
initialState = {},
...props
}: ProgressReportsGridProps) => {
const source = useMemo(() => {
Expand Down Expand Up @@ -210,9 +211,14 @@ export const ProgressReportsGrid = ({
},
} as const;
}, [quarter]);

const [dataGridProps] = useDataGridSource({
...source,
apiRef: props.apiRef,
sessionStorageProps: {
key: 'progress-reports-grid',
defaultValue: initialState,
},
});

const slots = useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import {
DataGridPro as DataGrid,
DataGridProProps as DataGridProps,
} from '@mui/x-data-grid-pro';
import { GridInitialStatePro } from '@mui/x-data-grid-pro/models/gridStatePro';
import { useDebounceFn } from 'ahooks';
import { isEqual, merge } from 'lodash';
import { useEffect, useMemo, useRef } from 'react';
import { merge } from 'lodash';
import { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import {
EngagementDataGridRowFragment as Engagement,
Expand All @@ -21,17 +19,10 @@ import {
useDataGridSource,
} from '~/components/Grid';
import { TabPanelContent } from '~/components/Tabs';
import { useSessionStorage } from '~/hooks/useSessionStorage';
import { PartnerDetailEngagementsDocument } from './PartnerDetailEngagements.graphql';

export const PartnerDetailEngagements = () => {
const { partnerId = '' } = useParams();
const [savedGridState, setSavedGridState] =
useSessionStorage<GridInitialStatePro>(
`partners-engagements-grid-state-${partnerId}`,
EngagementInitialState
);
const prevState = useRef<GridInitialStatePro | null>(null);

const [props] = useDataGridSource({
query: PartnerDetailEngagementsDocument,
Expand All @@ -40,6 +31,10 @@ export const PartnerDetailEngagements = () => {
initialInput: {
sort: EngagementColumns[0]!.field,
},
sessionStorageProps: {
key: `partners-engagements-grid-state-${partnerId}`,
defaultValue: EngagementInitialState,
},
});

const slots = useMemo(
Expand All @@ -54,21 +49,6 @@ export const PartnerDetailEngagements = () => {
[props.slotProps]
);

const onStateChange = useDebounceFn(
() => {
const gridState = props.apiRef.current.exportState();
if (!isEqual(gridState, prevState.current)) {
prevState.current = gridState;
setSavedGridState(gridState);
}
},
{ wait: 500, maxWait: 500 }
);

useEffect(() => {
props.apiRef.current.restoreState(savedGridState);
}, [savedGridState, props.apiRef]);

return (
<TabPanelContent>
<DataGrid<Engagement>
Expand All @@ -77,10 +57,8 @@ export const PartnerDetailEngagements = () => {
slots={slots}
slotProps={slotProps}
columns={EngagementColumns}
initialState={EngagementInitialState}
headerFilters
hideFooter
onStateChange={onStateChange.run}
sx={[flexLayout, noHeaderFilterButtons, noFooter]}
/>
</TabPanelContent>
Expand Down
34 changes: 6 additions & 28 deletions src/scenes/Partners/Detail/Tabs/Projects/PartnerDetailProjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import {
DataGridProProps as DataGridProps,
GridColDef,
} from '@mui/x-data-grid-pro';
import { GridInitialStatePro } from '@mui/x-data-grid-pro/models/gridStatePro';
import { useDebounceFn } from 'ahooks';
import { isEqual, merge } from 'lodash';
import { useEffect, useMemo, useRef } from 'react';
import { merge } from 'lodash';
import { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { PartnerTypeLabels, PartnerTypeList } from '~/api/schema.graphql';
import { unmatchedIndexThrow } from '~/common';
Expand All @@ -25,27 +23,24 @@ import {
ProjectToolbar,
} from '~/components/ProjectDataGrid';
import { TabPanelContent } from '~/components/Tabs';
import { useSessionStorage } from '~/hooks/useSessionStorage';
import {
PartnerProjectDataGridRowFragment as PartnerProject,
PartnerProjectsDocument,
} from './PartnerProjects.graphql';

export const PartnerDetailProjects = () => {
const { partnerId = '' } = useParams();
const [savedGridState, setSavedGridState] =
useSessionStorage<GridInitialStatePro>(
`partners-projects-grid-state-${partnerId}`,
ProjectInitialState
);
const prevState = useRef<GridInitialStatePro | null>(null);
const [props] = useDataGridSource({
query: PartnerProjectsDocument,
variables: { partnerId },
listAt: 'partner.projects',
initialInput: {
sort: 'name',
},
sessionStorageProps: {
key: `partners-projects-grid-state-${partnerId}`,
defaultValue: ProjectInitialState,
},
});

const slots = useMemo(
Expand All @@ -60,21 +55,6 @@ export const PartnerDetailProjects = () => {
[props.slotProps]
);

const onStateChange = useDebounceFn(
() => {
const gridState = props.apiRef.current.exportState();
if (!isEqual(gridState, prevState.current)) {
prevState.current = gridState;
setSavedGridState(gridState);
}
},
{ wait: 500, maxWait: 500 }
);

useEffect(() => {
props.apiRef.current.restoreState(savedGridState);
}, [savedGridState, props.apiRef]);

return (
<TabPanelContent>
<DataGrid<PartnerProject>
Expand All @@ -83,10 +63,8 @@ export const PartnerDetailProjects = () => {
slots={slots}
slotProps={slotProps}
columns={PartnerProjectColumns}
initialState={ProjectInitialState}
headerFilters
hideFooter
onStateChange={onStateChange.run}
sx={[flexLayout, noHeaderFilterButtons, noFooter]}
/>
</TabPanelContent>
Expand Down
35 changes: 6 additions & 29 deletions src/scenes/Projects/List/EngagementsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import {
DataGridPro as DataGrid,
DataGridProProps as DataGridProps,
} from '@mui/x-data-grid-pro';
import { GridInitialStatePro } from '@mui/x-data-grid-pro/models/gridStatePro';
import { useDebounceFn } from 'ahooks';
import { isEqual, merge } from 'lodash';
import { useEffect, useMemo, useRef } from 'react';
import { merge } from 'lodash';
import { useMemo } from 'react';
import {
EngagementDataGridRowFragment as Engagement,
EngagementColumns,
Expand All @@ -19,24 +17,20 @@ import {
noHeaderFilterButtons,
useDataGridSource,
} from '~/components/Grid';
import { useSessionStorage } from '~/hooks/useSessionStorage';
import { EngagementListDocument } from './EngagementList.graphql';

export const EngagementsPanel = () => {
const [savedGridState, setSavedGridState] =
useSessionStorage<GridInitialStatePro>(
'engagements-grid-state',
EngagementInitialState
);
const prevState = useRef<GridInitialStatePro | null>(null);

const [dataGridProps] = useDataGridSource({
query: EngagementListDocument,
variables: {},
listAt: 'engagements',
initialInput: {
sort: EngagementColumns[0]!.field,
},
sessionStorageProps: {
key: 'engagements-grid',
defaultValue: EngagementInitialState,
},
});

const slots = useMemo(
Expand All @@ -52,32 +46,15 @@ export const EngagementsPanel = () => {
[dataGridProps.slotProps]
);

const onStateChange = useDebounceFn(
() => {
const gridState = dataGridProps.apiRef.current.exportState();
if (!isEqual(gridState, prevState.current)) {
prevState.current = gridState;
setSavedGridState(gridState);
}
},
{ wait: 500, maxWait: 500 }
);

useEffect(() => {
dataGridProps.apiRef.current.restoreState(savedGridState);
}, [savedGridState, dataGridProps.apiRef]);

return (
<DataGrid<Engagement>
{...DefaultDataGridStyles}
{...dataGridProps}
slots={slots}
slotProps={slotProps}
columns={EngagementColumns}
initialState={savedGridState}
headerFilters
hideFooter
onStateChange={onStateChange.run}
sx={[flexLayout, noHeaderFilterButtons, noFooter]}
/>
);
Expand Down
Loading

0 comments on commit cf430c7

Please sign in to comment.