@campxdev/react-blueprint 1.2.20 → 1.3.0
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 +3 -3
- package/src/App.tsx +101 -18
- package/src/components/Assets/Icons/IconComponents/QuizIcon.tsx +51 -0
- package/src/components/Assets/Icons/IconComponents/TimerIcon.tsx +711 -0
- package/src/components/Assets/Icons/Icons.tsx +4 -0
- package/src/components/DataDisplay/Card/Card.tsx +3 -7
- package/src/components/DataDisplay/EditableDataTable/EditableDataTable.tsx +36 -46
- package/src/components/Input/SingleSelect/SingleSelect.tsx +179 -28
- package/src/components/Input/components/{FetchingOptionsLoader.tsx → OptionsLoader.tsx} +10 -2
- package/src/components/Input/styles.tsx +1 -1
- package/src/components/Layout/PageContent/PageContent.tsx +11 -8
- package/src/components/Layout/export.ts +3 -5
- package/src/components/Navigation/TabsContainer/TabsContainer.tsx +10 -2
- package/src/themes/commonTheme.ts +10 -3
|
@@ -62,6 +62,7 @@ import { PeoplexIcon } from './IconComponents/PeoplexIcon';
|
|
|
62
62
|
import { ProductFeaturesIcon } from './IconComponents/ProductFeaturesIcon';
|
|
63
63
|
import { ProfileIcon } from './IconComponents/ProfileIcon';
|
|
64
64
|
import { QuestionsIcon } from './IconComponents/QuestionsIcon';
|
|
65
|
+
import QuizIcon from './IconComponents/QuizIcon';
|
|
65
66
|
import { RedirectIcon } from './IconComponents/RedirectIcon';
|
|
66
67
|
import { RedoIcon } from './IconComponents/RedoIcon';
|
|
67
68
|
import { ResourcesIcon } from './IconComponents/ResourcesIcon';
|
|
@@ -78,6 +79,7 @@ import { TasksIcon } from './IconComponents/TasksIcon';
|
|
|
78
79
|
import { TextLocalIcon } from './IconComponents/TextLocalIcon';
|
|
79
80
|
import { TicketsIcon } from './IconComponents/TicketsIcon';
|
|
80
81
|
import { TimeTableIcon } from './IconComponents/TimeTableIcon';
|
|
82
|
+
import TimerIcon from './IconComponents/TimerIcon';
|
|
81
83
|
import { UmsIcon } from './IconComponents/UmsIcon';
|
|
82
84
|
import { UnCheckedCheckboxIcon } from './IconComponents/UncheckCheckBoxIcon';
|
|
83
85
|
import { UnCheckedRadioIcon } from './IconComponents/UncheckedRadioIcon';
|
|
@@ -178,4 +180,6 @@ export const Icons = {
|
|
|
178
180
|
AttendanceIcon,
|
|
179
181
|
ResourcesIcon,
|
|
180
182
|
TimeTableIcon,
|
|
183
|
+
TimerIcon,
|
|
184
|
+
QuizIcon,
|
|
181
185
|
};
|
|
@@ -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
|
|
12
|
+
import { DropDownIcon, DropdownMenu } from '../../export';
|
|
13
13
|
import {
|
|
14
14
|
StyledButton,
|
|
15
15
|
StyledCardActions,
|
|
@@ -46,8 +46,7 @@ export interface CardProps {
|
|
|
46
46
|
imageSrc?: string;
|
|
47
47
|
titleImgIcon?: ReactNode;
|
|
48
48
|
checkBox?: boolean;
|
|
49
|
-
|
|
50
|
-
switchProps?: SwitchProps;
|
|
49
|
+
|
|
51
50
|
moreOptions?: boolean;
|
|
52
51
|
menu?: Array<ReactNode>;
|
|
53
52
|
icon?: ReactNode;
|
|
@@ -64,7 +63,7 @@ export const Card = ({
|
|
|
64
63
|
footer,
|
|
65
64
|
fields,
|
|
66
65
|
imageSrc,
|
|
67
|
-
|
|
66
|
+
|
|
68
67
|
statusSx,
|
|
69
68
|
cardSx,
|
|
70
69
|
headerSx,
|
|
@@ -78,8 +77,6 @@ export const Card = ({
|
|
|
78
77
|
icon,
|
|
79
78
|
children,
|
|
80
79
|
menu = [],
|
|
81
|
-
switchProps,
|
|
82
|
-
hasSwitch,
|
|
83
80
|
}: CardProps) => {
|
|
84
81
|
const handleClick = (e: any) => {
|
|
85
82
|
footer?.onClick();
|
|
@@ -110,7 +107,6 @@ export const Card = ({
|
|
|
110
107
|
</Stack>
|
|
111
108
|
</Stack>
|
|
112
109
|
<Stack flexDirection={'row'} gap={'12px'} alignItems={'center'}>
|
|
113
|
-
{hasSwitch && <Switch {...switchProps} />}
|
|
114
110
|
{status && (
|
|
115
111
|
<StyledStatusText variant="label2" sx={statusSx}>
|
|
116
112
|
{status}{' '}
|
|
@@ -129,7 +129,7 @@ export const EditableTableCore = (props: EditableDataTableProps) => {
|
|
|
129
129
|
height: '100%',
|
|
130
130
|
},
|
|
131
131
|
'& .MuiDataGrid-cell.MuiDataGrid-cell--editing': {
|
|
132
|
-
padding: '0px 9px
|
|
132
|
+
padding: '0px 9px',
|
|
133
133
|
alignItems: 'center',
|
|
134
134
|
},
|
|
135
135
|
'& .MuiDataGrid-cell': {
|
|
@@ -144,6 +144,13 @@ export const EditableTableCore = (props: EditableDataTableProps) => {
|
|
|
144
144
|
borderColor: theme.palette.primary.main,
|
|
145
145
|
},
|
|
146
146
|
},
|
|
147
|
+
'& .MuiAutocomplete-input': {
|
|
148
|
+
border: 'none',
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
'& .MuiOutlinedInput-input': {
|
|
152
|
+
padding: '8px 14px',
|
|
153
|
+
},
|
|
147
154
|
}}
|
|
148
155
|
{...props}
|
|
149
156
|
rows={rows}
|
|
@@ -156,53 +163,36 @@ export const EditableTableCore = (props: EditableDataTableProps) => {
|
|
|
156
163
|
width: 150,
|
|
157
164
|
cellClassName: 'actions',
|
|
158
165
|
getActions: (params) => {
|
|
166
|
+
const actions = [];
|
|
159
167
|
if (rowModesModel[params.id]?.mode === GridRowModes.Edit) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
label="Cancel"
|
|
177
|
-
onClick={() => handleDeleteClick(params)}
|
|
178
|
-
color="inherit"
|
|
179
|
-
/>,
|
|
180
|
-
];
|
|
168
|
+
actions.push(
|
|
169
|
+
<GridActionsCellItem
|
|
170
|
+
icon={<Icons.SaveIcon />}
|
|
171
|
+
label="Save"
|
|
172
|
+
onClick={() => handleSaveClick(params)}
|
|
173
|
+
/>,
|
|
174
|
+
);
|
|
175
|
+
} else {
|
|
176
|
+
actions.push(
|
|
177
|
+
<GridActionsCellItem
|
|
178
|
+
icon={<Icons.EditIcon />}
|
|
179
|
+
label="Edit"
|
|
180
|
+
onClick={() => handleEditClick(params)}
|
|
181
|
+
color="inherit"
|
|
182
|
+
/>,
|
|
183
|
+
);
|
|
181
184
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
<
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
<GridActionsCellItem
|
|
194
|
-
icon={<Icons.EditIcon />}
|
|
195
|
-
label="Edit"
|
|
196
|
-
onClick={() => handleEditClick(params)}
|
|
197
|
-
color="inherit"
|
|
198
|
-
/>,
|
|
199
|
-
<GridActionsCellItem
|
|
200
|
-
icon={<Icons.DeleteIcon />}
|
|
201
|
-
label="Delete"
|
|
202
|
-
onClick={() => handleDeleteClick(params)}
|
|
203
|
-
color="inherit"
|
|
204
|
-
/>,
|
|
205
|
-
];
|
|
185
|
+
if (!props.hideDelete) {
|
|
186
|
+
actions.push(
|
|
187
|
+
<GridActionsCellItem
|
|
188
|
+
icon={<Icons.DeleteIcon />}
|
|
189
|
+
label="Delete"
|
|
190
|
+
onClick={() => handleDeleteClick(params)}
|
|
191
|
+
color="inherit"
|
|
192
|
+
/>,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
return actions;
|
|
206
196
|
},
|
|
207
197
|
} as GridColDef,
|
|
208
198
|
]}
|
|
@@ -5,15 +5,14 @@ import {
|
|
|
5
5
|
Box,
|
|
6
6
|
Autocomplete as MuiAutocomplete,
|
|
7
7
|
Paper,
|
|
8
|
-
PaperProps,
|
|
9
8
|
} from '@mui/material';
|
|
10
9
|
import axios from 'axios';
|
|
11
|
-
import _ from 'lodash';
|
|
12
|
-
import { SyntheticEvent, useEffect, useReducer } from 'react';
|
|
10
|
+
import _, { debounce } from 'lodash';
|
|
11
|
+
import { SyntheticEvent, useEffect, useMemo, useReducer } from 'react';
|
|
13
12
|
import { Typography } from '../../DataDisplay/Typography/Typography';
|
|
14
13
|
import { Spinner } from '../../Feedback/Spinner/Spinner';
|
|
15
14
|
import { TextField } from '../TextField/TextField';
|
|
16
|
-
import {
|
|
15
|
+
import { OptionsLoader } from '../components/OptionsLoader';
|
|
17
16
|
import { OptionContainer } from '../styles';
|
|
18
17
|
|
|
19
18
|
function sleep(duration: number): Promise<void> {
|
|
@@ -24,6 +23,13 @@ function sleep(duration: number): Promise<void> {
|
|
|
24
23
|
});
|
|
25
24
|
}
|
|
26
25
|
|
|
26
|
+
declare module '@mui/material/Autocomplete' {
|
|
27
|
+
interface AutocompletePaperSlotPropsOverrides {
|
|
28
|
+
loadingOptions: boolean;
|
|
29
|
+
isSearch: boolean;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
export type SingleSelectProps = {
|
|
28
34
|
options?: { label: string; subLabel?: string; value: any }[] | any[];
|
|
29
35
|
optionsApiEndPoint?: string;
|
|
@@ -33,6 +39,11 @@ export type SingleSelectProps = {
|
|
|
33
39
|
label?: string;
|
|
34
40
|
name?: string;
|
|
35
41
|
getValue?: (option: any) => any;
|
|
42
|
+
dbValueProps?: {
|
|
43
|
+
valueKey: string;
|
|
44
|
+
isObjectId?: boolean;
|
|
45
|
+
};
|
|
46
|
+
dbLabelProps?: { labelKey: string; subLabelKey?: string };
|
|
36
47
|
onChange: (value: any) => void;
|
|
37
48
|
error?: any;
|
|
38
49
|
helperText?: string;
|
|
@@ -53,7 +64,7 @@ export type SingleSelectProps = {
|
|
|
53
64
|
| 'renderInput'
|
|
54
65
|
>;
|
|
55
66
|
|
|
56
|
-
const CustomPaper = (props:
|
|
67
|
+
const CustomPaper = (props: any) => (
|
|
57
68
|
<Paper
|
|
58
69
|
{...props}
|
|
59
70
|
sx={{
|
|
@@ -62,7 +73,7 @@ const CustomPaper = (props: PaperProps) => (
|
|
|
62
73
|
}}
|
|
63
74
|
>
|
|
64
75
|
{props.children}
|
|
65
|
-
<
|
|
76
|
+
<OptionsLoader loading={props.loadingOptions} isSearch={props.isSearch} />
|
|
66
77
|
</Paper>
|
|
67
78
|
);
|
|
68
79
|
|
|
@@ -71,12 +82,14 @@ enum SingleSelectActionsTypes {
|
|
|
71
82
|
CLOSE = 'close',
|
|
72
83
|
LOAD_INTERNAL_OPTIONS_START = 'load_internal_options_start',
|
|
73
84
|
LOAD_INTERNAL_OPTIONS_END = 'load_internal_options_end',
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
LOAD_SELECTED_OPTIONS_START = 'load_selected_options_start',
|
|
86
|
+
LOAD_SELECTED_OPTIONS_END = 'load_selected_options_end',
|
|
76
87
|
SET_NETWORK_ERROR = 'set_network_error',
|
|
77
88
|
SET_INTERNAL_OPTIONS = 'set_internal_options',
|
|
78
89
|
APPEND_INTERNAL_OPTIONS = 'append_internal_options',
|
|
79
90
|
CHANGE_HAS_MORE_FLAG = 'change_has_more_flag',
|
|
91
|
+
SET_SEARCH = 'set_search',
|
|
92
|
+
CLEAR_SEARCH = 'clear_search',
|
|
80
93
|
}
|
|
81
94
|
const singleSelectReducer = (
|
|
82
95
|
state: any,
|
|
@@ -98,15 +111,27 @@ const singleSelectReducer = (
|
|
|
98
111
|
case SingleSelectActionsTypes.LOAD_INTERNAL_OPTIONS_END: {
|
|
99
112
|
return { ...state, loadingInternalOptions: false };
|
|
100
113
|
}
|
|
101
|
-
case SingleSelectActionsTypes.
|
|
114
|
+
case SingleSelectActionsTypes.LOAD_SELECTED_OPTIONS_START: {
|
|
102
115
|
return { ...state, loadingInitialInternalOptions: true };
|
|
103
116
|
}
|
|
104
|
-
case SingleSelectActionsTypes.
|
|
117
|
+
case SingleSelectActionsTypes.LOAD_SELECTED_OPTIONS_END: {
|
|
105
118
|
return { ...state, loadingInitialInternalOptions: false };
|
|
106
119
|
}
|
|
107
120
|
case SingleSelectActionsTypes.SET_NETWORK_ERROR: {
|
|
108
121
|
return { ...state, ...stateChanges };
|
|
109
122
|
}
|
|
123
|
+
case SingleSelectActionsTypes.SET_SEARCH: {
|
|
124
|
+
return { ...state, search: stateChanges.search, hasMore: true };
|
|
125
|
+
}
|
|
126
|
+
case SingleSelectActionsTypes.CLEAR_SEARCH: {
|
|
127
|
+
return {
|
|
128
|
+
...state,
|
|
129
|
+
search: null,
|
|
130
|
+
offset: 0,
|
|
131
|
+
internalOptions: [],
|
|
132
|
+
internalOptionsMap: {},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
110
135
|
case SingleSelectActionsTypes.SET_INTERNAL_OPTIONS: {
|
|
111
136
|
return {
|
|
112
137
|
...state,
|
|
@@ -125,7 +150,7 @@ const singleSelectReducer = (
|
|
|
125
150
|
},
|
|
126
151
|
loadingInternalOptions: false,
|
|
127
152
|
limit: state.limit,
|
|
128
|
-
offset: state.offset + 10,
|
|
153
|
+
offset: state.offset + (stateChanges?.persistOffset ? 0 : 10),
|
|
129
154
|
};
|
|
130
155
|
}
|
|
131
156
|
case SingleSelectActionsTypes.CHANGE_HAS_MORE_FLAG: {
|
|
@@ -152,6 +177,11 @@ export const SingleSelect = ({
|
|
|
152
177
|
onChange,
|
|
153
178
|
error,
|
|
154
179
|
helperText,
|
|
180
|
+
dbValueProps = {
|
|
181
|
+
valueKey: 'id',
|
|
182
|
+
isObjectId: false,
|
|
183
|
+
},
|
|
184
|
+
dbLabelProps,
|
|
155
185
|
onOpen,
|
|
156
186
|
onClose,
|
|
157
187
|
...restProps
|
|
@@ -169,6 +199,7 @@ export const SingleSelect = ({
|
|
|
169
199
|
limit: 10,
|
|
170
200
|
offset: 0,
|
|
171
201
|
hasMore: true,
|
|
202
|
+
search: null,
|
|
172
203
|
});
|
|
173
204
|
const {
|
|
174
205
|
open,
|
|
@@ -178,6 +209,7 @@ export const SingleSelect = ({
|
|
|
178
209
|
limit,
|
|
179
210
|
offset,
|
|
180
211
|
hasMore,
|
|
212
|
+
search,
|
|
181
213
|
} = state;
|
|
182
214
|
|
|
183
215
|
const internalAxios = useCampxAxios ? campxAxios : axios;
|
|
@@ -186,7 +218,7 @@ export const SingleSelect = ({
|
|
|
186
218
|
dispatch({
|
|
187
219
|
actionType: SingleSelectActionsTypes.OPEN,
|
|
188
220
|
});
|
|
189
|
-
if (optionsApiEndPoint &&
|
|
221
|
+
if (optionsApiEndPoint && internalOptions.length <= 1) {
|
|
190
222
|
try {
|
|
191
223
|
dispatch({
|
|
192
224
|
actionType: SingleSelectActionsTypes.LOAD_INTERNAL_OPTIONS_START,
|
|
@@ -196,18 +228,36 @@ export const SingleSelect = ({
|
|
|
196
228
|
params: {
|
|
197
229
|
limit,
|
|
198
230
|
offset,
|
|
231
|
+
selectedValueData: value,
|
|
232
|
+
dbValueProps: {
|
|
233
|
+
...dbValueProps,
|
|
234
|
+
...(dbValueProps.isObjectId && { isObjectId: true }),
|
|
235
|
+
},
|
|
236
|
+
dbLabelProps,
|
|
199
237
|
...optionsApiEndpointParams,
|
|
200
238
|
},
|
|
201
239
|
})
|
|
202
240
|
.then((res) => res.data);
|
|
203
241
|
await sleep(700);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
242
|
+
|
|
243
|
+
if (internalOptions.length) {
|
|
244
|
+
dispatch({
|
|
245
|
+
actionType: SingleSelectActionsTypes.APPEND_INTERNAL_OPTIONS,
|
|
246
|
+
stateChanges: {
|
|
247
|
+
newOptions: options,
|
|
248
|
+
internalOptionsMap: generateOptionsMap(options),
|
|
249
|
+
persistOffset: true,
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
} else {
|
|
253
|
+
dispatch({
|
|
254
|
+
actionType: SingleSelectActionsTypes.SET_INTERNAL_OPTIONS,
|
|
255
|
+
stateChanges: {
|
|
256
|
+
internalOptions: options,
|
|
257
|
+
internalOptionsMap: generateOptionsMap(options),
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
}
|
|
211
261
|
} catch (e) {
|
|
212
262
|
dispatch({
|
|
213
263
|
actionType: SingleSelectActionsTypes.SET_NETWORK_ERROR,
|
|
@@ -232,6 +282,11 @@ export const SingleSelect = ({
|
|
|
232
282
|
dispatch({
|
|
233
283
|
actionType: SingleSelectActionsTypes.CLOSE,
|
|
234
284
|
});
|
|
285
|
+
if (optionsApiEndPoint) {
|
|
286
|
+
dispatch({
|
|
287
|
+
actionType: SingleSelectActionsTypes.CLEAR_SEARCH,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
235
290
|
if (onClose) {
|
|
236
291
|
onClose(event, reason);
|
|
237
292
|
}
|
|
@@ -249,10 +304,18 @@ export const SingleSelect = ({
|
|
|
249
304
|
actionType: SingleSelectActionsTypes.LOAD_INTERNAL_OPTIONS_START,
|
|
250
305
|
});
|
|
251
306
|
const newOptions = await internalAxios
|
|
252
|
-
.get(optionsApiEndPoint
|
|
307
|
+
.get(optionsApiEndPoint, {
|
|
253
308
|
params: {
|
|
254
309
|
limit: limit,
|
|
255
310
|
offset: offset + 10,
|
|
311
|
+
search: search,
|
|
312
|
+
selectedValueData: value,
|
|
313
|
+
dbValueProps: {
|
|
314
|
+
...dbValueProps,
|
|
315
|
+
...(dbValueProps.isObjectId && { isObjectId: true }),
|
|
316
|
+
},
|
|
317
|
+
dbLabelProps,
|
|
318
|
+
...optionsApiEndpointParams,
|
|
256
319
|
},
|
|
257
320
|
})
|
|
258
321
|
.then((res) => res.data);
|
|
@@ -272,13 +335,92 @@ export const SingleSelect = ({
|
|
|
272
335
|
}
|
|
273
336
|
};
|
|
274
337
|
|
|
275
|
-
const
|
|
338
|
+
const searchDb = async (searchValue: string) => {
|
|
276
339
|
dispatch({
|
|
277
|
-
actionType: SingleSelectActionsTypes.
|
|
340
|
+
actionType: SingleSelectActionsTypes.SET_SEARCH,
|
|
341
|
+
stateChanges: {
|
|
342
|
+
search: searchValue,
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
if (!searchValue || searchValue.trim() === '') {
|
|
346
|
+
dispatch({
|
|
347
|
+
actionType: SingleSelectActionsTypes.CLEAR_SEARCH,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
if (optionsApiEndPoint) {
|
|
351
|
+
try {
|
|
352
|
+
dispatch({
|
|
353
|
+
actionType: SingleSelectActionsTypes.LOAD_INTERNAL_OPTIONS_START,
|
|
354
|
+
});
|
|
355
|
+
const options = await internalAxios
|
|
356
|
+
.get(optionsApiEndPoint, {
|
|
357
|
+
params: {
|
|
358
|
+
limit,
|
|
359
|
+
offset: 0,
|
|
360
|
+
selectedValueData: value,
|
|
361
|
+
dbValueProps: {
|
|
362
|
+
...dbValueProps,
|
|
363
|
+
...(dbValueProps.isObjectId && { isObjectId: true }),
|
|
364
|
+
},
|
|
365
|
+
dbLabelProps,
|
|
366
|
+
search: searchValue,
|
|
367
|
+
...optionsApiEndpointParams,
|
|
368
|
+
},
|
|
369
|
+
})
|
|
370
|
+
.then((res) => res.data);
|
|
371
|
+
await sleep(700);
|
|
372
|
+
|
|
373
|
+
dispatch({
|
|
374
|
+
actionType: SingleSelectActionsTypes.SET_INTERNAL_OPTIONS,
|
|
375
|
+
stateChanges: {
|
|
376
|
+
internalOptions: options,
|
|
377
|
+
internalOptionsMap: generateOptionsMap(options),
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
} catch (e) {
|
|
381
|
+
dispatch({
|
|
382
|
+
actionType: SingleSelectActionsTypes.SET_NETWORK_ERROR,
|
|
383
|
+
stateChanges: {
|
|
384
|
+
error: e,
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
dispatch({
|
|
388
|
+
actionType: SingleSelectActionsTypes.LOAD_INTERNAL_OPTIONS_END,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const debouncedSendRequest = useMemo(() => {
|
|
395
|
+
return debounce((searchValue) => {
|
|
396
|
+
searchDb(searchValue);
|
|
397
|
+
}, 300);
|
|
398
|
+
}, [searchDb]);
|
|
399
|
+
|
|
400
|
+
const handleSearch = async (
|
|
401
|
+
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
|
402
|
+
) => {
|
|
403
|
+
const searchValue = e.target.value;
|
|
404
|
+
debouncedSendRequest(searchValue);
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const loadSelectedOptions = async () => {
|
|
408
|
+
dispatch({
|
|
409
|
+
actionType: SingleSelectActionsTypes.LOAD_SELECTED_OPTIONS_START,
|
|
278
410
|
});
|
|
279
411
|
try {
|
|
280
412
|
const res = await internalAxios.get(optionsApiEndPoint ?? '', {
|
|
281
|
-
params: {
|
|
413
|
+
params: {
|
|
414
|
+
limit,
|
|
415
|
+
offset,
|
|
416
|
+
selectedValueData: value,
|
|
417
|
+
dbValueProps: {
|
|
418
|
+
...dbValueProps,
|
|
419
|
+
...(dbValueProps.isObjectId && { isObjectId: true }),
|
|
420
|
+
},
|
|
421
|
+
dbLabelProps,
|
|
422
|
+
filterBySelectedValues: true,
|
|
423
|
+
},
|
|
282
424
|
});
|
|
283
425
|
dispatch({
|
|
284
426
|
actionType: SingleSelectActionsTypes.SET_INTERNAL_OPTIONS,
|
|
@@ -298,10 +440,9 @@ export const SingleSelect = ({
|
|
|
298
440
|
|
|
299
441
|
useEffect(() => {
|
|
300
442
|
if (value && optionsApiEndPoint) {
|
|
301
|
-
|
|
443
|
+
loadSelectedOptions().finally(() => {
|
|
302
444
|
dispatch({
|
|
303
|
-
actionType:
|
|
304
|
-
SingleSelectActionsTypes.LOAD_INITIAL_INTERNAL_OPTIONS_END,
|
|
445
|
+
actionType: SingleSelectActionsTypes.LOAD_SELECTED_OPTIONS_END,
|
|
305
446
|
});
|
|
306
447
|
});
|
|
307
448
|
}
|
|
@@ -329,11 +470,19 @@ export const SingleSelect = ({
|
|
|
329
470
|
}}
|
|
330
471
|
open={open}
|
|
331
472
|
autoFocus={true}
|
|
473
|
+
filterOptions={(options, state) => {
|
|
474
|
+
if (optionsApiEndPoint) {
|
|
475
|
+
return options;
|
|
476
|
+
}
|
|
477
|
+
return options.filter((option) =>
|
|
478
|
+
option.label.toLowerCase().includes(state.inputValue.toLowerCase()),
|
|
479
|
+
);
|
|
480
|
+
}}
|
|
332
481
|
value={state.internalOptionsMap[value]}
|
|
333
482
|
PaperComponent={CustomPaper}
|
|
334
483
|
renderOption={(props, option: any) => {
|
|
335
484
|
return (
|
|
336
|
-
<Box component="li" {...props}>
|
|
485
|
+
<Box component="li" {...props} key={option.value}>
|
|
337
486
|
<OptionContainer>
|
|
338
487
|
<Typography variant="label1">{option.label}</Typography>
|
|
339
488
|
<Typography variant="caption">{option?.subLabel}</Typography>
|
|
@@ -349,7 +498,8 @@ export const SingleSelect = ({
|
|
|
349
498
|
...restProps.slotProps,
|
|
350
499
|
paper: {
|
|
351
500
|
...restProps.slotProps?.paper,
|
|
352
|
-
|
|
501
|
+
loadingOptions: loadingInternalOptions,
|
|
502
|
+
isSearch: !!state.search,
|
|
353
503
|
},
|
|
354
504
|
}}
|
|
355
505
|
onOpen={handleOpen}
|
|
@@ -361,6 +511,7 @@ export const SingleSelect = ({
|
|
|
361
511
|
label={label}
|
|
362
512
|
required={required}
|
|
363
513
|
name={name}
|
|
514
|
+
onChange={handleSearch}
|
|
364
515
|
error={error}
|
|
365
516
|
helperText={helperText}
|
|
366
517
|
/>
|
|
@@ -2,11 +2,19 @@ import { Typography } from '../../DataDisplay/Typography/Typography';
|
|
|
2
2
|
import { Spinner } from '../../Feedback/Spinner/Spinner';
|
|
3
3
|
import { FetchingOptionsLoaderContainer } from '../styles';
|
|
4
4
|
|
|
5
|
-
export const
|
|
5
|
+
export const OptionsLoader = ({
|
|
6
|
+
loading,
|
|
7
|
+
isSearch,
|
|
8
|
+
}: {
|
|
9
|
+
loading: boolean;
|
|
10
|
+
isSearch: boolean;
|
|
11
|
+
}) => {
|
|
6
12
|
return loading ? (
|
|
7
13
|
<FetchingOptionsLoaderContainer direction="row" alignItems="center">
|
|
8
14
|
<Spinner />
|
|
9
|
-
<Typography variant="caption">
|
|
15
|
+
<Typography variant="caption">
|
|
16
|
+
{isSearch ? 'Searching' : 'Loading Options'}
|
|
17
|
+
</Typography>
|
|
10
18
|
</FetchingOptionsLoaderContainer>
|
|
11
19
|
) : (
|
|
12
20
|
<></>
|
|
@@ -5,7 +5,7 @@ export const OptionContainer = styled(Box)(({ theme }) => ({
|
|
|
5
5
|
flexDirection: 'column',
|
|
6
6
|
borderBottom: `1px solid ${theme.palette.secondary.main}`,
|
|
7
7
|
width: '100%',
|
|
8
|
-
padding: '
|
|
8
|
+
padding: '4px 0px',
|
|
9
9
|
}));
|
|
10
10
|
|
|
11
11
|
export const FetchingOptionsLoaderContainer = styled(Stack)(({ theme }) => ({
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { Box, BoxProps, styled } from '@mui/material';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
padding: '1rem',
|
|
5
|
-
flex: 1,
|
|
3
|
+
const PageContentContainer = styled(Box)(({ theme }) => ({
|
|
6
4
|
display: 'flex',
|
|
7
5
|
flexDirection: 'column',
|
|
8
|
-
borderRadius: '10px',
|
|
9
6
|
overflowY: 'auto',
|
|
7
|
+
padding: '16px',
|
|
8
|
+
gap: '16px',
|
|
10
9
|
backgroundColor: theme.palette.surface.paperBackground,
|
|
11
|
-
height: '
|
|
10
|
+
height: 'calc(100vh - 148px)',
|
|
11
|
+
width: '100%',
|
|
12
|
+
borderRadius: '8px',
|
|
12
13
|
}));
|
|
13
14
|
|
|
14
|
-
export
|
|
15
|
-
return
|
|
16
|
-
}
|
|
15
|
+
export const PageContent = (props: BoxProps) => {
|
|
16
|
+
return (
|
|
17
|
+
<PageContentContainer {...props}>{props.children}</PageContentContainer>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export * from './AppHeader/AppHeader';
|
|
2
|
+
export * from './PageContent/PageContent';
|
|
4
3
|
export * from './PageHeader/components/DensitySelector/DensitySelector';
|
|
5
|
-
|
|
6
|
-
export { AppHeader, TabsLayout };
|
|
4
|
+
export * from './TabsLayout/TabsLayout';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Box, Tab, TabProps, Tabs, TabsProps } from '@mui/material';
|
|
1
|
+
import { Box, styled, Tab, TabProps, Tabs, TabsProps } from '@mui/material';
|
|
2
2
|
import { ChangeEvent, useEffect, useState } from 'react';
|
|
3
3
|
|
|
4
4
|
interface CustomTabProps extends Omit<TabProps, 'component'> {
|
|
@@ -14,6 +14,12 @@ export interface TabsContainerProps {
|
|
|
14
14
|
tabsProps: TabsProps;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
const TabContent = styled(Box)(({ theme }) => ({
|
|
18
|
+
width: '100%',
|
|
19
|
+
height: 'calc(100vh - 200px)',
|
|
20
|
+
backgroundColor: theme.palette.surface.paperBackground,
|
|
21
|
+
}));
|
|
22
|
+
|
|
17
23
|
export const TabsContainer = ({
|
|
18
24
|
tabs,
|
|
19
25
|
onTabChange,
|
|
@@ -52,7 +58,9 @@ export const TabsContainer = ({
|
|
|
52
58
|
/>
|
|
53
59
|
))}
|
|
54
60
|
</Tabs>
|
|
55
|
-
<
|
|
61
|
+
<TabContent>
|
|
62
|
+
{tabs.find((tab) => tab?.key === currentTab)?.component}
|
|
63
|
+
</TabContent>
|
|
56
64
|
</>
|
|
57
65
|
);
|
|
58
66
|
};
|
|
@@ -302,7 +302,15 @@ export const getCommonTheme = (mode: Theme) => {
|
|
|
302
302
|
'& label': {
|
|
303
303
|
display: 'none',
|
|
304
304
|
},
|
|
305
|
+
input: {
|
|
306
|
+
padding: '9px',
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
fieldset: {
|
|
310
|
+
top: '0px',
|
|
311
|
+
},
|
|
305
312
|
'& legend': {
|
|
313
|
+
height: '0px',
|
|
306
314
|
'& span': {
|
|
307
315
|
display: 'none',
|
|
308
316
|
},
|
|
@@ -310,9 +318,6 @@ export const getCommonTheme = (mode: Theme) => {
|
|
|
310
318
|
'& input:-webkit-autofill': {
|
|
311
319
|
height: '7px',
|
|
312
320
|
},
|
|
313
|
-
fieldset: {
|
|
314
|
-
top: '0px',
|
|
315
|
-
},
|
|
316
321
|
minWidth: '200px',
|
|
317
322
|
},
|
|
318
323
|
},
|
|
@@ -446,6 +451,8 @@ export const getCommonTheme = (mode: Theme) => {
|
|
|
446
451
|
root: {
|
|
447
452
|
'& .MuiTabs-flexContainer': {
|
|
448
453
|
borderBottom: `1px solid ${ColorTokens.border.primary}`,
|
|
454
|
+
backgroundColor: ColorTokens.surface.paperBackground,
|
|
455
|
+
borderRadius: '8px 8px 0px 0px',
|
|
449
456
|
},
|
|
450
457
|
},
|
|
451
458
|
indicator: {
|