@codezee/sixtify-brahma 0.2.2 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/package.json +1 -1
  2. package/packages/shared-components/src/Actions/ConfigureAction.tsx +13 -0
  3. package/packages/shared-components/src/Actions/index.ts +2 -1
  4. package/packages/shared-components/src/AgGrid/ActionCell/ActionCell.tsx +3 -1
  5. package/packages/shared-components/src/AgGrid/AgGrid.tsx +7 -1
  6. package/packages/shared-components/src/Card/ProfileCard/ProfileCard.tsx +1 -1
  7. package/packages/shared-components/src/Card/ProfileCard/ProfileCardItem/ProfileCardBody.tsx +4 -4
  8. package/packages/shared-components/src/Card/ProfileCard/ProfileCardItem/ProfileCardHeader.tsx +1 -1
  9. package/packages/shared-components/src/Charts/PieChart.tsx +20 -8
  10. package/packages/shared-components/src/Charts/Skeleton.tsx +36 -0
  11. package/packages/shared-components/src/Drawer/Bullet.tsx +1 -1
  12. package/packages/shared-components/src/Drawer/CloseDrawer/CloseDrawerMenuItem.tsx +8 -1
  13. package/packages/shared-components/src/Drawer/CloseDrawer/CloseDrawerMenuItemList.tsx +11 -7
  14. package/packages/shared-components/src/Drawer/CloseDrawer/CloseDrawerSubMenuItemList.tsx +96 -97
  15. package/packages/shared-components/src/Drawer/CloseDrawer/Popper.tsx +3 -3
  16. package/packages/shared-components/src/Drawer/Drawer.tsx +1 -1
  17. package/packages/shared-components/src/Drawer/MenuItem.tsx +8 -2
  18. package/packages/shared-components/src/Drawer/OpenDrawer/OpenDrawerMenuItemList.tsx +162 -214
  19. package/packages/shared-components/src/FilterList/FilterListV2.tsx +24 -13
  20. package/packages/shared-components/src/FilterList/index.ts +2 -0
  21. package/packages/shared-components/src/FormFields/Autocomplete/Autocomplete.tsx +86 -4
  22. package/packages/shared-components/src/FormFields/DatePicker/DatePicker.tsx +14 -3
  23. package/packages/shared-components/src/FormFields/DatePicker/Skeleton.tsx +15 -8
  24. package/packages/shared-components/src/FormFields/DateTimePicker/DateTimePicker.tsx +9 -4
  25. package/packages/shared-components/src/FormFields/FileUpload/FileNames.tsx +32 -0
  26. package/packages/shared-components/src/FormFields/FileUpload/FileUpload.tsx +13 -53
  27. package/packages/shared-components/src/FormFields/FileUpload/index.ts +1 -0
  28. package/packages/shared-components/src/FormFields/ListItemButton/ListItemButton.tsx +16 -1
  29. package/packages/shared-components/src/FormFields/TextField/Skeleton.tsx +13 -8
  30. package/packages/shared-components/src/FormFields/TextField/TextField.tsx +2 -2
  31. package/packages/shared-components/src/FormFields/TimePicker/TimePicker.tsx +6 -0
  32. package/packages/shared-components/src/Indicator/Indicator.tsx +4 -3
  33. package/packages/shared-components/src/Layouts/FormGridLayout.tsx +27 -0
  34. package/packages/shared-components/src/Layouts/index.ts +2 -1
  35. package/packages/shared-components/src/Pagination/Pagination.tsx +42 -0
  36. package/packages/shared-components/src/Pagination/index.ts +1 -0
  37. package/packages/shared-components/src/Stepper/Stepper.tsx +1 -1
  38. package/packages/shared-components/src/Svgs/Drawer/SettingIcon.tsx +17 -37
  39. package/packages/shared-components/src/Svgs/Drawer/SvgBankConfig.tsx +36 -0
  40. package/packages/shared-components/src/Svgs/Drawer/SvgConfiguration.tsx +16 -0
  41. package/packages/shared-components/src/Svgs/Drawer/SvgPayroll.tsx +32 -0
  42. package/packages/shared-components/src/Svgs/Drawer/SvgsTransaction.tsx +72 -70
  43. package/packages/shared-components/src/Svgs/Drawer/index.ts +3 -0
  44. package/packages/shared-components/src/Svgs/ImportExcelSuccessIcon.tsx +54 -0
  45. package/packages/shared-components/src/Svgs/SvgConfigure.tsx +51 -0
  46. package/packages/shared-components/src/Svgs/SvgEmail.tsx +24 -0
  47. package/packages/shared-components/src/Svgs/SvgPhone.tsx +16 -0
  48. package/packages/shared-components/src/Svgs/SvgsHome.tsx +8 -6
  49. package/packages/shared-components/src/Svgs/SvgsIndicator.tsx +7 -3
  50. package/packages/shared-components/src/Svgs/index.ts +3 -1
  51. package/packages/shared-components/src/Timeline/TimelineTrackSegments.tsx +11 -2
  52. package/packages/shared-components/src/Tooltip/Tooltip.tsx +1 -1
  53. package/packages/shared-components/src/UserProfileMenu/UserProfileMenu.styled.tsx +3 -7
  54. package/packages/shared-components/src/UserProfileMenu/UserProfileMenu.tsx +76 -15
  55. package/packages/shared-components/src/index.ts +6 -5
  56. package/packages/shared-components/src/utils/colorVariant.ts +26 -6
  57. package/packages/shared-components/src/utils/date.ts +19 -5
  58. package/packages/shared-components/src/utils/index.ts +9 -11
  59. package/packages/shared-components/src/utils/theme/colorPalette.ts +2 -0
  60. package/packages/shared-components/src/utils/theme/theme.ts +8 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { Box, List, useTheme } from "@mui/material";
