@campxdev/react-blueprint 1.6.5 → 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.
- package/package.json +1 -1
- package/src/components/Assets/Icons/IconComponents/PrinterIcon.tsx +42 -0
- package/src/components/Assets/Icons/Icons.tsx +2 -0
- package/src/components/DataDisplay/ActivityLogView/ActivityLogView.tsx +2 -7
- package/src/components/DataDisplay/Card/Card.tsx +1 -1
- package/src/components/DataDisplay/DataTable/TablePagination.tsx +4 -0
- package/src/components/DataDisplay/EditableDataTable/EditableDataTable.tsx +32 -21
- package/src/components/Feedback/Tooltip/ToolTipContent.tsx +15 -0
- package/src/components/Feedback/Tooltip/Tooltip.tsx +3 -17
- package/src/components/Feedback/export.ts +1 -0
- package/src/components/Input/SingleSelect/SingleSelect.tsx +22 -5
- package/src/components/Layout/PageHeader/PageHeader.tsx +52 -42
- package/src/components/Layout/PageHeader/components/DensitySelector/DensitySelector.tsx +2 -2
- package/src/components/Layout/PageHeader/components/SearchBar.tsx +66 -0
- package/src/components/Layout/PageHeader/components/TableColumnsSelector/TableColumnsSelector.tsx +14 -4
- package/src/components/Navigation/ConfirmDialog/ConfirmDialog.tsx +2 -2
- package/src/hooks/usePageHeader.ts +51 -12
- package/src/redux/slices/pageHeaderSlice.ts +71 -9
- package/src/stories/Feedback/Tooltip.stories.tsx +2 -6
- package/src/stories/Input/TextField.stories.tsx +2 -2
package/package.json
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const PrinterIcon = ({ size = 16 }) => {
|
|
2
|
+
return (
|
|
3
|
+
<svg
|
|
4
|
+
width={size}
|
|
5
|
+
height={size}
|
|
6
|
+
viewBox="0 0 16 17"
|
|
7
|
+
fill="none"
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
d="M11.169 5.66634H4.8362C4.70378 5.6655 4.57703 5.61253 4.48339 5.51889C4.38975 5.42525 4.33678 5.29849 4.33594 5.16607V3.83274C4.33594 2.12607 5.129 1.33301 6.8362 1.33301H9.169C10.8757 1.33301 11.6687 2.12607 11.6687 3.83327V5.16661C11.6678 5.29884 11.6148 5.42539 11.5213 5.51889C11.4278 5.6124 11.3012 5.66536 11.169 5.66634ZM5.33594 4.66634H10.6693V3.83327C10.6693 2.69994 10.3029 2.33354 9.16954 2.33354H6.8362C5.70287 2.33354 5.33647 2.69994 5.33647 3.83381L5.33594 4.66634Z"
|
|
12
|
+
fill="#121212"
|
|
13
|
+
stroke="#121212"
|
|
14
|
+
strokeWidth="0.4"
|
|
15
|
+
/>
|
|
16
|
+
<path
|
|
17
|
+
d="M8.669 15.6672H7.33567C5.72234 15.6672 4.83594 14.7808 4.83594 13.1669V10.5002C4.83692 10.3679 4.88995 10.2413 4.98358 10.1478C5.0772 10.0542 5.20388 10.0013 5.3362 10.0005H10.6695C10.802 10.0013 10.9287 10.0543 11.0224 10.1479C11.116 10.2416 11.169 10.3683 11.1698 10.5008V13.1674C11.1693 14.7808 10.2823 15.6672 8.669 15.6672ZM5.83594 11.0005V13.1669C5.83594 14.2202 6.28287 14.6666 7.3362 14.6666H8.66954C9.72234 14.6672 10.1693 14.2202 10.1693 13.1669V11.0005H5.83594Z"
|
|
18
|
+
fill="#121212"
|
|
19
|
+
stroke="#121212"
|
|
20
|
+
strokeWidth="0.4"
|
|
21
|
+
/>
|
|
22
|
+
<path
|
|
23
|
+
d="M12.0003 12.9998H10.6669C10.5347 12.9989 10.4082 12.9459 10.3146 12.8524C10.2211 12.7589 10.1682 12.6323 10.1672 12.5001V10.9998H5.83333V12.4996C5.8325 12.6319 5.77959 12.7586 5.68607 12.8522C5.59255 12.9458 5.46593 12.9989 5.3336 12.9998H4.00027C2.3864 12.9998 1.5 12.1129 1.5 10.4996V7.16677C1.5 5.5529 2.3864 4.6665 4.00027 4.6665H12.0003C13.6136 4.6665 14.5005 5.5529 14.5005 7.16677V10.5001C14.5 12.1129 13.6131 12.9998 12.0003 12.9998ZM11.1667 11.9998H12.0003C13.0536 11.9998 13.5005 11.5529 13.5005 10.5001V7.16677C13.5005 6.11344 13.0536 5.66704 12.0008 5.66704H4.0008C2.94747 5.66704 2.50107 6.11397 2.50107 7.1673V10.5006C2.50107 11.554 2.948 12.0009 4.00133 12.0009H4.83333V10.4996C4.83431 10.3673 4.88727 10.2408 4.98078 10.1473C5.07429 10.0538 5.20083 10.0008 5.33307 9.99984H10.6664C10.7987 10.0007 10.9254 10.0536 11.019 10.1471C11.1127 10.2406 11.1657 10.3672 11.1667 10.4996V11.9998Z"
|
|
24
|
+
fill="#121212"
|
|
25
|
+
stroke="#121212"
|
|
26
|
+
strokeWidth="0.4"
|
|
27
|
+
/>
|
|
28
|
+
<path
|
|
29
|
+
d="M11.3305 11.0005H4.66433C4.532 10.9997 4.40532 10.9467 4.3117 10.8532C4.21808 10.7597 4.16504 10.6331 4.16406 10.5008C4.1649 10.3683 4.21788 10.2416 4.31151 10.1479C4.40515 10.0543 4.53191 10.0013 4.66433 10.0005H11.331C11.4634 10.0013 11.5902 10.0543 11.6838 10.1479C11.7774 10.2416 11.8304 10.3683 11.8313 10.5008C11.8303 10.6332 11.7772 10.7599 11.6834 10.8534C11.5897 10.9469 11.4629 10.9998 11.3305 11.0005Z"
|
|
30
|
+
fill="#121212"
|
|
31
|
+
stroke="#121212"
|
|
32
|
+
strokeWidth="0.4"
|
|
33
|
+
/>
|
|
34
|
+
<path
|
|
35
|
+
d="M6.66433 8.3335H4.66433C4.532 8.33266 4.40532 8.27976 4.3117 8.18623C4.21808 8.09271 4.16504 7.96609 4.16406 7.83376C4.1649 7.70134 4.21788 7.57458 4.31151 7.48095C4.40515 7.38731 4.53191 7.33434 4.66433 7.3335H6.66433C6.79675 7.33434 6.92351 7.38731 7.01714 7.48095C7.11078 7.57458 7.16376 7.70134 7.1646 7.83376C7.16362 7.96609 7.11058 8.09271 7.01696 8.18623C6.92334 8.27976 6.79666 8.33266 6.66433 8.3335Z"
|
|
36
|
+
fill="#121212"
|
|
37
|
+
stroke="#121212"
|
|
38
|
+
strokeWidth="0.4"
|
|
39
|
+
/>
|
|
40
|
+
</svg>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
@@ -78,6 +78,7 @@ import { OpenPaymentsIcon } from './IconComponents/OpenPaymentsIcon';
|
|
|
78
78
|
import { PayxIcon } from './IconComponents/PayxIcon';
|
|
79
79
|
import { PdfIcon } from './IconComponents/PdfIcon';
|
|
80
80
|
import { PeoplexIcon } from './IconComponents/PeoplexIcon';
|
|
81
|
+
import { PrinterIcon } from './IconComponents/PrinterIcon';
|
|
81
82
|
import { ProductFeaturesIcon } from './IconComponents/ProductFeaturesIcon';
|
|
82
83
|
import { ProfileIcon } from './IconComponents/ProfileIcon';
|
|
83
84
|
import QuizIcon from './IconComponents/QuizIcon';
|
|
@@ -116,6 +117,7 @@ import { WhatsappIcon } from './IconComponents/WhatsappIcon';
|
|
|
116
117
|
|
|
117
118
|
export const Icons = {
|
|
118
119
|
NoteIcon,
|
|
120
|
+
PrinterIcon,
|
|
119
121
|
RedoIcon,
|
|
120
122
|
WhatsappIcon,
|
|
121
123
|
SmsIcon,
|
|
@@ -91,12 +91,7 @@ const ActivityLogFilter = ({
|
|
|
91
91
|
disabled={isLoading}
|
|
92
92
|
/>
|
|
93
93
|
<Stack spacing={1} direction="row" ml={1} mt={2}>
|
|
94
|
-
<Button
|
|
95
|
-
onClick={handleFilterSubmit}
|
|
96
|
-
variant="contained"
|
|
97
|
-
disabled={isLoading}
|
|
98
|
-
loading={isLoading}
|
|
99
|
-
>
|
|
94
|
+
<Button onClick={handleFilterSubmit} variant="contained">
|
|
100
95
|
Submit
|
|
101
96
|
</Button>
|
|
102
97
|
</Stack>
|
|
@@ -222,7 +217,7 @@ export const ActivityLogView = ({
|
|
|
222
217
|
</Box>
|
|
223
218
|
))
|
|
224
219
|
)}
|
|
225
|
-
{isFetchingNextPage &&
|
|
220
|
+
{isFetchingNextPage && (
|
|
226
221
|
<StyledSpinnerBox>
|
|
227
222
|
<Spinner />
|
|
228
223
|
</StyledSpinnerBox>
|
|
@@ -57,6 +57,10 @@ export const TablePagination = (props: PaginationProps) => {
|
|
|
57
57
|
},
|
|
58
58
|
}}
|
|
59
59
|
menu={[
|
|
60
|
+
<DropdownMenuItem
|
|
61
|
+
label="10 / Page"
|
|
62
|
+
onClick={() => onLimitChange(Number(10))}
|
|
63
|
+
/>,
|
|
60
64
|
<DropdownMenuItem
|
|
61
65
|
label="20 / Page"
|
|
62
66
|
onClick={() => onLimitChange(Number(20))}
|
|
@@ -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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
190
|
+
|
|
191
|
+
if (deleteVisibilityArray.includes(params.row.id)) {
|
|
181
192
|
actions.push(
|
|
182
193
|
<GridActionsCellItem
|
|
183
194
|
icon={<Icons.DeleteIcon />}
|
|
@@ -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,
|
|
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:
|
|
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
|
-
};
|
|
@@ -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?: {
|
|
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">
|
|
455
|
-
|
|
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 {
|
|
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
|
|
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
|
-
{
|
|
93
|
+
{isTableMode ? <ViewTab title="Default View" /> : viewsSlot}
|
|
94
|
+
|
|
89
95
|
<Stack direction="row" alignItems="center">
|
|
90
|
-
{
|
|
96
|
+
{isTableMode && (
|
|
91
97
|
<FiltersAnchor
|
|
92
98
|
handleClick={() => {
|
|
93
99
|
setExpanded(!expanded);
|
|
94
100
|
}}
|
|
95
101
|
showDot={false}
|
|
96
102
|
/>
|
|
97
|
-
)}
|
|
98
|
-
{
|
|
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
|
-
{
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
+
};
|
package/src/components/Layout/PageHeader/components/TableColumnsSelector/TableColumnsSelector.tsx
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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={{
|
|
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
|
|
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 {
|
|
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 {
|
|
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
|
};
|
|
@@ -1,33 +1,95 @@
|
|
|
1
1
|
import { GridColumnVisibilityModel, GridDensity } from '@mui/x-data-grid';
|
|
2
2
|
import { createSlice } from '@reduxjs/toolkit';
|
|
3
3
|
|
|
4
|
-
export type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export type PageHeaderSingleState = {
|
|
5
|
+
density: GridDensity;
|
|
6
|
+
columnVisibilityModel: GridColumnVisibilityModel;
|
|
7
|
+
filters: {
|
|
8
|
+
search?: string;
|
|
9
|
+
limit: number;
|
|
10
|
+
offset: number;
|
|
11
|
+
skip: number;
|
|
12
|
+
[x: string]: any;
|
|
8
13
|
};
|
|
9
14
|
};
|
|
10
15
|
|
|
16
|
+
export type PageHeaderState = {
|
|
17
|
+
[uniqueId: string]: PageHeaderSingleState;
|
|
18
|
+
};
|
|
19
|
+
|
|
11
20
|
const initialState: PageHeaderState = {};
|
|
12
21
|
|
|
13
22
|
export const pageHeaderSlice = createSlice({
|
|
14
23
|
name: 'pageHeader',
|
|
15
24
|
initialState,
|
|
16
25
|
reducers: {
|
|
17
|
-
|
|
26
|
+
setColumnVisibilityModelForUniqueId: (state, action) => {
|
|
18
27
|
const { uniqueId, columnVisibilityModel } = action.payload;
|
|
19
28
|
state[uniqueId] = { ...state[uniqueId], columnVisibilityModel };
|
|
20
29
|
},
|
|
21
|
-
|
|
30
|
+
setDensityForUniqueId: (state, action) => {
|
|
22
31
|
const { uniqueId, density } = action.payload;
|
|
23
32
|
state[uniqueId] = { ...state[uniqueId], density };
|
|
24
33
|
},
|
|
34
|
+
setSearchForUniqueId: (state, action) => {
|
|
35
|
+
const { uniqueId, search } = action.payload;
|
|
36
|
+
state[uniqueId] = {
|
|
37
|
+
...state[uniqueId],
|
|
38
|
+
filters: {
|
|
39
|
+
...state[uniqueId]?.filters,
|
|
40
|
+
search: search,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
},
|
|
25
44
|
resetStateForUniqueId: (state, action) => {
|
|
26
45
|
const { uniqueId } = action.payload;
|
|
27
|
-
state[uniqueId] = {
|
|
46
|
+
state[uniqueId] = {
|
|
47
|
+
density: 'standard',
|
|
48
|
+
columnVisibilityModel: {},
|
|
49
|
+
filters: {
|
|
50
|
+
limit: 10,
|
|
51
|
+
offset: 0,
|
|
52
|
+
skip: 0,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
setLimitForUniqueId: (state, action) => {
|
|
57
|
+
const { uniqueId, limit } = action.payload;
|
|
58
|
+
state[uniqueId] = {
|
|
59
|
+
...state[uniqueId],
|
|
60
|
+
filters: {
|
|
61
|
+
...state[uniqueId].filters,
|
|
62
|
+
limit: limit,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
setOffsetForUniqueId: (state, action) => {
|
|
67
|
+
const { uniqueId, offset } = action.payload;
|
|
68
|
+
state[uniqueId] = {
|
|
69
|
+
...state[uniqueId],
|
|
70
|
+
filters: {
|
|
71
|
+
...state[uniqueId].filters,
|
|
72
|
+
offset: offset,
|
|
73
|
+
skip: offset,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
setDefaultFiltersForUniqueId: (state, action) => {
|
|
78
|
+
const { uniqueId, defaultFilters } = action.payload;
|
|
79
|
+
state[uniqueId] = {
|
|
80
|
+
...state[uniqueId],
|
|
81
|
+
filters: defaultFilters,
|
|
82
|
+
};
|
|
28
83
|
},
|
|
29
84
|
},
|
|
30
85
|
});
|
|
31
86
|
|
|
32
|
-
export const {
|
|
33
|
-
|
|
87
|
+
export const {
|
|
88
|
+
setColumnVisibilityModelForUniqueId,
|
|
89
|
+
setDensityForUniqueId,
|
|
90
|
+
resetStateForUniqueId,
|
|
91
|
+
setSearchForUniqueId,
|
|
92
|
+
setDefaultFiltersForUniqueId,
|
|
93
|
+
setLimitForUniqueId,
|
|
94
|
+
setOffsetForUniqueId,
|
|
95
|
+
} = pageHeaderSlice.actions;
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
Icons,
|
|
5
|
-
Tooltip,
|
|
6
|
-
ToolTipContent,
|
|
7
|
-
} from '../../components/export';
|
|
2
|
+
import { Button, Icons, Tooltip } from '../../components/export';
|
|
3
|
+
import { ToolTipContent } from '../../components/Feedback/Tooltip/ToolTipContent';
|
|
8
4
|
|
|
9
5
|
export default {
|
|
10
6
|
title: 'Feedback/Tooltip',
|
|
@@ -5,8 +5,8 @@ import { Meta } from '@storybook/react';
|
|
|
5
5
|
import { InputAdornment as MuiInputAdornment } from '@mui/material';
|
|
6
6
|
import { Icons } from '../../components/Assets/Icons/Icons';
|
|
7
7
|
|
|
8
|
-
import { TextField, TextFieldProps, Tooltip
|
|
9
|
-
|
|
8
|
+
import { TextField, TextFieldProps, Tooltip } from '../../components/export';
|
|
9
|
+
import { ToolTipContent } from '../../components/Feedback/Tooltip/ToolTipContent';
|
|
10
10
|
|
|
11
11
|
// Define the default export with Meta type including the component type
|
|
12
12
|
export default {
|