@campxdev/react-blueprint 1.6.4 → 1.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/.storybook/preview.tsx +1 -2
  2. package/package.json +1 -1
  3. package/src/App.tsx +71 -46
  4. package/src/components/Assets/Icons/IconComponents/PrinterIcon.tsx +42 -0
  5. package/src/components/Assets/Icons/Icons.tsx +2 -0
  6. package/src/components/DataDisplay/ActivityLogView/ActivityLogView.tsx +228 -0
  7. package/src/components/DataDisplay/ActivityLogView/Icons.tsx +65 -0
  8. package/src/components/DataDisplay/ActivityLogView/service.tsx +101 -0
  9. package/src/components/DataDisplay/ActivityLogView/styles.tsx +52 -0
  10. package/src/components/DataDisplay/Card/Card.tsx +1 -1
  11. package/src/components/DataDisplay/DataTable/TablePagination.tsx +4 -0
  12. package/src/components/DataDisplay/EditableDataTable/EditableDataTable.tsx +32 -21
  13. package/src/components/DataDisplay/export.ts +1 -0
  14. package/src/components/Feedback/Tooltip/ToolTipContent.tsx +15 -0
  15. package/src/components/Feedback/Tooltip/Tooltip.tsx +3 -17
  16. package/src/components/Feedback/export.ts +1 -0
  17. package/src/components/Input/SingleSelect/SingleSelect.tsx +22 -5
  18. package/src/components/Layout/PageHeader/PageHeader.tsx +52 -42
  19. package/src/components/Layout/PageHeader/components/DensitySelector/DensitySelector.tsx +2 -2
  20. package/src/components/Layout/PageHeader/components/SearchBar.tsx +66 -0
  21. package/src/components/Layout/PageHeader/components/TableColumnsSelector/TableColumnsSelector.tsx +14 -4
  22. package/src/components/Navigation/ConfirmDialog/ConfirmDialog.tsx +2 -2
  23. package/src/hooks/usePageHeader.ts +51 -12
  24. package/src/redux/slices/pageHeaderSlice.ts +71 -9
  25. package/src/stories/DataDisplay/ActivityLogView.stories.tsx +96 -0
  26. package/src/stories/Feedback/Tooltip.stories.tsx +2 -6
  27. package/src/stories/Input/TextField.stories.tsx +2 -2
@@ -16,10 +16,11 @@ import { v4 } from 'uuid';
16
16
  import { DataTable, DataTableProps, Icons } from '../../export';
17
17
 
18
18
  export type EditableDataTableProps = {
19
- hideDelete?: boolean;
20
19
  onChange: (rows: GridValidRowModel) => void;
21
20
  onSave?: (params: any) => void;
22
21
  onDelete?: (params: any) => void;
22
+ editVisibilityArray?: number[];
23
+ deleteVisibilityArray?: number[];
23
24
  } & Omit<
24
25
  DataTableProps,
25
26
  | 'rowModesModel'