4
4
  import { isEmpty as _isEmpty } from "lodash";
5
- import { useEffect, useState } from "react";
5
+ import { type HTMLAttributeAnchorTarget, useEffect, useState } from "react";
6
6
  import { urlToNestedObject } from "../../utils/urlToNestedObject";
7
7
  import type { MenuItem } from "../Drawer";
8
8
  import { OpenDrawerCollapse } from "./OpenDrawerCollapse";
@@ -13,24 +13,164 @@ type OpenDrawerMenuItemListProps = {
13
13
  currentPathname: string;
14
14
  };
15
15
 
16
- export const OpenDrawerMenuItemList = ({
17
- menuItems,
18
- currentPathname,
19
- }: OpenDrawerMenuItemListProps) => {
20
- //TODO: jaydip, fix this type
21
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
- const [subMenusOpen, setSubMenusOpen] = useState<Record<string, any>>({});
16
+ export type NestedMenuState = {
17
+ [K in MenuItem["key"]]?:
18
+ | boolean
19
+ | {
20
+ [SubK in MenuItem["key"]]?: boolean | NestedMenuState;
21
+ };
22
+ };
23
+
24
+ type MenuItemRecursiveProps = {
25
+ menuItem: MenuItem;
26
+ level?: number;
27
+ parentPath?: string;
28
+ subMenusOpen: NestedMenuState;
29
+ setSubMenusOpen: (
30
+ value: NestedMenuState | ((prev: NestedMenuState) => NestedMenuState)
31
+ ) => void;
32
+ currentPathMenuOpen: NestedMenuState;
33
+ };
34
+
35
+ const getNestedMenuState = (state: NestedMenuState, path: string[]) => {
36
+ if (path.length === 0) {
37
+ return false;
38
+ }
39
+
40
+ if (typeof state !== "object") {
41
+ return false;
42
+ }
23
43
 
24
- const [currentPathMenuOpen, setCurrentPathMenuOpen] = useState<
25
- //TODO: jaydip, fix this type
26
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
- Record<string, any>
28
- >({});
44
+ const first = path[0];
29
45
 
46
+ if (!first) {
47
+ return false;
48
+ }
49
+
50
+ const rest = path.slice(1);
51
+
52
+ const nextState = state[first];
53
+
54
+ if (rest.length === 0) {
55
+ return Boolean(nextState);
56
+ }
57
+
58
+ return getNestedMenuState(nextState as NestedMenuState, rest);
59
+ };
60
+
61
+ export const isMenuOpen = (state: NestedMenuState, path: string[]) => {
62
+ const value = getNestedMenuState(state, path);
63
+
64
+ return Boolean(value);
65
+ };
66
+
67
+ export const MenuItemRecursive = ({
68
+ menuItem,
69
+ level = 0,
70
+ parentPath = "",
71
+ subMenusOpen,
72
+ setSubMenusOpen,
73
+ currentPathMenuOpen,
74
+ }: MenuItemRecursiveProps) => {
30
75
  const theme = useTheme();
31
76
 
77
+ if (level === 3) {
78
+ return;
79
+ }
80
+
32
81
  const { butterflyBlue, slate } = theme.palette.app.color;
33
82
 
83
+ const { key, icon, title, onClick, menuItems = [] } = menuItem;
84
+
85
+ const currentPath = parentPath ? `${parentPath}/${key}` : key;
86
+
87
+ const pathArray = currentPath.split("/");
88
+
89
+ const isMenuSelected = isMenuOpen(subMenusOpen, pathArray);
90
+
91
+ const dynamicPadding = level * 3 + 1.5;
92
+
93
+ const handleClick = (target?: HTMLAttributeAnchorTarget) => {
94
+ if (menuItems.length > 0) {
95
+ setSubMenusOpen((prev) => {
96
+ const newState = { ...prev };
97
+
98
+ let current = newState;
99
+
100
+ for (let i = 0; i < pathArray.length - 1; i++) {
101
+ const segment = pathArray[i];
102
+
103
+ if (!segment) {
104
+ continue;
105
+ }
106
+
107
+ current[segment] =
108
+ typeof current[segment] === "object" ? current[segment] : {};
109
+ current = current[segment] as NestedMenuState;
110
+ }
111
+
112
+ const lastSegment = pathArray[pathArray.length - 1];
113
+
114
+ if (lastSegment) {
115
+ current[lastSegment] = !isMenuSelected;
116
+ }
117
+
118
+ return newState;
119
+ });
120
+ } else if (onClick && !isMenuSelected) {
121
+ const path = key === "home" ? "/" : `/${currentPath}`;
122
+
123
+ onClick(path, target);
124
+ }
125
+ };
126
+
127
+ return (
128
+ <Box key={key}>
129
+ <OpenDrawerMenuItem
130
+ sx={{
131
+ paddingLeft: dynamicPadding,
132
+ ":focus-visible": {
133
+ border: `1px solid ${butterflyBlue[900]}`,
134
+ backgroundColor: slate[900],
135
+ },
136
+ }}
137
+ onClick={handleClick}
138
+ icon={level === 0 ? icon : undefined}
139
+ title={title}
140
+ isShowEndAdornment={menuItems.length > 0 && level < 2}
141
+ selected={isMenuSelected}
142
+ />
143
+
144
+ {menuItems.length > 0 && (
145
+ <OpenDrawerCollapse in={isMenuSelected}>
146
+ <List component="div" disablePadding>
147
+ {menuItems.map((subMenuItem) => (
148
+ <MenuItemRecursive
149
+ key={subMenuItem.key}
150
+ menuItem={subMenuItem}
151
+ level={level + 1}
152
+ parentPath={currentPath}
153
+ subMenusOpen={subMenusOpen}
154
+ setSubMenusOpen={setSubMenusOpen}
155
+ currentPathMenuOpen={currentPathMenuOpen}
156
+ />
157
+ ))}
158
+ </List>
159
+ </OpenDrawerCollapse>
160
+ )}
161
+ </Box>
162
+ );
163
+ };
164
+
165
+ export const OpenDrawerMenuItemList = ({
166
+ menuItems,
167
+ currentPathname,
168
+ }: OpenDrawerMenuItemListProps) => {
169
+ const [subMenusOpen, setSubMenusOpen] = useState<NestedMenuState>({});
170
+
171
+ const [currentPathMenuOpen, setCurrentPathMenuOpen] =
172
+ useState<NestedMenuState>({});
173
+
34
174
  useEffect(() => {
35
175
  const obj = urlToNestedObject(currentPathname);
36
176
 
@@ -45,205 +185,13 @@ export const OpenDrawerMenuItemList = ({
45
185
  setCurrentPathMenuOpen(obj);
46
186
  }, [currentPathname]);
47
187
 
48
- return menuItems.map((menuItem) => {
49
- const { menuItems = [], key: key1, icon, title, onClick } = menuItem;
50
-
51
- const isMenuSelected = !!subMenusOpen?.[key1];
52
-
53
- if (menuItems.length > 0) {
54
- return (
55
- <Box key={key1}>
56
- <OpenDrawerMenuItem
57
- sx={{
58
- ":focus-visible": {
59
- border: `1px solid ${butterflyBlue[900]}`,
60
- backgroundColor: slate[900],
61
- },
62
- }}
63
- onClick={() => {
64
- setSubMenusOpen((prev) => ({
65
- ...prev,
66
- [key1]: !isMenuSelected,
67
- }));
68
- }}
69
- icon={icon}
70
- title={title}
71
- isShowEndAdornment
72
- selected={isMenuSelected}
73
- key={key1}
74
- />
75
-
76
- <OpenDrawerCollapse in={isMenuSelected}>
77
- <List component="div" disablePadding key={key1}>
78
- {menuItems.map(
79
- ({ key: key2, onClick, title, menuItems = [] }) => {
80
- const isSubMenuSelected = menuItems.length
81
- ? !!subMenusOpen?.[key1]?.[key2] ||
82
- !!currentPathMenuOpen?.[key1]?.[key2]?.menuItems
83
- : !!subMenusOpen?.[key1]?.[key2] ||
84
- !!currentPathMenuOpen?.[key1]?.[key2];
85
-
86
- return (
87
- <Box
88
- sx={{
89
- bgcolor:
90
- isSubMenuSelected && menuItems.length === 0
91
- ? butterflyBlue[900]
92
- : "",
93
- }}
94
- key={key2}
95
- >
96
- {menuItems.length > 0 ? (
97
- <>
98
- <OpenDrawerMenuItem
99
- sx={{
100
- paddingLeft: 4.5,
101
- ":focus-visible": {
102
- border: `1px solid ${butterflyBlue[900]}`,
103
- backgroundColor: slate[900],
104
- },
105
- }}
106
- onClick={() => {
107
- // eslint-disable-next-line sonarjs/no-nested-functions
108
- setSubMenusOpen((prev) => ({
109
- ...prev,
110
- [key1]: {
111
- ...(prev?.[key1] || {}),
112
- [key2]: !isSubMenuSelected,
113
- },
114
- }));
115
- }}
116
- key={key2}
117
- title={title}
118
- isShowEndAdornment
119
- selected={isSubMenuSelected}
120
- />
121
- <OpenDrawerCollapse in={isSubMenuSelected}>
122
- <List component="div" disablePadding key={key2}>
123
- {menuItems.map(
124
- ({ key: key3, title, onClick }) => {
125
- const menuSelectedItem =
126
- !!subMenusOpen[key1]?.[key2]?.[key3] ||
127
- !!currentPathMenuOpen[key1]?.[key2]?.[key3];
128
-
129
- return (
130
- <Box
131
- sx={{
132
- bgcolor: menuSelectedItem
133
- ? theme.palette.app.color
134
- .butterflyBlue[900]
135
- : "",
136
- }}
137
- key={key3}
138
- >
139
- <OpenDrawerMenuItem
140
- sx={
141
- menuSelectedItem
142
- ? {
143
- paddingLeft: menuItems.length
144
- ? 7.5
145
- : 4.5,
146
- }
147
- : {
148
- paddingLeft: menuItems.length
149
- ? 7.5
150
- : 4.5,
151
- ":focus-visible": {
152
- border: `1px solid ${butterflyBlue[900]}`,
153
- backgroundColor:
154
- theme.palette.app.color
155
- .slate[900],
156
- },
157
- }
158
- }
159
- // eslint-disable-next-line sonarjs/no-nested-functions
160
- onClick={(target) => {
161
- if (onClick && !menuSelectedItem) {
162
- onClick(
163
- `/${key1}/${key2}/${key3}`,
164
- target
165
- );
166
- setSubMenusOpen((prev) => ({
167
- ...prev,
168
- [key2]: {
169
- ...(prev?.[key2] || {}),
170
- [key3]: !menuSelectedItem,
171
- },
172
- }));
173
- }
174
- }}
175
- key={key3}
176
- title={title}
177
- selected={menuSelectedItem}
178
- />
179
- </Box>
180
- );
181
- }
182
- )}
183
- </List>
184
- </OpenDrawerCollapse>
185
- </>
186
- ) : (
187
- <OpenDrawerMenuItem
188
- sx={
189
- isSubMenuSelected
190
- ? { paddingLeft: 4.5 }
191
- : {
192
- paddingLeft: 4.5,
193
- ":focus-visible": {
194
- border: `1px solid ${butterflyBlue[900]}`,
195
- backgroundColor: slate[900],
196
- },
197
- }
198
- }
199
- onClick={(target) => {
200
- if (onClick && !isSubMenuSelected) {
201
- onClick(`/${key1}/${key2}`, target);
202
- }
203
- }}
204
- key={key2}
205
- title={title}
206
- selected={isSubMenuSelected}
207
- />
208
- )}
209
- </Box>
210
- );
211
- }
212
- )}
213
- </List>
214
- </OpenDrawerCollapse>
215
- </Box>
216
- );
217
- }
218
-
219
- return (
220
- <OpenDrawerMenuItem
221
- sx={
222
- isMenuSelected
223
- ? {}
224
- : {
225
- ":focus-within": {
226
- border: `1px solid ${butterflyBlue[900]}`,
227
- backgroundColor: slate[900],
228
- },
229
- }
230
- }
231
- onClick={(target) => {
232
- if (onClick && !isMenuSelected) {
233
- if (key1 === "home") {
234
- onClick("/", target);
235
-
236
- return;
237
- }
238
-
239
- onClick(`/${key1}`, target);
240
- }
241
- }}
242
- key={key1}
243
- icon={icon}
244
- selected={isMenuSelected}
245
- title={title}
246
- />
247
- );
248
- });
188
+ return menuItems.map((menuItem) => (
189
+ <MenuItemRecursive
190
+ key={menuItem.key}
191
+ menuItem={menuItem}
192
+ subMenusOpen={subMenusOpen}
193
+ setSubMenusOpen={setSubMenusOpen}
194
+ currentPathMenuOpen={currentPathMenuOpen}
195
+ />
196
+ ));
249
197
  };
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useMemo, useRef, useState } from "react";
1
+ import { ExpandMore } from "@mui/icons-material";
2
2
  import {
3
3
  Accordion,
4
4
  AccordionDetails,
@@ -11,23 +11,25 @@ import {
11
11
  Typography,
12
12
  useTheme,
13
13
  } from "@mui/material";
14
- import type { FilterListType } from "./FilterTypeWrapper";
15
- import {
16
- FilterPopupWrapper,
17
- GetFilterPopupComponent,
18
- } from "./FilterPopupWrapper";
14
+ import { ClearIcon } from "@mui/x-date-pickers/icons";
15
+ import { isEmpty } from "lodash";
16
+ import { DateTime } from "luxon";
17
+ import React, { useEffect, useMemo, useRef, useState } from "react";
19
18
  import type { FieldValues } from "react-hook-form";
20
19
  import { useForm, useWatch } from "react-hook-form";
21
- import { SvgFilterList } from "../Svgs/SvgFilterList";
22
- import { ExpandMore } from "@mui/icons-material";
20
+ import { Button } from "../Button";
21
+ import { FilterPill } from "../Chips/FilterPill";
22
+ import { dateFormats } from "../FormFields";
23
23
  import { Switch } from "../FormFields/Switch";
24
24
  import { PadBox } from "../PadBox";
25
- import { Button } from "../Button";
26
- import { ClearIcon } from "@mui/x-date-pickers/icons";
25
+ import { SvgFilterList } from "../Svgs/SvgFilterList";
27
26
  import { Tooltip } from "../Tooltip";
28
- import { FilterPill } from "../Chips/FilterPill";
27
+ import {
28
+ FilterPopupWrapper,
29
+ GetFilterPopupComponent,
30
+ } from "./FilterPopupWrapper";
31
+ import type { FilterListType } from "./FilterTypeWrapper";
29
32
  import { getFormValue } from "./getFormData";
30
- import { isEmpty } from "lodash";
31
33
 
32
34
  export type FilterListV2Props = {
33
35
  filterListItems: FilterListType[];
@@ -37,6 +39,7 @@ export type FilterListV2Props = {
37
39
  onChange: (data: FieldValues, isPopup: boolean) => void;
38
40
  onClear: () => void;
39
41
  resetFormBasedOnFields?: string;
42
+ dateKeys?: string[];
40
43
  };
41
44
  export const FilterListV2 = ({
42
45
  filterListItems,
@@ -45,6 +48,7 @@ export const FilterListV2 = ({
45
48
  onApply,
46
49
  onClear,
47
50
  onChange,
51
+ dateKeys,
48
52
  }: FilterListV2Props) => {
49
53
  const theme = useTheme();
50
54
 
@@ -170,7 +174,14 @@ export const FilterListV2 = ({
170
174
 
171
175
  const item = getFilterItem(key);
172
176
 
173
- const keyValue = item && getFormValue(value, item);
177
+ const keyValue =
178
+ item &&
179
+ getFormValue(
180
+ dateKeys?.includes(item?.key)
181
+ ? DateTime.fromISO(value).toFormat(dateFormats.dateWithEuropean)
182
+ : value,
183
+ item
184
+ );
174
185
 
175
186
  if (!keyValue) {
176
187
  return;
@@ -1,3 +1,5 @@
1
1
  export * from "./FilterPopup";
2
2
  export * from "./FilterList";
3
3
  export * from "./FilterListV2";
4
+ export * from "./FilterTypeWrapper";
5
+ export * from "./FilterPopupWrapper";
@@ -16,18 +16,21 @@ import {
16
16
  useTheme,
17
17
  } from "@mui/material";
18
18
  import { styled } from "@mui/material/styles";
19
- import { useMemo, useRef, type KeyboardEvent } from "react";
19
+ import { useMemo, useRef, useState, type KeyboardEvent } from "react";
20
20
  import {
21
+ useController,
21
22
  type ControllerRenderProps,
22
23
  type FieldValues,
23
24
  type UseControllerProps,
24
- useController,
25
25
  } from "react-hook-form";
26
+ import { useTranslation } from "react-i18next";
26
27
  import { EditAction } from "../../Actions";
27
- import { Skeleton } from "./Skeleton";
28
+ import { toasts } from "../../Toast";
28
29
  import { BoxStyled, CheckStyled } from "../CheckBox/CheckBox.styled";
30
+ import { Skeleton } from "./Skeleton";
29
31
 
30
32
  export type Option = {
33
+ heading?: string;
31
34
  label: string;
32
35
  value: string | number;
33
36
  disabled?: boolean;
@@ -41,6 +44,7 @@ export type AutocompleteProps<P extends FieldValues> = UseControllerProps<P> &
41
44
  Omit<
42
45
  MuiAutocompleteProps<
43
46
  {
47
+ heading?: string;
44
48
  label: string;
45
49
  value: string | number;
46
50
  disabled?: boolean;
@@ -60,11 +64,14 @@ export type AutocompleteProps<P extends FieldValues> = UseControllerProps<P> &
60
64
  label?: string;
61
65
  helperText?: string;
62
66
  error?: boolean;
67
+ withLabel?: boolean;
63
68
  placeholder?: string;
64
69
  isShowAvatar?: boolean;
65
70
  shouldCloseOnSelect?: boolean;
66
71
  onAction?: () => void;
67
72
  isShowSelectAll?: boolean;
73
+ isShowOptionsOnType?: boolean;
74
+ maxLimit?: number;
68
75
  renderOption?: (
69
76
  props: React.HTMLProps<HTMLLIElement>,
70
77
  option: Option,
@@ -86,20 +93,27 @@ export function Autocomplete<P extends FieldValues>({
86
93
  loading = false,
87
94
  helperText,
88
95
  error,
96
+ withLabel = false,
89
97
  placeholder = "",
90
98
  freeSolo,
99
+ isShowOptionsOnType = false,
91
100
  isShowSelectAll = true,
92
101
  isShowAvatar = false,
93
102
  shouldCloseOnSelect = false,
94
103
  onAction,
95
104
  renderOption,
96
105
  getOptionLabel,
106
+ maxLimit,
97
107
  ...restProps
98
108
  }: AutocompleteProps<P>) {
99
109
  const {
100
110
  field: { onChange, value, ...restField },
101
111
  } = useController({ name, control, defaultValue, rules });
102
112
 
113
+ const { t } = useTranslation();
114
+
115
+ const [inputValue, setInputValue] = useState("");
116
+
103
117
  const handleSelectAll = (isSelected: boolean) => {
104
118
  if (isSelected) {
105
119
  const allValues = options.map((option) => option.value);
@@ -130,6 +144,16 @@ export function Autocomplete<P extends FieldValues>({
130
144
  ];
131
145
  }, [multiple, isShowSelectAll, options]);
132
146
 
147
+ const filteredOptions = useMemo(() => {
148
+ if (inputValue.length < 3) {
149
+ return [];
150
+ }
151
+
152
+ return options.filter((option) =>
153
+ option.label.toLowerCase().includes(inputValue.toLowerCase())
154
+ );
155
+ }, [inputValue]);
156
+
133
157
  // eslint-disable-next-line sonarjs/function-return-type
134
158
  const selectedValue = useMemo(() => {
135
159
  if (multiple && freeSolo) {
@@ -140,6 +164,8 @@ export function Autocomplete<P extends FieldValues>({
140
164
  return selectedOption ? selectedOption.label : val.toString();
141
165
  }) || []
142
166
  );
167
+ } else if (withLabel) {
168
+ return options.find((option) => option.value === value?.value) ?? null;
143
169
  } else if (multiple) {
144
170
  return options.filter((option) => value?.includes(option.value));
145
171
  } else if (!options.find((option) => option.value === value) && freeSolo) {
@@ -176,6 +202,19 @@ export function Autocomplete<P extends FieldValues>({
176
202
  },
177
203
  }));
178
204
 
205
+ const GroupHeader = styled("div")(({ theme }) => ({
206
+ position: "sticky",
207
+ padding: "4px 10px",
208
+ fontSize: "16px",
209
+ fontWeight: 500,
210
+ color: theme.palette.app.color.butterflyBlue[900],
211
+ backgroundColor: theme.palette.app.color.butterflyBlue[500],
212
+ }));
213
+
214
+ const GroupItems = styled("ul")({
215
+ padding: 0,
216
+ });
217
+
179
218
  if (loading) {
180
219
  return <Skeleton label={label} />;
181
220
  }
@@ -193,6 +232,14 @@ export function Autocomplete<P extends FieldValues>({
193
232
  }
194
233
 
195
234
  if (selectedValue && Array.isArray(selectedValue)) {
235
+ if (maxLimit && selectedValue.length >= maxLimit) {
236
+ toasts.error({
237
+ title: t("common.autocomplete.limitExceed", { maxLimit }),
238
+ });
239
+
240
+ return;
241
+ }
242
+
196
243
  const valuesArray = selectedValue.map((item) => item.value);
197
244
 
198
245
  if (valuesArray.includes(highlightedOptionRef.current)) {
@@ -339,15 +386,25 @@ export function Autocomplete<P extends FieldValues>({
339
386
  ...params.InputProps,
340
387
  startAdornment,
341
388
  }}
389
+ onChange={(e) => {
390
+ if (isShowOptionsOnType) {
391
+ setInputValue(e.target.value);
392
+ }
393
+ }}
342
394
  onKeyDown={(e) => handleKeyDown(e)}
343
395
  />
344
396
  );
345
397
  }}
346
398
  multiple={multiple}
347
- options={memoizedOptions}
399
+ options={isShowOptionsOnType ? filteredOptions : memoizedOptions}
348
400
  isOptionEqualToValue={(option, value) =>
349
401
  freeSolo ? false : option.value === value.value
350
402
  }
403
+ onInputChange={(_, __, reason) => {
404
+ if (reason === "clear") {
405
+ setInputValue("");
406
+ }
407
+ }}
351
408
  getOptionLabel={(option) => {
352
409
  if (getOptionLabel) {
353
410
  return getOptionLabel(option);
@@ -360,7 +417,25 @@ export function Autocomplete<P extends FieldValues>({
360
417
  return option.label;
361
418
  }}
362
419
  value={selectedValue}
420
+ // eslint-disable-next-line sonarjs/cognitive-complexity
363
421
  onChange={(_, newValue) => {
422
+ if (withLabel) {
423
+ return onChange(newValue);
424
+ }
425
+
426
+ if (
427
+ multiple &&
428
+ Array.isArray(newValue) &&
429
+ maxLimit &&
430
+ newValue.length > maxLimit
431
+ ) {
432
+ toasts.error({
433
+ title: t("common.autocomplete.limitExceed", { maxLimit }),
434
+ });
435
+
436
+ return;
437
+ }
438
+
364
439
  if (multiple && isShowSelectAll && Array.isArray(newValue)) {
365
440
  const isSelectAllIncluded = newValue.some(
366
441
  (option) =>
@@ -406,6 +481,13 @@ export function Autocomplete<P extends FieldValues>({
406
481
 
407
482
  onChange(newValue ? newValue.value : null);
408
483
  }}
484
+ groupBy={(option) => option.heading ?? ""}
485
+ renderGroup={(params) => (
486
+ <li key={params.key}>
487
+ <GroupHeader>{params.group}</GroupHeader>
488
+ <GroupItems>{params.children}</GroupItems>
489
+ </li>
490
+ )}
409
491
  getOptionDisabled={(option) => !!option.disabled}
410
492
  />
411
493