@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.
@@ -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, Switch, SwitchProps } from '../../export';
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
- hasSwitch?: boolean;
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
- checkBox,
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 0px 0px',
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
- return props.hideDelete
161
- ? [
162
- <GridActionsCellItem
163
- icon={<Icons.SaveIcon />}
164
- label="Save"
165
- onClick={() => handleSaveClick(params)}
166
- />,
167
- ]
168
- : [
169
- <GridActionsCellItem
170
- icon={<Icons.SaveIcon />}
171
- label="Save"
172
- onClick={() => handleSaveClick(params)}
173
- />,
174
- <GridActionsCellItem
175
- icon={<Icons.DeleteIcon />}
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
- return props.hideDelete
184
- ? [
185
- <GridActionsCellItem
186
- icon={<Icons.EditIcon />}
187
- label="Edit"
188
- onClick={() => handleEditClick(params)}
189
- color="inherit"
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 { FetchingOptionsLoader } from '../components/FetchingOptionsLoader';
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: PaperProps) => (
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
- <FetchingOptionsLoader loading={!!props.square} />
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
- LOAD_INITIAL_INTERNAL_OPTIONS_START = 'load_initial_internal_options_start',
75
- LOAD_INITIAL_INTERNAL_OPTIONS_END = 'load_initial_internal_options_end',
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.LOAD_INITIAL_INTERNAL_OPTIONS_START: {
114
+ case SingleSelectActionsTypes.LOAD_SELECTED_OPTIONS_START: {
102
115
  return { ...state, loadingInitialInternalOptions: true };
103
116
  }
104
- case SingleSelectActionsTypes.LOAD_INITIAL_INTERNAL_OPTIONS_END: {
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 && !internalOptions.length) {
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
- dispatch({
205
- actionType: SingleSelectActionsTypes.SET_INTERNAL_OPTIONS,
206
- stateChanges: {
207
- internalOptions: options,
208
- internalOptionsMap: generateOptionsMap(options),
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 fetchInitialOptions = async () => {
338
+ const searchDb = async (searchValue: string) => {
276
339
  dispatch({
277
- actionType: SingleSelectActionsTypes.LOAD_INITIAL_INTERNAL_OPTIONS_START,
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: { limit, offset, selectedValue: value },
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
- fetchInitialOptions().finally(() => {
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
- square: loadingInternalOptions,
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 FetchingOptionsLoader = ({ loading }: { loading: boolean }) => {
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">Fetching Options</Typography>
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: '5px 0px',
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 StyledPageContent = styled(Box)(({ theme }) => ({
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: '100%',
10
+ height: 'calc(100vh - 148px)',
11
+ width: '100%',
12
+ borderRadius: '8px',
12
13
  }));
13
14
 
14
- export function PageContent(props: BoxProps) {
15
- return <StyledPageContent {...props}>{props.children}</StyledPageContent>;
16
- }
15
+ export const PageContent = (props: BoxProps) => {
16
+ return (
17
+ <PageContentContainer {...props}>{props.children}</PageContentContainer>
18
+ );
19
+ };
@@ -1,6 +1,4 @@
1
- import { AppHeader } from './AppHeader/AppHeader';
2
- import { TabsLayout } from './TabsLayout/TabsLayout';
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
- <Box p={2}>{tabs.find((tab) => tab?.key === currentTab)?.component}</Box>
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: {