@@ -29,7 +30,7 @@ export type EditableDataTableProps = {
29
30
  >;
30
31
 
31
32
  export const EditableDataTable = (props: EditableDataTableProps) => {
32
- const { rows } = props;
33
+ const { rows = [] } = props;
33
34
 
34
35
  useEffect(() => {}, [props.columns]);
35
36
 
@@ -43,7 +44,7 @@ export const EditableDataTable = (props: EditableDataTableProps) => {
43
44
 
44
45
  export const EditableTableCore = (props: EditableDataTableProps) => {
45
46
  const theme = useTheme();
46
- const { rows, columns } = props;
47
+ const { rows = [], columns } = props;
47
48
  const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
48
49
  const processRowUpdate = (newRow: GridRowModel) => {
49
50
  const updatedRow = { ...newRow, isNew: false };
@@ -86,6 +87,12 @@ export const EditableTableCore = (props: EditableDataTableProps) => {
86
87
  props.onChange(rows?.filter((row) => row.id !== params.id) ?? []);
87
88
  };
88
89
 
90
+ const deleteVisibilityArray =
91
+ props.deleteVisibilityArray || rows.map((row) => row.id);
92
+
93
+ const editVisibilityArray =
94
+ props.editVisibilityArray || rows.map((row) => row.id);
95
+
89
96
  return (
90
97
  <>
91
98
  <DataTable
@@ -159,25 +166,29 @@ export const EditableTableCore = (props: EditableDataTableProps) => {
159
166
  cellClassName: 'actions',
160
167
  getActions: (params) => {
161
168
  const actions = [];
162
- if (rowModesModel[params.id]?.mode === GridRowModes.Edit) {
163
- actions.push(
164
- <GridActionsCellItem
165
- icon={<Icons.SaveIcon />}
166
- label="Save"
167
- onClick={() => handleSaveClick(params)}
168
- />,
169
- );
170
- } else {
171
- actions.push(
172
- <GridActionsCellItem
173
- icon={<Icons.EditIcon />}
174
- label="Edit"
175
- onClick={() => handleEditClick(params)}
176
- color="inherit"
177
- />,
178
- );
169
+
170
+ if (editVisibilityArray.includes(params.row.id)) {
171
+ if (rowModesModel[params.id]?.mode === GridRowModes.Edit) {
172
+ actions.push(
173
+ <GridActionsCellItem
174
+ icon={<Icons.SaveIcon />}
175
+ label="Save"
176
+ onClick={() => handleSaveClick(params)}
177
+ />,
178
+ );
179
+ } else {
180
+ actions.push(
181
+ <GridActionsCellItem
182
+ icon={<Icons.EditIcon />}
183
+ label="Edit"
184
+ onClick={() => handleEditClick(params)}
185
+ color="inherit"
186
+ />,
187
+ );
188
+ }
179
189
  }
180
- if (!props.hideDelete) {
190
+
191
+ if (deleteVisibilityArray.includes(params.row.id)) {
181
192
  actions.push(
182
193
  <GridActionsCellItem
183
194
  icon={<Icons.DeleteIcon />}
@@ -1,4 +1,5 @@
1
1
  export * from './AccordionGroup/AccordionGroup';
2
+ export * from './ActivityLogView/ActivityLogView';
2
3
  export * from './Avatar/Avatar';
3
4
  export * from './Card/Card';
4
5
  export * from './Chips/Chips';
@@ -0,0 +1,15 @@
1
+ import { Stack } from '@mui/material';
2
+ import { Icons, Typography } from '../../export';
3
+ import { TooltipContentProps } from './Tooltip';
4
+
5
+ export const ToolTipContent = ({ message }: TooltipContentProps) => {
6
+ return (
7
+ <Stack gap={1} sx={{ margin: '5px' }}>
8
+ <Stack direction="row" gap={1}>
9
+ <Icons.BulbIcon />
10
+ <Typography variant="subtitle3">Note:</Typography>
11
+ </Stack>
12
+ <Typography variant="caption">{message}</Typography>
13
+ </Stack>
14
+ );
15
+ };
@@ -2,14 +2,11 @@ import {
2
2
  IconButton,
3
3
  Tooltip as MuiTooltip,
4
4
  TooltipProps as MuiTooltipProps,
5
- Stack,
6
5
  } from '@mui/material';
7
- import { Children, ReactElement } from 'react';
8
- import { BulbIcon } from '../../Assets/Icons/IconComponents/BulbIcon';
9
- import { Typography } from '../../DataDisplay/Typography/Typography';
6
+ import { Children, ReactNode } from 'react';
10
7
 
11
8
  export type TooltipProps = {
12
- children: ReactElement | string;
9
+ children: ReactNode;
13
10
  } & MuiTooltipProps;
14
11
  export type TooltipContentProps = { message: string };
15
12
 
@@ -19,6 +16,7 @@ export const Tooltip = ({
19
16
  ...props
20
17
  }: TooltipProps) => {
21
18
  const isIconButton = Children.only(props.children).type === IconButton;
19
+
22
20
  return (
23
21
  <MuiTooltip {...props} placement={placement} arrow={arrow}>
24
22
  {isIconButton ? (
@@ -29,15 +27,3 @@ export const Tooltip = ({
29
27
  </MuiTooltip>
30
28
  );
31
29
  };
32
-
33
- export const ToolTipContent = ({ message }: TooltipContentProps) => {
34
- return (
35
- <Stack gap={1} sx={{ margin: '5px' }}>
36
- <Stack direction="row" gap={1}>
37
- <BulbIcon />
38
- <Typography variant="subtitle3">Note:</Typography>
39
- </Stack>
40
- <Typography variant="caption">{message}</Typography>
41
- </Stack>
42
- );
43
- };
@@ -2,4 +2,5 @@ export * from './Alert/Alert';
2
2
  export * from './Snackbar/Snackbar';
3
3
  export * from './Spinner/Spinner';
4
4
  export * from './Tooltip/Tooltip';
5
+ export * from './Tooltip/ToolTipContent';
5
6
  export * from './Tutorial/Tutorial';
@@ -6,7 +6,7 @@ import {
6
6
  Paper,
7
7
  } from '@mui/material';
8
8
  import axios, { AxiosInstance } from 'axios';
9
- import _, { debounce } from 'lodash';
9
+ import _, { debounce, startCase } from 'lodash';
10
10
  import { SyntheticEvent, useEffect, useMemo, useReducer } from 'react';
11
11
  import { Typography } from '../../DataDisplay/Typography/Typography';
12
12
  import { Spinner } from '../../Feedback/Spinner/Spinner';
@@ -49,7 +49,12 @@ export type SingleSelectProps = {
49
49
  isInt?: boolean;
50
50
  isFloat?: boolean;
51
51
  };
52
- dbLabelProps?: { labelKey: string; subLabelKey?: string };
52
+ dbLabelProps?: {
53
+ labelKey: string;
54
+ subLabelKey?: string;
55
+ useLabelStartCase?: boolean;
56
+ useSubLabelStartCase?: boolean;
57
+ };
53
58
  onChange?: (value: any) => void;
54
59
  error?: any;
55
60
  helperText?: string;
@@ -102,7 +107,11 @@ export const SingleSelect = ({
102
107
  isInt: false,
103
108
  isFloat: false,
104
109
  },
105
- dbLabelProps,
110
+ dbLabelProps = {
111
+ labelKey: '',
112
+ useLabelStartCase: false,
113
+ useSubLabelStartCase: false,
114
+ },
106
115
  onOpen,
107
116
  onClose,
108
117
  ...restProps
@@ -451,8 +460,16 @@ export const SingleSelect = ({
451
460
  return (
452
461
  <Box component="li" {...props} key={option.value}>
453
462
  <OptionContainer>
454
- <Typography variant="label1">{option.label}</Typography>
455
- <Typography variant="caption">{option?.subLabel}</Typography>
463
+ <Typography variant="label1">
464
+ {dbLabelProps.useLabelStartCase
465
+ ? startCase(option.label)
466
+ : option.label}
467
+ </Typography>
468
+ <Typography variant="caption">
469
+ {dbLabelProps.useSubLabelStartCase
470
+ ? startCase(option?.subLabel)
471
+ : option?.subLabel}
472
+ </Typography>
456
473
  </OptionContainer>
457
474
  </Box>
458
475
  );
@@ -1,6 +1,6 @@
1
1
  import { Box, Divider, Stack, useTheme } from '@mui/material';
2
2
  import { GridColDef } from '@mui/x-data-grid';
3
- import { motion } from 'framer-motion';
3
+ import { AnimatePresence, motion } from 'framer-motion';
4
4
  import { ReactNode, useState } from 'react';
5
5
  import {
6
6
  DensitySelector,
@@ -8,13 +8,19 @@ import {
8
8
  TableColumnsSelector,
9
9
  Typography,
10
10
  } from '../../export';
11
- import { ColumnsAnchor } from './components/Anchors';
11
+ import {
12
+ ColumnsAnchor,
13
+ FiltersAnchor,
14
+ SearchAnchor,
15
+ } from './components/Anchors';
16
+ import { SearchBar } from './components/SearchBar';
12
17
 
13
18
  interface PageHeaderProps {
14
- uniqueId: string;
19
+ uniqueId?: string;
15
20
  viewsSlot?: ReactNode;
16
21
  actions?: ReactNode[];
17
22
  columns?: GridColDef[];
23
+ searchText?: string;
18
24
  }
19
25
 
20
26
  const ViewTab = ({ title }: { title: string }) => {
@@ -42,19 +48,16 @@ const motionDivVariants = {
42
48
  expanded: { height: '102px' },
43
49
  };
44
50
 
45
- const motionTextFieldVariants = {
46
- collapsed: { width: '40px' },
47
- expanded: { width: '300px' },
48
- };
49
-
50
51
  export const PageHeader = ({
51
52
  uniqueId,
52
53
  actions,
53
54
  columns,
54
55
  viewsSlot = <Box></Box>,
56
+ searchText = 'Search',
55
57
  }: PageHeaderProps) => {
56
58
  const [expanded, setExpanded] = useState(false);
57
59
  const [expandedSearch, setExpandedSearch] = useState(false);
60
+
58
61
  const theme = useTheme();
59
62
 
60
63
  const handleSearchClick = () => {
@@ -65,6 +68,8 @@ export const PageHeader = ({
65
68
  setExpandedSearch(false);
66
69
  };
67
70
 
71
+ const isTableMode = columns && uniqueId;
72
+
68
73
  return (
69
74
  <motion.div
70
75
  style={{
@@ -85,17 +90,18 @@ export const PageHeader = ({
85
90
  alignItems="center"
86
91
  justifyContent="space-between"
87
92
  >
88
- {columns ? <ViewTab title="Default View" /> : viewsSlot}
93
+ {isTableMode ? <ViewTab title="Default View" /> : viewsSlot}
94
+
89
95
  <Stack direction="row" alignItems="center">
90
- {/* {columns && (
96
+ {isTableMode && (
91
97
  <FiltersAnchor
92
98
  handleClick={() => {
93
99
  setExpanded(!expanded);
94
100
  }}
95
101
  showDot={false}
96
102
  />
97
- )} */}
98
- {columns && (
103
+ )}
104
+ {isTableMode && (
99
105
  <ColumnsAnchor
100
106
  handleClick={() => {
101
107
  setExpanded(!expanded);
@@ -103,35 +109,39 @@ export const PageHeader = ({
103
109
  showDot={false}
104
110
  />
105
111
  )}
106
- {/* <motion.div
107
- variants={motionTextFieldVariants}
108
- animate={expandedSearch ? 'expanded' : 'collapsed'}
109
- transition={{ duration: 0.3 }}
110
- >
111
- {!expandedSearch && (
112
- <SearchAnchor handleClick={handleSearchClick} showDot={false} />
113
- )}
114
- {expandedSearch && (
115
- <TextField
116
- containerProps={{
117
- margin: '0px',
118
- }}
119
- size="small"
120
- placeholder="Search by name"
121
- // onChange={(e) => { setInput(e.target.value); }}
122
- InputProps={{
123
- startAdornment: (
124
- <InputAdornment position="start">
125
- <Icons.SearchIcon />
126
- </InputAdornment>
127
- ),
128
- }}
129
- onBlur={handleSearchBlur}
130
- autoFocus
131
- />
132
- )}
133
- </motion.div> */}
134
- {columns && <DensitySelector uniqueId={uniqueId} />}
112
+ {isTableMode && (
113
+ <AnimatePresence mode="wait">
114
+ {expandedSearch ? (
115
+ <motion.div
116
+ key="searchBar"
117
+ initial={{ opacity: 0, x: -20, scale: 0.95 }}
118
+ animate={{ opacity: 1, x: 0, scale: 1 }}
119
+ exit={{ opacity: 0, x: 20, scale: 0.95 }}
120
+ transition={{ duration: 0.3 }}
121
+ >
122
+ <SearchBar
123
+ searchText={searchText}
124
+ handleSearchBlur={handleSearchBlur}
125
+ uniqueId={uniqueId}
126
+ />
127
+ </motion.div>
128
+ ) : (
129
+ <motion.div
130
+ key="searchAnchor"
131
+ initial={{ opacity: 0, x: 20, scale: 0.95 }}
132
+ animate={{ opacity: 1, x: 0, scale: 1 }}
133
+ exit={{ opacity: 0, x: -20, scale: 0.95 }}
134
+ transition={{ duration: 0.3 }}
135
+ >
136
+ <SearchAnchor
137
+ handleClick={handleSearchClick}
138
+ showDot={false}
139
+ />
140
+ </motion.div>
141
+ )}
142
+ </AnimatePresence>
143
+ )}
144
+ {isTableMode && <DensitySelector uniqueId={uniqueId} />}
135
145
  {actions?.map((action, index) => action)}
136
146
  </Stack>
137
147
  </Stack>
@@ -144,7 +154,7 @@ export const PageHeader = ({
144
154
  )}
145
155
  {expanded && (
146
156
  <Stack direction="row" width="100%" alignItems="center" gap={2}>
147
- {columns && (
157
+ {columns && uniqueId && (
148
158
  <TableColumnsSelector columns={columns} uniqueId={uniqueId} />
149
159
  )}
150
160
  <Divider
@@ -2,7 +2,7 @@ import { MenuListProps, MenuProps, Stack, useTheme } from '@mui/material';
2
2
  import { GridDensity } from '@mui/x-data-grid';
3
3
  import { capitalize } from 'lodash';
4
4
  import { useDispatch, useSelector } from 'react-redux';
5
- import { setDensity } from '../../../../../redux/slices/pageHeaderSlice';
5
+ import { setDensityForUniqueId } from '../../../../../redux/slices/pageHeaderSlice';
6
6
  import { RootState } from '../../../../../redux/store';
7
7
  import { Button, DropdownMenu, Icons, Typography } from '../../../../export';
8
8
  import { DensityAnchor } from '../Anchors';
@@ -38,7 +38,7 @@ export const DensitySelector = ({
38
38
 
39
39
  const handleMenuClick = (value: GridDensity, close: () => void) => {
40
40
  dispatch(
41
- setDensity({
41
+ setDensityForUniqueId({
42
42
  uniqueId: uniqueId,
43
43
  density: value,
44
44
  }),
@@ -0,0 +1,66 @@
1
+ import { InputAdornment } from '@mui/material';
2
+ import { debounce } from 'lodash';
3
+ import React, { useMemo } from 'react';
4
+ import { useDispatch, useSelector } from 'react-redux';
5
+ import { setSearchForUniqueId } from '../../../../redux/slices/pageHeaderSlice';
6
+ import { RootState } from '../../../../redux/store';
7
+ import { Icons, TextField } from '../../../export';
8
+
9
+ export const SearchBar = ({
10
+ handleSearchBlur,
11
+ uniqueId,
12
+ searchText,
13
+ }: {
14
+ handleSearchBlur: () => void;
15
+ uniqueId: string;
16
+ searchText: string;
17
+ }) => {
18
+ const dispatch = useDispatch();
19
+
20
+ const search = useSelector(
21
+ (state: RootState) => state.pageHeader[uniqueId]?.filters?.search,
22
+ );
23
+
24
+ // Wrap onSearch in useCallback
25
+ const onSearch = (value: string) => {
26
+ dispatch(
27
+ setSearchForUniqueId({
28
+ uniqueId: uniqueId,
29
+ search: value,
30
+ }),
31
+ );
32
+ };
33
+
34
+ // Now we can memoize a debounced version of onSearch
35
+ const debouncedSendRequest = useMemo(
36
+ () => debounce(onSearch, 300),
37
+ [onSearch],
38
+ );
39
+
40
+ // Pass the updated value to the debounced function in onChange
41
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
42
+ debouncedSendRequest(e.target.value);
43
+ };
44
+
45
+ return (
46
+ <TextField
47
+ containerProps={{
48
+ margin: '0px',
49
+ width: '300px',
50
+ }}
51
+ size="small"
52
+ placeholder={searchText}
53
+ defaultValue={search || ''}
54
+ onChange={handleChange}
55
+ InputProps={{
56
+ startAdornment: (
57
+ <InputAdornment position="start">
58
+ <Icons.SearchIcon />
59
+ </InputAdornment>
60
+ ),
61
+ }}
62
+ onBlur={handleSearchBlur}
63
+ autoFocus
64
+ />
65
+ );
66
+ };
@@ -3,7 +3,7 @@ import { MenuListProps, MenuProps, Typography, useTheme } from '@mui/material';
3
3
  import { GridColDef, GridColumnVisibilityModel } from '@mui/x-data-grid';
4
4
  import { useState } from 'react';
5
5
  import { useDispatch, useSelector } from 'react-redux';
6
- import { setColumnVisibilityModel } from '../../../../../redux/slices/pageHeaderSlice';
6
+ import { setColumnVisibilityModelForUniqueId } from '../../../../../redux/slices/pageHeaderSlice';
7
7
  import { RootState } from '../../../../../redux/store';
8
8
  import { Button, Icons, SearchBar, SingleCheckBox } from '../../../../export';
9
9
  import { DropdownMenu } from '../../../../Navigation/export';
@@ -45,7 +45,7 @@ export const TableColumnsSelector = ({
45
45
  [column.field]: !checked,
46
46
  };
47
47
  dispatch(
48
- setColumnVisibilityModel({
48
+ setColumnVisibilityModelForUniqueId({
49
49
  uniqueId: uniqueId,
50
50
  columnVisibilityModel: newColumnVisibilityModel,
51
51
  }),
@@ -77,7 +77,17 @@ export const TableColumnsSelector = ({
77
77
  Columns
78
78
  </Button>
79
79
  )}
80
- menuProps={{ ...props.menuProps }}
80
+ menuProps={{
81
+ ...props.menuProps,
82
+ anchorOrigin: {
83
+ vertical: 'bottom',
84
+ horizontal: 'left',
85
+ },
86
+ transformOrigin: {
87
+ vertical: 'top',
88
+ horizontal: 'left',
89
+ },
90
+ }}
81
91
  menuHeader={
82
92
  <SearchBar
83
93
  fullWidth
@@ -89,7 +99,7 @@ export const TableColumnsSelector = ({
89
99
  />
90
100
  }
91
101
  menuListContainerSx={{
92
- margin: '10px 2px 0px 0px',
102
+ margin: '10px 5px 0px 5px',
93
103
  gap: 1,
94
104
  maxHeight: '350px',
95
105
  }}
@@ -36,7 +36,7 @@ export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
36
36
  open={isOpen}
37
37
  content={({ close }) => {
38
38
  return (
39
- <>
39
+ <Box sx={{ padding: '16px' }}>
40
40
  <Stack direction="row" alignItems="center">
41
41
  <img
42
42
  src={
@@ -71,7 +71,7 @@ export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
71
71
  {confirmButtonText}
72
72
  </Button>
73
73
  </Stack>
74
- </>
74
+ </Box>
75
75
  );
76
76
  }}
77
77
  onClose={onCancel}
@@ -1,30 +1,69 @@
1
- import { GridColumnVisibilityModel, GridDensity } from '@mui/x-data-grid';
2
- import { useRef } from 'react';
1
+ import { useEffect, useRef } from 'react';
3
2
  import { useDispatch, useSelector } from 'react-redux';
4
3
  import { v4 } from 'uuid';
5
- import { resetStateForUniqueId } from '../redux/slices/pageHeaderSlice';
4
+ import {
5
+ PageHeaderSingleState,
6
+ resetStateForUniqueId,
7
+ setDefaultFiltersForUniqueId,
8
+ setLimitForUniqueId,
9
+ setOffsetForUniqueId,
10
+ } from '../redux/slices/pageHeaderSlice';
6
11
  import { RootState } from '../redux/store';
7
12
 
8
- export const usePageHeader = () => {
13
+ export const usePageHeader = (defaultFilters?: { [x: string]: any }) => {
9
14
  const uuidRef = useRef(v4());
10
15
  const dispatch = useDispatch();
11
- const filterState = useSelector(
12
- (state: RootState) =>
13
- state.pageHeader[uuidRef.current] ||
14
- ({} as {
15
- density: GridDensity;
16
- columnVisibilityModel: GridColumnVisibilityModel;
17
- }),
18
- );
19
16
 
20
17
  const resetState = () => {
21
18
  dispatch(resetStateForUniqueId({ uniqueId: uuidRef.current }));
22
19
  };
23
20
 
21
+ const setDefaultFilters = (defaultFilters: { [x: string]: any }) => {
22
+ dispatch(
23
+ setDefaultFiltersForUniqueId({
24
+ uniqueId: uuidRef.current,
25
+ defaultFilters,
26
+ }),
27
+ );
28
+ };
29
+
30
+ const onLimitChange = (limit: number) => {
31
+ dispatch(
32
+ setLimitForUniqueId({
33
+ uniqueId: uuidRef.current,
34
+ limit,
35
+ }),
36
+ );
37
+ };
38
+
39
+ const onPageChange = (offset: number) => {
40
+ dispatch(
41
+ setOffsetForUniqueId({
42
+ uniqueId: uuidRef.current,
43
+ offset,
44
+ }),
45
+ );
46
+ };
47
+
48
+ useEffect(() => {
49
+ if (defaultFilters)
50
+ setDefaultFilters({ limit: 10, offset: 0, skip: 0, ...defaultFilters });
51
+ }, []);
52
+
53
+ const filterState = useSelector(
54
+ (state: RootState) =>
55
+ state.pageHeader[uuidRef.current] ||
56
+ ({ filters: { limit: 10, offset: 0, skip: 0 } } as PageHeaderSingleState),
57
+ );
58
+
24
59
  return {
25
60
  columnVisibilityModel: filterState.columnVisibilityModel,
26
61
  density: filterState.density,
62
+ filters: { ...defaultFilters, ...filterState.filters },
27
63
  uniqueId: uuidRef.current,
28
64
  resetState,
65
+ setDefaultFilters,
66
+ onPageChange,
67
+ onLimitChange,
29
68
  };
30
69
  };