@campxdev/react-blueprint 1.2.16 → 1.2.17
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/DataDisplay/Card/Card.tsx +6 -1
- package/src/components/DataDisplay/DataTable/DataTable.tsx +1 -0
- package/src/components/DataDisplay/EditableDataTable/EditableDataTable.tsx +209 -0
- package/src/components/DataDisplay/export.ts +1 -0
- package/src/components/Input/SingleSelect/SingleSelect.tsx +55 -20
- package/src/components/Layout/AppHeader/AppHeader.tsx +10 -2
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from '@mui/material';
|
|
10
10
|
import { Variant } from '@mui/material/styles/createTypography';
|
|
11
11
|
import { ReactNode } from 'react';
|
|
12
|
-
import { DropDownIcon, DropdownMenu } from '../../export';
|
|
12
|
+
import { DropDownIcon, DropdownMenu, Switch, SwitchProps } from '../../export';
|
|
13
13
|
import {
|
|
14
14
|
StyledButton,
|
|
15
15
|
StyledCardActions,
|
|
@@ -46,6 +46,8 @@ export interface CardProps {
|
|
|
46
46
|
imageSrc?: string;
|
|
47
47
|
titleImgIcon?: ReactNode;
|
|
48
48
|
checkBox?: boolean;
|
|
49
|
+
hasSwitch?: boolean;
|
|
50
|
+
switchProps?: SwitchProps;
|
|
49
51
|
moreOptions?: boolean;
|
|
50
52
|
menu?: Array<ReactNode>;
|
|
51
53
|
icon?: ReactNode;
|
|
@@ -76,6 +78,8 @@ export const Card = ({
|
|
|
76
78
|
icon,
|
|
77
79
|
children,
|
|
78
80
|
menu = [],
|
|
81
|
+
switchProps,
|
|
82
|
+
hasSwitch,
|
|
79
83
|
}: CardProps) => {
|
|
80
84
|
const handleClick = (e: any) => {
|
|
81
85
|
footer?.onClick();
|
|
@@ -106,6 +110,7 @@ export const Card = ({
|
|
|
106
110
|
</Stack>
|
|
107
111
|
</Stack>
|
|
108
112
|
<Stack flexDirection={'row'} gap={'12px'} alignItems={'center'}>
|
|
113
|
+
{hasSwitch && <Switch {...switchProps} />}
|
|
109
114
|
{status && (
|
|
110
115
|
<StyledStatusText variant="label2" sx={statusSx}>
|
|
111
116
|
{status}{' '}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { Button } from '@mui/material';
|
|
2
|
+
import {
|
|
3
|
+
GridActionsCellItem,
|
|
4
|
+
GridColDef,
|
|
5
|
+
GridEventListener,
|
|
6
|
+
GridRowEditStopReasons,
|
|
7
|
+
GridRowModel,
|
|
8
|
+
GridRowModes,
|
|
9
|
+
GridRowModesModel,
|
|
10
|
+
GridRowParams,
|
|
11
|
+
GridToolbarContainer,
|
|
12
|
+
GridValidRowModel,
|
|
13
|
+
} from '@mui/x-data-grid';
|
|
14
|
+
import { useEffect, useRef, useState } from 'react';
|
|
15
|
+
import { v4 } from 'uuid';
|
|
16
|
+
import { DataTable, DataTableProps, Icons } from '../../export';
|
|
17
|
+
|
|
18
|
+
export type EditableDataTableProps = {
|
|
19
|
+
limit?: number;
|
|
20
|
+
offset?: number;
|
|
21
|
+
totalCount?: number;
|
|
22
|
+
hideDelete?: boolean;
|
|
23
|
+
onPageChange?: (page: number) => void;
|
|
24
|
+
onLimitChange?: (limit: number) => void;
|
|
25
|
+
onChange: (rows: GridValidRowModel) => void;
|
|
26
|
+
onSave?: (params: any) => void;
|
|
27
|
+
onDelete?: (params: any) => void;
|
|
28
|
+
} & Omit<
|
|
29
|
+
DataTableProps,
|
|
30
|
+
| 'rowModesModel'
|
|
31
|
+
| 'onRowModesModelChange'
|
|
32
|
+
| 'onRowEditStop'
|
|
33
|
+
| 'processRowUpdate'
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
export const EditableDataTable = (props: EditableDataTableProps) => {
|
|
37
|
+
const { rows } = props;
|
|
38
|
+
|
|
39
|
+
useEffect(() => {}, [props.columns]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<EditableTableCore
|
|
43
|
+
{...props}
|
|
44
|
+
rows={rows?.map((row) => (row.id ? row : { id: v4(), ...row }))}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const EditableTableCore = (props: EditableDataTableProps) => {
|
|
50
|
+
const { rows, columns } = props;
|
|
51
|
+
const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
|
|
52
|
+
const processRowUpdate = (newRow: GridRowModel) => {
|
|
53
|
+
const updatedRow = { ...newRow, isNew: false };
|
|
54
|
+
props.onSave && props.onSave(newRow);
|
|
55
|
+
props.onChange(
|
|
56
|
+
rows?.map((row) => (row.id === newRow.id ? updatedRow : row)) ?? [],
|
|
57
|
+
);
|
|
58
|
+
return updatedRow;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const handleRowEditStop: GridEventListener<'rowEditStop'> = (
|
|
62
|
+
params,
|
|
63
|
+
event,
|
|
64
|
+
) => {
|
|
65
|
+
if (params.reason === GridRowEditStopReasons.rowFocusOut) {
|
|
66
|
+
event.defaultMuiPrevented = true;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const handleRowModesModelChange = (newRowModesModel: GridRowModesModel) => {
|
|
71
|
+
setRowModesModel(newRowModesModel);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const handleEditClick = (params: GridRowParams) => {
|
|
75
|
+
setRowModesModel({
|
|
76
|
+
...rowModesModel,
|
|
77
|
+
[params.id]: { mode: GridRowModes.Edit },
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const handleSaveClick = (params: GridRowParams) => {
|
|
82
|
+
setRowModesModel({
|
|
83
|
+
...rowModesModel,
|
|
84
|
+
[params.id]: { mode: GridRowModes.View },
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const handleDeleteClick = (params: GridRowParams) => {
|
|
89
|
+
props.onDelete && props.onDelete(params);
|
|
90
|
+
props.onChange(rows?.filter((row) => row.id !== params.id) ?? []);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<>
|
|
95
|
+
<DataTable
|
|
96
|
+
editMode="row"
|
|
97
|
+
onRowModesModelChange={handleRowModesModelChange}
|
|
98
|
+
onRowEditStop={handleRowEditStop}
|
|
99
|
+
processRowUpdate={processRowUpdate}
|
|
100
|
+
rowModesModel={rowModesModel}
|
|
101
|
+
{...props}
|
|
102
|
+
rows={rows}
|
|
103
|
+
columns={[
|
|
104
|
+
...columns,
|
|
105
|
+
{
|
|
106
|
+
field: 'actions',
|
|
107
|
+
type: 'actions',
|
|
108
|
+
headerName: 'Actions',
|
|
109
|
+
width: 150,
|
|
110
|
+
cellClassName: 'actions',
|
|
111
|
+
getActions: (params) => {
|
|
112
|
+
if (rowModesModel[params.id]?.mode === GridRowModes.Edit) {
|
|
113
|
+
return props.hideDelete
|
|
114
|
+
? [
|
|
115
|
+
<GridActionsCellItem
|
|
116
|
+
icon={<Icons.SaveIcon />}
|
|
117
|
+
label="Save"
|
|
118
|
+
onClick={() => handleSaveClick(params)}
|
|
119
|
+
/>,
|
|
120
|
+
]
|
|
121
|
+
: [
|
|
122
|
+
<GridActionsCellItem
|
|
123
|
+
icon={<Icons.SaveIcon />}
|
|
124
|
+
label="Save"
|
|
125
|
+
onClick={() => handleSaveClick(params)}
|
|
126
|
+
/>,
|
|
127
|
+
<GridActionsCellItem
|
|
128
|
+
icon={<Icons.DeleteIcon />}
|
|
129
|
+
label="Cancel"
|
|
130
|
+
onClick={() => handleDeleteClick(params)}
|
|
131
|
+
color="inherit"
|
|
132
|
+
/>,
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return props.hideDelete
|
|
137
|
+
? [
|
|
138
|
+
<GridActionsCellItem
|
|
139
|
+
icon={<Icons.EditIcon />}
|
|
140
|
+
label="Edit"
|
|
141
|
+
onClick={() => handleEditClick(params)}
|
|
142
|
+
color="inherit"
|
|
143
|
+
/>,
|
|
144
|
+
]
|
|
145
|
+
: [
|
|
146
|
+
<GridActionsCellItem
|
|
147
|
+
icon={<Icons.EditIcon />}
|
|
148
|
+
label="Edit"
|
|
149
|
+
onClick={() => handleEditClick(params)}
|
|
150
|
+
color="inherit"
|
|
151
|
+
/>,
|
|
152
|
+
<GridActionsCellItem
|
|
153
|
+
icon={<Icons.DeleteIcon />}
|
|
154
|
+
label="Delete"
|
|
155
|
+
onClick={() => handleDeleteClick(params)}
|
|
156
|
+
color="inherit"
|
|
157
|
+
/>,
|
|
158
|
+
];
|
|
159
|
+
},
|
|
160
|
+
} as GridColDef,
|
|
161
|
+
]}
|
|
162
|
+
slots={{
|
|
163
|
+
footer: (footerProps) => (
|
|
164
|
+
<EditFooter
|
|
165
|
+
fields={props.columns.map((column) => column.field)}
|
|
166
|
+
setRows={props.onChange}
|
|
167
|
+
setRowModesModel={setRowModesModel}
|
|
168
|
+
/>
|
|
169
|
+
),
|
|
170
|
+
}}
|
|
171
|
+
/>
|
|
172
|
+
</>
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
interface EditFooterProps {
|
|
177
|
+
setRows: (
|
|
178
|
+
newRows: (oldRows: GridValidRowModel[]) => GridValidRowModel[],
|
|
179
|
+
) => void;
|
|
180
|
+
setRowModesModel: (
|
|
181
|
+
newModel: (oldModel: GridRowModesModel) => GridRowModesModel,
|
|
182
|
+
) => void;
|
|
183
|
+
fields: string[];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const EditFooter = (props: EditFooterProps) => {
|
|
187
|
+
const { setRows, setRowModesModel, fields } = props;
|
|
188
|
+
const id = useRef(v4()).current;
|
|
189
|
+
const handleClick = () => {
|
|
190
|
+
setRows((oldRows) => [
|
|
191
|
+
...oldRows,
|
|
192
|
+
{
|
|
193
|
+
id,
|
|
194
|
+
isNew: true,
|
|
195
|
+
...Object.fromEntries(fields.map((field) => [field, ''])),
|
|
196
|
+
},
|
|
197
|
+
]);
|
|
198
|
+
setRowModesModel((oldModel) => ({
|
|
199
|
+
...oldModel,
|
|
200
|
+
[id]: { mode: GridRowModes.Edit, fieldToFocus: 'name' },
|
|
201
|
+
}));
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<GridToolbarContainer sx={{ margin: '10px 0px' }}>
|
|
206
|
+
<Button onClick={handleClick}>+ Add Row</Button>
|
|
207
|
+
</GridToolbarContainer>
|
|
208
|
+
);
|
|
209
|
+
};
|
|
@@ -3,5 +3,6 @@ export * from './Avatar/Avatar';
|
|
|
3
3
|
export * from './Card/Card';
|
|
4
4
|
export * from './Chips/Chips';
|
|
5
5
|
export * from './DataTable/DataTable';
|
|
6
|
+
export * from './EditableDataTable/EditableDataTable';
|
|
6
7
|
export * from './SidePanel/SidePanel';
|
|
7
8
|
export * from './Typography/Typography';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { axios as campxAxios } from '@campxdev/campx-web-utils';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
AutocompleteCloseReason,
|
|
4
|
+
AutocompleteProps,
|
|
4
5
|
Box,
|
|
5
6
|
Autocomplete as MuiAutocomplete,
|
|
6
7
|
Paper,
|
|
@@ -8,7 +9,7 @@ import {
|
|
|
8
9
|
} from '@mui/material';
|
|
9
10
|
import axios from 'axios';
|
|
10
11
|
import _ from 'lodash';
|
|
11
|
-
import { useEffect, useReducer } from 'react';
|
|
12
|
+
import { SyntheticEvent, useEffect, useReducer } from 'react';
|
|
12
13
|
import { Typography } from '../../DataDisplay/Typography/Typography';
|
|
13
14
|
import { Spinner } from '../../Feedback/Spinner/Spinner';
|
|
14
15
|
import { TextField } from '../TextField/TextField';
|
|
@@ -26,16 +27,31 @@ function sleep(duration: number): Promise<void> {
|
|
|
26
27
|
export type SingleSelectProps = {
|
|
27
28
|
options?: { label: string; subLabel?: string; value: any }[] | any[];
|
|
28
29
|
optionsApiEndPoint?: string;
|
|
30
|
+
optionsApiEndpointParams?: any;
|
|
29
31
|
useCampxAxios?: boolean;
|
|
30
32
|
required?: boolean;
|
|
31
33
|
label?: string;
|
|
32
34
|
name?: string;
|
|
33
|
-
value?: any;
|
|
34
35
|
getValue?: (option: any) => any;
|
|
35
36
|
onChange: (value: any) => void;
|
|
36
37
|
error?: any;
|
|
37
38
|
helperText?: string;
|
|
38
|
-
} &
|
|
39
|
+
} & Omit<
|
|
40
|
+
AutocompleteProps<
|
|
41
|
+
{ label: string; subLabel?: string; value: any } | any,
|
|
42
|
+
false,
|
|
43
|
+
false,
|
|
44
|
+
false
|
|
45
|
+
>,
|
|
46
|
+
| 'options'
|
|
47
|
+
| 'open'
|
|
48
|
+
| 'onChange'
|
|
49
|
+
| 'autoFocus'
|
|
50
|
+
| 'PaperComponent'
|
|
51
|
+
| 'renderOption'
|
|
52
|
+
| 'options'
|
|
53
|
+
| 'renderInput'
|
|
54
|
+
>;
|
|
39
55
|
|
|
40
56
|
const CustomPaper = (props: PaperProps) => (
|
|
41
57
|
<Paper
|
|
@@ -126,6 +142,7 @@ const singleSelectReducer = (
|
|
|
126
142
|
export const SingleSelect = ({
|
|
127
143
|
options,
|
|
128
144
|
optionsApiEndPoint,
|
|
145
|
+
optionsApiEndpointParams,
|
|
129
146
|
useCampxAxios = true,
|
|
130
147
|
required = false,
|
|
131
148
|
label,
|
|
@@ -135,6 +152,8 @@ export const SingleSelect = ({
|
|
|
135
152
|
onChange,
|
|
136
153
|
error,
|
|
137
154
|
helperText,
|
|
155
|
+
onOpen,
|
|
156
|
+
onClose,
|
|
138
157
|
...restProps
|
|
139
158
|
}: SingleSelectProps) => {
|
|
140
159
|
const generateOptionsMap = (options: any[]) => {
|
|
@@ -163,7 +182,7 @@ export const SingleSelect = ({
|
|
|
163
182
|
|
|
164
183
|
const internalAxios = useCampxAxios ? campxAxios : axios;
|
|
165
184
|
|
|
166
|
-
const handleOpen = async () => {
|
|
185
|
+
const handleOpen = async (event: SyntheticEvent) => {
|
|
167
186
|
dispatch({
|
|
168
187
|
actionType: SingleSelectActionsTypes.OPEN,
|
|
169
188
|
});
|
|
@@ -177,6 +196,7 @@ export const SingleSelect = ({
|
|
|
177
196
|
params: {
|
|
178
197
|
limit,
|
|
179
198
|
offset,
|
|
199
|
+
...optionsApiEndpointParams,
|
|
180
200
|
},
|
|
181
201
|
})
|
|
182
202
|
.then((res) => res.data);
|
|
@@ -200,6 +220,21 @@ export const SingleSelect = ({
|
|
|
200
220
|
});
|
|
201
221
|
}
|
|
202
222
|
}
|
|
223
|
+
if (onOpen) {
|
|
224
|
+
onOpen(event);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const handleClose = (
|
|
229
|
+
event: SyntheticEvent,
|
|
230
|
+
reason: AutocompleteCloseReason,
|
|
231
|
+
) => {
|
|
232
|
+
dispatch({
|
|
233
|
+
actionType: SingleSelectActionsTypes.CLOSE,
|
|
234
|
+
});
|
|
235
|
+
if (onClose) {
|
|
236
|
+
onClose(event, reason);
|
|
237
|
+
}
|
|
203
238
|
};
|
|
204
239
|
|
|
205
240
|
const handleScroll = async (event: any) => {
|
|
@@ -288,22 +323,13 @@ export const SingleSelect = ({
|
|
|
288
323
|
}
|
|
289
324
|
return (
|
|
290
325
|
<MuiAutocomplete
|
|
326
|
+
{...restProps}
|
|
291
327
|
onChange={(e, value) => {
|
|
292
328
|
onChange(getValue ? getValue(value) : value?.value);
|
|
293
329
|
}}
|
|
294
330
|
open={open}
|
|
295
331
|
autoFocus={true}
|
|
296
332
|
value={state.internalOptionsMap[value]}
|
|
297
|
-
renderInput={(params) => (
|
|
298
|
-
<TextField
|
|
299
|
-
{...params}
|
|
300
|
-
label={label}
|
|
301
|
-
required={required}
|
|
302
|
-
name={name}
|
|
303
|
-
error={error}
|
|
304
|
-
helperText={helperText}
|
|
305
|
-
/>
|
|
306
|
-
)}
|
|
307
333
|
PaperComponent={CustomPaper}
|
|
308
334
|
renderOption={(props, option: any) => {
|
|
309
335
|
return (
|
|
@@ -316,20 +342,29 @@ export const SingleSelect = ({
|
|
|
316
342
|
);
|
|
317
343
|
}}
|
|
318
344
|
ListboxProps={{
|
|
345
|
+
...restProps.ListboxProps,
|
|
319
346
|
onScroll: handleScroll,
|
|
320
347
|
}}
|
|
321
348
|
slotProps={{
|
|
349
|
+
...restProps.slotProps,
|
|
322
350
|
paper: {
|
|
351
|
+
...restProps.slotProps?.paper,
|
|
323
352
|
square: loadingInternalOptions,
|
|
324
353
|
},
|
|
325
354
|
}}
|
|
326
355
|
onOpen={handleOpen}
|
|
327
|
-
onClose={
|
|
328
|
-
dispatch({
|
|
329
|
-
actionType: SingleSelectActionsTypes.CLOSE,
|
|
330
|
-
});
|
|
331
|
-
}}
|
|
356
|
+
onClose={handleClose}
|
|
332
357
|
options={internalOptions}
|
|
358
|
+
renderInput={(params) => (
|
|
359
|
+
<TextField
|
|
360
|
+
{...params}
|
|
361
|
+
label={label}
|
|
362
|
+
required={required}
|
|
363
|
+
name={name}
|
|
364
|
+
error={error}
|
|
365
|
+
helperText={helperText}
|
|
366
|
+
/>
|
|
367
|
+
)}
|
|
333
368
|
/>
|
|
334
369
|
);
|
|
335
370
|
};
|
|
@@ -4,6 +4,8 @@ import { Typography } from '../../DataDisplay/Typography/Typography';
|
|
|
4
4
|
import { Button } from '../../export';
|
|
5
5
|
import UserBox from './AppHeaderActions/UserBox';
|
|
6
6
|
import { StyledHeader } from './styles/styles';
|
|
7
|
+
import { StyledIconButton } from '../../Navigation/DropDownMenu/styles';
|
|
8
|
+
import { HelpIcon } from '../../Assets/Icons/IconComponents/HelpIcon';
|
|
7
9
|
|
|
8
10
|
export interface AppHeaderProps {
|
|
9
11
|
actions?: ReactNode[];
|
|
@@ -35,10 +37,10 @@ export const AppHeader = ({
|
|
|
35
37
|
<Stack alignItems={'center'} gap={'12px'} flexDirection={'row'}>
|
|
36
38
|
{/* <StyledIconButton>
|
|
37
39
|
<a
|
|
38
|
-
href={
|
|
40
|
+
href={'https://helpdesk.campx.in/helpdesk/my-tickets'}
|
|
39
41
|
target="_blank"
|
|
40
42
|
rel="noreferrer"
|
|
41
|
-
style={{ textDecoration:
|
|
43
|
+
style={{ textDecoration: 'none' }}
|
|
42
44
|
>
|
|
43
45
|
<HelpIcon size={20} />
|
|
44
46
|
</a>
|
|
@@ -47,6 +49,12 @@ export const AppHeader = ({
|
|
|
47
49
|
variant="outlined"
|
|
48
50
|
id="jiraIssueCollector"
|
|
49
51
|
className="reportAnIssue"
|
|
52
|
+
onClick={() => {
|
|
53
|
+
window.open(
|
|
54
|
+
'https://helpdesk.campx.in/helpdesk/my-tickets',
|
|
55
|
+
'_blank',
|
|
56
|
+
);
|
|
57
|
+
}}
|
|
50
58
|
>
|
|
51
59
|
<Typography
|
|
52
60
|
variant="button"
|