@antscorp/antsomi-ui 1.3.6-beta.2 → 1.3.6-beta.20

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 (50) hide show
  1. package/es/components/atoms/Input/Input.d.ts +11 -17
  2. package/es/components/atoms/Input/Input.js +7 -11
  3. package/es/components/atoms/Switch/Switch.js +2 -1
  4. package/es/components/icons/LazyIcon/LazyIcon.d.ts +2 -0
  5. package/es/components/icons/LazyIcon/LazyIcon.js +2 -0
  6. package/es/components/icons/TaskAltIcon.d.ts +3 -0
  7. package/es/components/icons/TaskAltIcon.js +7 -0
  8. package/es/components/icons/UnsubscribeIcon.d.ts +3 -0
  9. package/es/components/icons/UnsubscribeIcon.js +7 -0
  10. package/es/components/icons/index.d.ts +2 -0
  11. package/es/components/icons/index.js +2 -0
  12. package/es/components/molecules/AddDynamicContent/components/DisplayFormat/DisplayFormat.d.ts +1 -0
  13. package/es/components/molecules/CodeStructure/CodeStructure.d.ts +23 -2
  14. package/es/components/molecules/CodeStructure/CodeStructure.js +114 -24
  15. package/es/components/molecules/CodeStructure/constants.js +2 -2
  16. package/es/components/molecules/CodeStructure/styled.d.ts +3 -0
  17. package/es/components/molecules/CodeStructure/styled.js +6 -0
  18. package/es/components/molecules/CodeStructure/type.d.ts +1 -1
  19. package/es/components/molecules/CodeStructure/type.js +1 -1
  20. package/es/components/molecules/CodeStructure/utils.d.ts +7 -1
  21. package/es/components/molecules/CodeStructure/utils.js +5 -6
  22. package/es/components/molecules/DrawerDetail/DrawerDetail.js +10 -5
  23. package/es/components/molecules/DrawerDetail/types.d.ts +1 -0
  24. package/es/components/molecules/Dropdown/style.scss +6 -4
  25. package/es/components/molecules/EditingListV2/EditingList.d.ts +2 -0
  26. package/es/components/molecules/EditingListV2/EditingList.js +17 -0
  27. package/es/components/molecules/EditingListV2/components/List/List.d.ts +9 -0
  28. package/es/components/molecules/EditingListV2/components/List/List.js +42 -0
  29. package/es/components/molecules/EditingListV2/components/List/index.d.ts +1 -0
  30. package/es/components/molecules/EditingListV2/components/List/index.js +1 -0
  31. package/es/components/molecules/EditingListV2/components/Loadable.d.ts +8 -0
  32. package/es/components/molecules/EditingListV2/components/Loadable.js +2 -0
  33. package/es/components/molecules/EditingListV2/components/Popover/Popover.d.ts +11 -0
  34. package/es/components/molecules/EditingListV2/components/Popover/Popover.js +10 -0
  35. package/es/components/molecules/EditingListV2/components/Popover/index.d.ts +1 -0
  36. package/es/components/molecules/EditingListV2/components/Popover/index.js +1 -0
  37. package/es/components/molecules/EditingListV2/components/index.d.ts +3 -0
  38. package/es/components/molecules/EditingListV2/components/index.js +3 -0
  39. package/es/components/molecules/EditingListV2/index.d.ts +2 -0
  40. package/es/components/molecules/EditingListV2/index.js +1 -0
  41. package/es/components/molecules/EditingListV2/types.d.ts +18 -0
  42. package/es/components/molecules/EditingListV2/types.js +1 -0
  43. package/es/components/molecules/EditingListV2/utils.d.ts +27 -0
  44. package/es/components/molecules/EditingListV2/utils.js +28 -0
  45. package/es/components/molecules/InputSelectAttribute/index.js +9 -5
  46. package/es/components/molecules/SearchPopover/components/PopoverSelect/PopoverSelect.js +2 -2
  47. package/es/components/molecules/index.d.ts +1 -0
  48. package/es/components/molecules/index.js +1 -0
  49. package/es/components/template/TemplateListing/Loadable.d.ts +1 -0
  50. package/package.json +2 -2
@@ -1,6 +1,5 @@
1
- /// <reference types="hoist-non-react-statics" />
2
1
  import React, { ReactNode } from 'react';
3
- import { InputProps as AntdInputProps, Input as AntdInput, InputRef } from 'antd';
2
+ import { InputProps as AntdInputProps, InputRef } from 'antd';
4
3
  export interface InputProps extends AntdInputProps {
5
4
  noborder?: 'true' | 'false' | boolean;
6
5
  debounce?: number;
@@ -16,20 +15,15 @@ export interface InputProps extends AntdInputProps {
16
15
  disableUndo?: boolean;
17
16
  withWrapper?: boolean;
18
17
  }
19
- export declare const Input: string & import("styled-components").StyledComponentBase<React.ForwardRefExoticComponent<AntdInputProps & React.RefAttributes<InputRef>> & {
20
- Group: React.FC<import("antd/es/input").GroupProps>;
21
- Search: React.ForwardRefExoticComponent<import("antd/es/input").SearchProps & React.RefAttributes<InputRef>>;
22
- TextArea: React.ForwardRefExoticComponent<import("antd/es/input").TextAreaProps & React.RefAttributes<import("antd/es/input/TextArea").TextAreaRef>>;
23
- Password: React.ForwardRefExoticComponent<import("antd/es/input").PasswordProps & React.RefAttributes<InputRef>>;
24
- }, any, InputProps, never> & import("hoist-non-react-statics").NonReactStatics<React.ForwardRefExoticComponent<AntdInputProps & React.RefAttributes<InputRef>> & {
25
- Group: React.FC<import("antd/es/input").GroupProps>;
26
- Search: React.ForwardRefExoticComponent<import("antd/es/input").SearchProps & React.RefAttributes<InputRef>>;
27
- TextArea: React.ForwardRefExoticComponent<import("antd/es/input").TextAreaProps & React.RefAttributes<import("antd/es/input/TextArea").TextAreaRef>>;
28
- Password: React.ForwardRefExoticComponent<import("antd/es/input").PasswordProps & React.RefAttributes<InputRef>>;
29
- }, {}> & {
30
- DefaultInput: typeof AntdInput;
31
- CustomSearch: typeof SearchInput;
18
+ export declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<InputRef>> & {
19
+ readonly DefaultInput: React.ForwardRefExoticComponent<AntdInputProps & React.RefAttributes<InputRef>> & {
20
+ Group: React.FC<import("antd/es/input").GroupProps>;
21
+ Search: React.ForwardRefExoticComponent<import("antd/es/input").SearchProps & React.RefAttributes<InputRef>>;
22
+ TextArea: React.ForwardRefExoticComponent<import("antd/es/input").TextAreaProps & React.RefAttributes<import("antd/es/input/TextArea").TextAreaRef>>;
23
+ Password: React.ForwardRefExoticComponent<import("antd/es/input").PasswordProps & React.RefAttributes<InputRef>>;
24
+ };
25
+ readonly CustomSearch: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<InputRef>>;
26
+ readonly TextArea: React.ForwardRefExoticComponent<import("antd/es/input").TextAreaProps & React.RefAttributes<import("antd/es/input/TextArea").TextAreaRef>>;
27
+ readonly Password: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<InputRef>>;
32
28
  };
33
- declare const SearchInput: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<InputRef>>;
34
29
  export declare const TextArea: React.ForwardRefExoticComponent<import("antd/es/input").TextAreaProps & React.RefAttributes<import("antd/es/input/TextArea").TextAreaRef>>;
35
- export {};
@@ -17,7 +17,7 @@ import { PreviewVisibilityEyeIcon, VisibilityOffEyeIcon } from '../../icons';
17
17
  const PATH = '@antscorp/antsomi-ui/es/components/atoms/Input/Input.tsx';
18
18
  const OriginInput = React.forwardRef((props, ref) => {
19
19
  // Props
20
- const { withWrapper, debounce, errorArchive, required, labelColor, isReverseMask, isHideErrMessage, focused, label, onAfterChange, onChange, errorMsg, ...restProps } = props;
20
+ const { debounce = 400, isHideErrMessage = false, withWrapper = true, errorArchive, required, labelColor, isReverseMask, focused, label, onAfterChange, onChange, errorMsg, ...restProps } = props;
21
21
  // State
22
22
  const [value, setValue] = useState(props.value);
23
23
  const [isFocused, setFocused] = useState(false);
@@ -79,16 +79,12 @@ const OriginInput = React.forwardRef((props, ref) => {
79
79
  return content;
80
80
  return _jsx("div", { className: "input__wrapper", children: content });
81
81
  });
82
- OriginInput.defaultProps = {
83
- debounce: 400,
84
- isHideErrMessage: false,
85
- withWrapper: true,
86
- };
87
- export const Input = OriginInput;
88
82
  const SearchInput = React.forwardRef((props, ref) => (_jsx(OriginInput, { bordered: false, autoFocus: true, suffix: _jsx(Icon, { type: "icon-ants-search-2", size: 24, color: globalToken?.bw8 }), ...props, ref: ref, className: `${props.className} antsomi-search-input` })));
89
83
  const PasswordInput = React.forwardRef((props, ref) => (_jsx(AntdInput.Password, { iconRender: visible => visible ? (_jsx(StyledIconWrapper, { type: "text", children: _jsx(PreviewVisibilityEyeIcon, {}) })) : (_jsx(StyledIconWrapper, { type: "text", children: _jsx(VisibilityOffEyeIcon, {}) })), ...props, ref: ref })));
90
- Input.CustomSearch = SearchInput;
91
- Input.TextArea = StyledInput.TextArea;
92
- Input.DefaultInput = AntdInput;
93
- Input.Password = PasswordInput;
84
+ export const Input = Object.assign(OriginInput, {
85
+ DefaultInput: AntdInput,
86
+ CustomSearch: SearchInput,
87
+ TextArea: StyledInput.TextArea,
88
+ Password: PasswordInput,
89
+ });
94
90
  export const { TextArea } = StyledInput;
@@ -3,6 +3,7 @@ import { THEME } from '@antscorp/antsomi-ui/es/constants';
3
3
  import { StyledSwitch } from './styled';
4
4
  const Switch = props => {
5
5
  const { color = THEME.token?.colorPrimary || '#005eb8', style, ...rest } = props;
6
- return _jsx(StyledSwitch, { style: { ...style, '--switch-color': color }, ...rest });
6
+ const validatedColor = CSS.supports('color', color) ? color : THEME.token?.colorPrimary;
7
+ return _jsx(StyledSwitch, { style: { ...style, '--switch-color': validatedColor }, ...rest });
7
8
  };
8
9
  export { Switch };
@@ -346,6 +346,7 @@ export declare const LazyIcon: {
346
346
  TabGroupIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
347
347
  TableIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
348
348
  TableVer2Icon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
349
+ TaskAltIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
349
350
  TextIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
350
351
  ThirdPartyPluginV130Icon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
351
352
  ThirdPartyPluginV230Icon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
@@ -360,6 +361,7 @@ export declare const LazyIcon: {
360
361
  UnblockIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
361
362
  UndoIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
362
363
  Unknown30Icon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
364
+ UnsubscribeIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
363
365
  UploadIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
364
366
  UploadMenuIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
365
367
  UserActivityIcon: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<import("../types").IconProps & import("react").RefAttributes<SVGSVGElement>>>;
@@ -352,6 +352,7 @@ export const LazyIcon = {
352
352
  TabGroupIcon: lazy(() => import('../TabGroupIcon').then(m => ({ default: m.TabGroupIcon }))),
353
353
  TableIcon: lazy(() => import('../TableIcon').then(m => ({ default: m.TableIcon }))),
354
354
  TableVer2Icon: lazy(() => import('../TableVer2Icon').then(m => ({ default: m.TableVer2Icon }))),
355
+ TaskAltIcon: lazy(() => import('../TaskAltIcon').then(m => ({ default: m.TaskAltIcon }))),
355
356
  TextIcon: lazy(() => import('../TextIcon').then(m => ({ default: m.TextIcon }))),
356
357
  ThirdPartyPluginV130Icon: lazy(() => import('../ThirdPartyPluginV130Icon').then(m => ({ default: m.ThirdPartyPluginV130Icon }))),
357
358
  ThirdPartyPluginV230Icon: lazy(() => import('../ThirdPartyPluginV230Icon').then(m => ({ default: m.ThirdPartyPluginV230Icon }))),
@@ -366,6 +367,7 @@ export const LazyIcon = {
366
367
  UnblockIcon: lazy(() => import('../UnblockIcon').then(m => ({ default: m.UnblockIcon }))),
367
368
  UndoIcon: lazy(() => import('../UndoIcon').then(m => ({ default: m.UndoIcon }))),
368
369
  Unknown30Icon: lazy(() => import('../Unknown30Icon').then(m => ({ default: m.Unknown30Icon }))),
370
+ UnsubscribeIcon: lazy(() => import('../UnsubscribeIcon').then(m => ({ default: m.UnsubscribeIcon }))),
369
371
  UploadIcon: lazy(() => import('../UploadIcon').then(m => ({ default: m.UploadIcon }))),
370
372
  UploadMenuIcon: lazy(() => import('../UploadMenuIcon').then(m => ({ default: m.UploadMenuIcon }))),
371
373
  UserActivityIcon: lazy(() => import('../UserActivityIcon').then(m => ({ default: m.UserActivityIcon }))),
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { IconProps } from './types';
3
+ export declare const TaskAltIcon: React.ForwardRefExoticComponent<IconProps & React.RefAttributes<SVGSVGElement>>;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ import { useIcon } from './hooks/useIcon';
4
+ export const TaskAltIcon = forwardRef((props, ref) => {
5
+ const { width, height } = useIcon(props);
6
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 -960 960 960", fill: "currentColor", ...props, ref: ref, width: width, height: height, children: _jsx("path", { d: "M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q65 0 123 19t107 53l-58 59q-38-24-81-37.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160q133 0 226.5-93.5T800-480q0-18-2-36t-6-35l65-65q11 32 17 66t6 70q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm-56-216L254-466l56-56 114 114 400-401 56 56-456 457Z" }) }));
7
+ });
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { IconProps } from './types';
3
+ export declare const UnsubscribeIcon: React.ForwardRefExoticComponent<IconProps & React.RefAttributes<SVGSVGElement>>;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ import { useIcon } from './hooks/useIcon';
4
+ export const UnsubscribeIcon = forwardRef((props, ref) => {
5
+ const { width, height } = useIcon(props);
6
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 -960 960 960", fill: "currentColor", ...props, ref: ref, width: width, height: height, children: _jsx("path", { d: "M480-440 160-640v400h320q0 21 3 40.5t9 39.5H160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v228q-18-9-38.5-15t-41.5-9v-124L480-440Zm0-80 320-200H160l320 200ZM760-40q-83 0-141.5-58.5T560-240q0-83 58.5-141.5T760-440q83 0 141.5 58.5T960-240q0 83-58.5 141.5T760-40ZM640-220h240v-40H640v40Zm-480-20v-480 480Z" }) }));
7
+ });
@@ -342,6 +342,7 @@ export { SystemRunningIcon } from './SystemRunningIcon';
342
342
  export { TabGroupIcon } from './TabGroupIcon';
343
343
  export { TableIcon } from './TableIcon';
344
344
  export { TableVer2Icon } from './TableVer2Icon';
345
+ export { TaskAltIcon } from './TaskAltIcon';
345
346
  export { TextIcon } from './TextIcon';
346
347
  export { ThirdPartyPluginV130Icon } from './ThirdPartyPluginV130Icon';
347
348
  export { ThirdPartyPluginV230Icon } from './ThirdPartyPluginV230Icon';
@@ -356,6 +357,7 @@ export { TipsIdeaLight30Icon } from './TipsIdeaLight30Icon';
356
357
  export { UnblockIcon } from './UnblockIcon';
357
358
  export { UndoIcon } from './UndoIcon';
358
359
  export { Unknown30Icon } from './Unknown30Icon';
360
+ export { UnsubscribeIcon } from './UnsubscribeIcon';
359
361
  export { UploadIcon } from './UploadIcon';
360
362
  export { UploadMenuIcon } from './UploadMenuIcon';
361
363
  export { UserActivityIcon } from './UserActivityIcon';
@@ -342,6 +342,7 @@ export { SystemRunningIcon } from './SystemRunningIcon';
342
342
  export { TabGroupIcon } from './TabGroupIcon';
343
343
  export { TableIcon } from './TableIcon';
344
344
  export { TableVer2Icon } from './TableVer2Icon';
345
+ export { TaskAltIcon } from './TaskAltIcon';
345
346
  export { TextIcon } from './TextIcon';
346
347
  export { ThirdPartyPluginV130Icon } from './ThirdPartyPluginV130Icon';
347
348
  export { ThirdPartyPluginV230Icon } from './ThirdPartyPluginV230Icon';
@@ -356,6 +357,7 @@ export { TipsIdeaLight30Icon } from './TipsIdeaLight30Icon';
356
357
  export { UnblockIcon } from './UnblockIcon';
357
358
  export { UndoIcon } from './UndoIcon';
358
359
  export { Unknown30Icon } from './Unknown30Icon';
360
+ export { UnsubscribeIcon } from './UnsubscribeIcon';
359
361
  export { UploadIcon } from './UploadIcon';
360
362
  export { UploadMenuIcon } from './UploadMenuIcon';
361
363
  export { UserActivityIcon } from './UserActivityIcon';
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import type { PayloadInfo } from '@antscorp/antsomi-ui/es/types';
2
3
  export type TDisplayFormat = 'number' | 'percentage' | 'currency' | 'datetime';
3
4
  type DisplayFormatProps = {
@@ -1,11 +1,32 @@
1
1
  import React from 'react';
2
2
  import { CodeStructureData } from './type';
3
3
  interface CodeStructureProps {
4
- initialData: CodeStructureData;
4
+ initialData: Partial<CodeStructureData>;
5
5
  onChange: ({ data, isError }: {
6
- data: CodeStructureData;
6
+ data: Partial<CodeStructureData>;
7
7
  isError: boolean;
8
8
  }) => void;
9
9
  }
10
+ /**
11
+ * Component to configure the code structure for a pool rule.
12
+ *
13
+ * The component contains a form with fields for:
14
+ * - Prefix
15
+ * - Infix (character type, number of digits, number of letters, capitalization, character order)
16
+ * - Suffix
17
+ * - Separator
18
+ * - Quantity (number of codes per time)
19
+ * - Refill interval (manual or automatic)
20
+ * - Refill threshold (number of codes remaining)
21
+ * - Refill unit (codes or percent)
22
+ *
23
+ * The form also displays a preview of the generated code sample.
24
+ *
25
+ * The component calls the `onChange` callback with the updated form values and an `isError` flag
26
+ * indicating whether the form is valid or not.
27
+ *
28
+ * @param {CodeStructureProps} props The component props.
29
+ * @returns {React.ReactElement} The rendered component.
30
+ */
10
31
  export declare const CodeStructure: React.FC<CodeStructureProps>;
11
32
  export {};
@@ -1,20 +1,42 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // Libraries
3
- import { useEffect } from 'react';
3
+ import { memo, useEffect } from 'react';
4
4
  import { Form, InputNumber, Radio, Select, Typography, Flex, Input, Row, Col } from 'antd';
5
5
  import { useImmer } from 'use-immer';
6
6
  import { translate, translations } from '@antscorp/antsomi-locales';
7
+ import { isEmpty } from 'lodash';
7
8
  // Utils
8
9
  import { calculateTotalCodes, generateCodeWithPrefixAndSuffix, generateRandomCodeWithConfig, } from './utils';
9
10
  // Types
10
11
  import { CapitalizationType, CharacterOrderType, CharacterType, RefillType, RefillUnitType, SeparatorType, } from './type';
11
12
  // Constants
12
13
  import { CAPITALIZATION_OPTIONS, CHARACTER_ORDER_OPTIONS, CHARACTER_TYPE_OPTIONS, REFILL_UNIT_OPTIONS, SEPARATOR_OPTIONS, } from './constants';
13
- import { CodeStructureWrapper } from './styled';
14
+ import { BlockAbsolute, CodeStructureWrapper } from './styled';
14
15
  import { useDebouncedCallbackV2 } from '@antscorp/antsomi-ui/es/hooks';
15
16
  const { Title } = Typography;
16
- export const CodeStructure = ({ initialData, onChange }) => {
17
- const { characterType = CharacterType.DIGIT_AND_LETTERS, digitalNumbers = 2, alphabetLetters = 3, capitalization = CapitalizationType.UPPERCASE, characterOrder = CharacterOrderType.RANDOM, separator = SeparatorType.UNDERSCORE, quantity = 1, suffix = '', refillInterval = RefillType.MANUAL, prefix = '', refillThreshold = 10, refillUnit = RefillUnitType.CODES, } = initialData;
17
+ /**
18
+ * Component to configure the code structure for a pool rule.
19
+ *
20
+ * The component contains a form with fields for:
21
+ * - Prefix
22
+ * - Infix (character type, number of digits, number of letters, capitalization, character order)
23
+ * - Suffix
24
+ * - Separator
25
+ * - Quantity (number of codes per time)
26
+ * - Refill interval (manual or automatic)
27
+ * - Refill threshold (number of codes remaining)
28
+ * - Refill unit (codes or percent)
29
+ *
30
+ * The form also displays a preview of the generated code sample.
31
+ *
32
+ * The component calls the `onChange` callback with the updated form values and an `isError` flag
33
+ * indicating whether the form is valid or not.
34
+ *
35
+ * @param {CodeStructureProps} props The component props.
36
+ * @returns {React.ReactElement} The rendered component.
37
+ */
38
+ export const CodeStructure = memo(({ initialData, onChange }) => {
39
+ const { characterType = CharacterType.DIGIT_AND_LETTERS, digitalNumbers = 2, alphabetLetters = 3, capitalization = CapitalizationType.UPPERCASE, characterOrder = CharacterOrderType.RANDOM, separator = SeparatorType.UNDERSCORE, quantity = 50, suffix = '', refillInterval = RefillType.MANUAL, prefix = '', refillThreshold = 10, refillUnit = RefillUnitType.CODES, } = initialData;
18
40
  const [form] = Form.useForm();
19
41
  const [state, setState] = useImmer({
20
42
  codeSample: '',
@@ -42,7 +64,7 @@ export const CodeStructure = ({ initialData, onChange }) => {
42
64
  draft.codeWithPrefixAndSuffix = value;
43
65
  });
44
66
  };
45
- const debouncedOnChange = useDebouncedCallbackV2(onChange, 350);
67
+ const debouncedOnChange = useDebouncedCallbackV2(onChange, 400);
46
68
  const updateFormValues = async (fieldKeyChange, isError) => {
47
69
  // Get all values from the form
48
70
  const allValues = form.getFieldsValue();
@@ -67,14 +89,38 @@ export const CodeStructure = ({ initialData, onChange }) => {
67
89
  totalPredicted = total;
68
90
  setMaxCodes(total);
69
91
  }
92
+ let codeSampleTmp = codeSample;
70
93
  if (isRelevantChangeCodeKey) {
71
- setCodeSample(generateRandomCodeWithConfig(form.getFieldsValue()));
94
+ codeSampleTmp = generateRandomCodeWithConfig(form.getFieldsValue());
95
+ setCodeSample(codeSampleTmp);
72
96
  }
73
97
  if (isChangePrefix) {
74
- setCodeWithPrefixAndSuffix(generateCodeWithPrefixAndSuffix(codeSample, form.getFieldValue('prefix'), form.getFieldValue('suffix'), form.getFieldValue('separator')));
98
+ setCodeWithPrefixAndSuffix(generateCodeWithPrefixAndSuffix(codeSampleTmp, form.getFieldValue('prefix'), form.getFieldValue('suffix'), form.getFieldValue('separator')));
75
99
  }
76
100
  const dataOnChange = {
77
- ...allValues,
101
+ quantity: allValues.quantity,
102
+ refillInterval: allValues.refillInterval,
103
+ prefix: allValues.prefix,
104
+ suffix: allValues.suffix,
105
+ separator: allValues.separator,
106
+ ...(allValues.refillInterval === 'auto' && {
107
+ refillThreshold: allValues.refillThreshold,
108
+ refillUnit: allValues.refillUnit,
109
+ }),
110
+ characterType: allValues.characterType,
111
+ ...(allValues.characterType === CharacterType.DIGIT_AND_LETTERS && {
112
+ digitalNumbers: allValues.digitalNumbers,
113
+ alphabetLetters: allValues.alphabetLetters,
114
+ capitalization: allValues.capitalization,
115
+ characterOrder: allValues.characterOrder,
116
+ }),
117
+ ...(allValues.characterType === CharacterType.DIGITS && {
118
+ digitalNumbers: allValues.digitalNumbers,
119
+ }),
120
+ ...(allValues.characterType === CharacterType.LETTERS && {
121
+ alphabetLetters: allValues.alphabetLetters,
122
+ capitalization: allValues.capitalization,
123
+ }),
78
124
  totalPredicted,
79
125
  };
80
126
  debouncedOnChange({
@@ -86,11 +132,33 @@ export const CodeStructure = ({ initialData, onChange }) => {
86
132
  setMaxCodes(calculateTotalCodes(alphabetLetters, digitalNumbers, characterType));
87
133
  }, [alphabetLetters, digitalNumbers, characterType]);
88
134
  useEffect(() => {
89
- setCodeSample(generateRandomCodeWithConfig(initialData));
135
+ setCodeSample(generateRandomCodeWithConfig({
136
+ characterType,
137
+ digitalNumbers,
138
+ alphabetLetters,
139
+ capitalization,
140
+ characterOrder,
141
+ }));
90
142
  }, [characterType, digitalNumbers, alphabetLetters, capitalization, characterOrder]);
91
143
  useEffect(() => {
92
- form.setFieldsValue(initialData);
93
- }, [initialData, form]);
144
+ setCodeWithPrefixAndSuffix(generateCodeWithPrefixAndSuffix(codeSample, prefix, suffix, separator));
145
+ }, [codeSample, prefix, suffix, separator]);
146
+ useEffect(() => {
147
+ form.setFieldsValue({
148
+ prefix,
149
+ suffix,
150
+ separator,
151
+ quantity,
152
+ refillInterval,
153
+ refillThreshold,
154
+ refillUnit,
155
+ characterType,
156
+ digitalNumbers,
157
+ alphabetLetters,
158
+ capitalization,
159
+ characterOrder,
160
+ });
161
+ }, [initialData]);
94
162
  return (_jsx(CodeStructureWrapper, { children: _jsxs(Form, { form: form, layout: "horizontal", labelCol: { span: 6 }, colon: false, wrapperCol: { span: 24 }, labelAlign: "left", initialValues: {
95
163
  characterType,
96
164
  digitalNumbers,
@@ -108,30 +176,52 @@ export const CodeStructure = ({ initialData, onChange }) => {
108
176
  const fieldKeyChange = changedFields[0].name[0];
109
177
  const isValidate = form.getFieldsError().some(field => field.errors.length > 0);
110
178
  updateFormValues(fieldKeyChange, isValidate);
111
- }, children: [_jsx(Title, { level: 5, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE, 'Code Structure') }), _jsx(Form.Item, { label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_PREFIX, 'Prefix'), name: "prefix", children: _jsx(Input, { placeholder: "", style: {
179
+ }, children: [_jsx(Title, { level: 5, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE, 'Code Structure') }), _jsx(Form.Item, { label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_PREFIX, 'Prefix'), name: "prefix", rules: [
180
+ {
181
+ pattern: /^[a-zA-Z0-9]+$/i,
182
+ message: 'Invalid input. Use only letters and numbers.',
183
+ },
184
+ ], children: _jsx(Input, { placeholder: "", style: {
112
185
  maxWidth: 465,
113
- } }) }), _jsxs(Row, { children: [_jsx(Col, { span: 6, offset: 0, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_INFIX, 'Infix') }), _jsx(Col, { span: 16, offset: 0, children: _jsxs(Flex, { vertical: true, gap: 10, children: [_jsx(Row, { children: _jsx(Col, { offset: 0, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_TYPE, 'Character Type') }) }), _jsx(Form.Item, { name: "characterType", children: _jsx(Radio.Group, { options: CHARACTER_TYPE_OPTIONS }) })] }) })] }), _jsx(Row, { children: _jsx(Col, { offset: 6, children: _jsxs(Flex, { gap: 10, align: "center", children: [_jsx(Form.Item, { name: "digitalNumbers", children: _jsx(InputNumber, { min: 1, max: 50, style: { width: '40px' } }) }), _jsx("div", { style: { marginBottom: '15px' }, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_TYPE_DIG_NO, 'digital numbers') })] }) }) }), _jsx(Row, { children: _jsx(Col, { offset: 6, children: _jsxs(Flex, { gap: 10, align: "center", children: [_jsx(Form.Item, { name: "alphabetLetters", children: _jsx(InputNumber, { min: 1, max: 50, style: { width: '40px' } }) }), _jsx("div", { style: { marginBottom: '15px' }, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_TYPE_LET_NO, 'alphabet letters') })] }) }) }), _jsxs(Flex, { vertical: true, gap: 10, children: [_jsx(Row, { children: _jsx(Col, { offset: 6, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CAP, 'Letters Capitalization') }) }), _jsx(Form.Item, { label: _jsx("span", { children: "\u00A0" }), name: "capitalization", children: _jsx(Radio.Group, { options: CAPITALIZATION_OPTIONS }) })] }), _jsxs(Flex, { vertical: true, gap: 10, children: [_jsx(Row, { children: _jsx(Col, { offset: 6, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_ORDER, 'Character Order') }) }), _jsx(Form.Item, { label: _jsx("span", { children: "\u00A0" }), name: "characterOrder", children: _jsx(Radio.Group, { options: CHARACTER_ORDER_OPTIONS }) })] }), _jsx(Form.Item, { label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_SUFFIX, 'Suffix'), name: "suffix", children: _jsx(Input, { placeholder: "", style: {
186
+ } }) }), _jsxs(Row, { children: [_jsx(Col, { span: 6, offset: 0, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_INFIX, 'Infix') }), _jsx(Col, { span: 16, offset: 0, children: _jsxs(Flex, { vertical: true, gap: 10, children: [_jsx(Row, { children: _jsx(Col, { offset: 0, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_TYPE, 'Character Type') }) }), _jsx(Form.Item, { name: "characterType", children: _jsx(Radio.Group, { options: CHARACTER_TYPE_OPTIONS }) })] }) })] }), _jsx(Row, { children: _jsx(Col, { offset: 6, children: _jsxs(Flex, { gap: 10, align: "center", style: {
187
+ position: 'relative',
188
+ }, children: [_jsx(Form.Item, { hidden: form.getFieldValue('characterType') === CharacterType.LETTERS, shouldUpdate: true, name: "digitalNumbers", rules: [{ required: true, message: `This field can't be empty` }], children: _jsx(InputNumber, { min: 1, max: 50, style: { width: '65px' } }) }), (form.getFieldValue('characterType') === CharacterType.DIGITS ||
189
+ form.getFieldValue('characterType') === CharacterType.DIGIT_AND_LETTERS) && (_jsx(BlockAbsolute, { children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_TYPE_DIG_NO, 'digital numbers') }))] }) }) }), _jsx(Row, { children: _jsx(Col, { offset: 6, children: _jsxs(Flex, { gap: 10, align: "center", style: {
190
+ position: 'relative',
191
+ }, children: [_jsx(Form.Item, { hidden: form.getFieldValue('characterType') === CharacterType.DIGITS, name: "alphabetLetters", rules: [{ required: true, message: `This field can't be empty` }], children: _jsx(InputNumber, { min: 1, max: 50, style: { width: '65px' } }) }), (form.getFieldValue('characterType') === CharacterType.DIGIT_AND_LETTERS ||
192
+ form.getFieldValue('characterType') === CharacterType.LETTERS) && (_jsx(BlockAbsolute, { children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_TYPE_LET_NO, 'alphabet letters') }))] }) }) }), _jsxs(Flex, { vertical: true, gap: 10, children: [_jsx(Row, { children: form.getFieldValue('characterType') !== CharacterType.DIGITS && (_jsx(Col, { offset: 6, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CAP, 'Letters Capitalization') })) }), _jsx(Form.Item, { hidden: form.getFieldValue('characterType') === CharacterType.DIGITS, label: _jsx("span", { children: "\u00A0" }), name: "capitalization", children: _jsx(Radio.Group, { options: CAPITALIZATION_OPTIONS }) })] }), _jsxs(Flex, { vertical: true, gap: 10, children: [_jsx(Row, { children: form.getFieldValue('characterType') === CharacterType.DIGIT_AND_LETTERS && (_jsx(Col, { offset: 6, children: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_ORDER, 'Character Order') })) }), _jsx(Form.Item, { hidden: form.getFieldValue('characterType') !== CharacterType.DIGIT_AND_LETTERS, label: _jsx("span", { children: "\u00A0" }), name: "characterOrder", children: _jsx(Radio.Group, { options: CHARACTER_ORDER_OPTIONS }) })] }), _jsx(Form.Item, { label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_SUFFIX, 'Suffix'), name: "suffix", rules: [
193
+ {
194
+ pattern: /^[a-zA-Z0-9]+$/i,
195
+ message: 'Invalid input. Use only letters and numbers.',
196
+ },
197
+ ], children: _jsx(Input, { placeholder: "", style: {
114
198
  maxWidth: 465,
115
- } }) }), _jsx(Form.Item, { label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_SEPARATOR, 'Separator'), name: "separator", children: _jsx(Select, { options: SEPARATOR_OPTIONS, style: { width: '180px' } }) }), _jsxs(Row, { children: [_jsx(Col, { span: 6, children: _jsxs(Flex, { justify: "start", align: "center", gap: 5, children: [translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_QUANTITY, 'Quantity'), ' ', _jsx("span", { style: { color: 'red' }, children: "*" })] }) }), _jsx(Col, { children: _jsxs(Flex, { gap: 10, align: "center", children: [_jsx(Form.Item, { required: true, name: "quantity", rules: [{ required: true }], children: _jsx(InputNumber, { min: 1, max: 10000 }) }), _jsx("div", { style: { marginBottom: '15px' }, children: "code(s) per time" })] }) })] }), _jsxs(Form.Item, { label: translate(translations._ACT_PREVIEW, 'Preview'), children: ["Maximum of ", _jsx("b", { children: maxCodes.toLocaleString() }), " codes (sample", ' ', generateCodeWithPrefixAndSuffix(codeSample, form.getFieldValue('prefix'), form.getFieldValue('suffix'), form.getFieldValue('separator')), ") to be generated"] }), _jsx(Title, { level: 5, children: "Code Refill" }), _jsx(Form.Item, { label: "Refill Interval", name: "refillInterval", children: _jsxs(Radio.Group, { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: [_jsx(Radio, { value: "manual", children: "Manual refill only" }), _jsx(Radio, { value: "auto", children: _jsxs(Flex, { gap: 10, align: "center", children: [_jsx(Typography.Text, { style: { whiteSpace: 'nowrap' }, children: "Add codes when less than" }), _jsx(Form.Item, { noStyle: true, shouldUpdate: true, children: ({ getFieldValue }) => {
199
+ } }) }), _jsx(Form.Item, { label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_SEPARATOR, 'Separator'), name: "separator", children: _jsx(Select, { options: SEPARATOR_OPTIONS, style: { width: '180px' } }) }), _jsxs(Row, { children: [_jsx(Col, { span: 6, children: _jsxs(Flex, { justify: "start", align: "center", gap: 5, children: [translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_QUANTITY, 'Quantity'), ' ', _jsx("span", { style: { color: 'red' }, children: "*" })] }) }), _jsx(Col, { children: _jsxs(Flex, { gap: 10, align: "center", style: { position: 'relative' }, children: [_jsx(Form.Item, { required: true, name: "quantity", rules: [{ required: true, message: `This field can't be empty` }], children: _jsx(InputNumber, { min: 0, max: 10000, style: { width: '65px' } }) }), _jsx(BlockAbsolute, { children: "code(s) per time" })] }) })] }), _jsx(Form.Item, { label: translate(translations._ACT_PREVIEW, 'Preview'), children: _jsxs(Typography.Text, { children: ["Maximum of ", _jsx("b", { children: maxCodes.toLocaleString() }), " codes (sample", ' ', state.codeWithPrefixAndSuffix, " ) to be generated"] }) }), _jsx(Title, { level: 5, children: "Code Refill" }), _jsx(Form.Item, { label: "Refill Interval", name: "refillInterval", children: _jsxs(Radio.Group, { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, onChange: e => {
200
+ if (e.target.value === 'manual' && isEmpty(form.getFieldValue('refillThreshold'))) {
201
+ form.setFieldsValue({ refillThreshold: 10 });
202
+ form.validateFields(['refillThreshold']);
203
+ }
204
+ }, children: [_jsx(Radio, { value: "manual", children: "Manual refill only" }), _jsx(Radio, { value: "auto", children: _jsxs(Flex, { gap: 10, align: "center", children: [_jsx(Typography.Text, { style: { whiteSpace: 'nowrap' }, children: "Add codes when less than" }), _jsx(Form.Item, { noStyle: true, shouldUpdate: true, children: ({ getFieldValue }) => {
116
205
  const refillUnit = getFieldValue('refillUnit');
117
206
  return (_jsx(Form.Item, { name: "refillThreshold", noStyle: true, rules: [
118
207
  { required: true, message: '' },
119
208
  {
120
209
  validator: (_, value) => {
121
210
  if (refillUnit === RefillUnitType.PERCENT) {
122
- if (value < 1 || value > 100) {
123
- return Promise.reject(new Error(''));
124
- }
125
- }
126
- else if (refillUnit === RefillUnitType.CODES) {
127
- if (value < 0) {
128
- return Promise.reject(new Error(''));
211
+ if (value > 100) {
212
+ form.setFieldsValue({ refillThreshold: 100 });
129
213
  }
130
214
  }
131
215
  return Promise.resolve();
132
216
  },
133
217
  },
134
- ], children: _jsx(InputNumber, { min: refillUnit === RefillUnitType.CODES ? 0 : 1, max: refillUnit === RefillUnitType.PERCENT ? 100 : undefined, style: { width: '63px' } }) }));
218
+ ], children: _jsx(InputNumber, { onBlur: e => {
219
+ const { value } = e.target;
220
+ if (isEmpty(value)) {
221
+ form.setFieldsValue({ refillThreshold: 1 });
222
+ form.validateFields(['refillThreshold']);
223
+ }
224
+ }, min: 1, max: refillUnit === RefillUnitType.PERCENT ? 100 : undefined, style: { width: '63px' } }) }));
135
225
  } }), _jsx(Form.Item, { noStyle: true, shouldUpdate: true, children: () => (_jsx(Form.Item, { name: "refillUnit", noStyle: true, rules: [
136
226
  { required: true, message: '' },
137
227
  {
@@ -139,5 +229,5 @@ export const CodeStructure = ({ initialData, onChange }) => {
139
229
  form.validateFields(['refillThreshold']);
140
230
  },
141
231
  },
142
- ], children: _jsx(Select, { options: REFILL_UNIT_OPTIONS, style: { width: '63px' }, onClick: e => e.preventDefault() }) })) }), "remaining"] }) })] }) })] }) }));
143
- };
232
+ ], children: _jsx(Select, { defaultValue: RefillUnitType.CODES, options: REFILL_UNIT_OPTIONS, style: { width: '63px' }, onClick: e => e.preventDefault() }) })) }), "remaining"] }) })] }) })] }) }));
233
+ });
@@ -30,8 +30,8 @@ export const CAPITALIZATION_OPTIONS = [
30
30
  label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CAP_LOW, 'lowercase'),
31
31
  },
32
32
  {
33
- value: CapitalizationType.TITLE_CASE,
34
- label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CAP_TITL, 'Title case'),
33
+ value: CapitalizationType.RANDOM,
34
+ label: translate(translations._POOL_RULE_SETTING_CODE_STRUCTURE_CHAC_ORDER_RANDOM, 'Random'),
35
35
  },
36
36
  ];
37
37
  export const CHARACTER_ORDER_OPTIONS = [
@@ -1 +1,4 @@
1
1
  export declare const CodeStructureWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
2
+ export declare const BlockAbsolute: import("styled-components").StyledComponent<"div", any, {
3
+ left?: number | undefined;
4
+ }, never>;
@@ -1,2 +1,8 @@
1
1
  import styled from 'styled-components';
2
2
  export const CodeStructureWrapper = styled.div ``;
3
+ export const BlockAbsolute = styled.div `
4
+ position: absolute;
5
+ left: ${p => p.left || 75}px;
6
+ white-space: nowrap;
7
+ margin-bottom: 15px;
8
+ `;
@@ -11,7 +11,7 @@ export declare enum CharacterOrderType {
11
11
  export declare enum CapitalizationType {
12
12
  UPPERCASE = "upper",
13
13
  LOWERCASE = "lower",
14
- TITLE_CASE = "title"
14
+ RANDOM = "random"
15
15
  }
16
16
  export declare enum SeparatorType {
17
17
  HYPHEN = "hyphen",
@@ -14,7 +14,7 @@ export var CapitalizationType;
14
14
  (function (CapitalizationType) {
15
15
  CapitalizationType["UPPERCASE"] = "upper";
16
16
  CapitalizationType["LOWERCASE"] = "lower";
17
- CapitalizationType["TITLE_CASE"] = "title";
17
+ CapitalizationType["RANDOM"] = "random";
18
18
  })(CapitalizationType || (CapitalizationType = {}));
19
19
  export var SeparatorType;
20
20
  (function (SeparatorType) {
@@ -1,4 +1,10 @@
1
1
  import { CharacterType, CodeStructureData, SeparatorType } from './type';
2
- export declare const generateRandomCodeWithConfig: ({ characterType, digitalNumbers, alphabetLetters, capitalization, characterOrder, }: CodeStructureData) => string;
2
+ export declare const generateRandomCodeWithConfig: ({ characterType, digitalNumbers, alphabetLetters, capitalization, characterOrder, }: {
3
+ characterType: CodeStructureData['characterType'];
4
+ digitalNumbers: CodeStructureData['digitalNumbers'];
5
+ alphabetLetters: CodeStructureData['alphabetLetters'];
6
+ capitalization: CodeStructureData['capitalization'];
7
+ characterOrder: CodeStructureData['characterOrder'];
8
+ }) => string;
3
9
  export declare const generateCodeWithPrefixAndSuffix: (code: string, prefix: string, suffix: string, separator: SeparatorType) => string;
4
10
  export declare const calculateTotalCodes: (numberOfLetters: number, numberOfDigits: number, characterType: CharacterType) => number;
@@ -18,8 +18,10 @@ export const generateRandomCodeWithConfig = ({ characterType, digitalNumbers, al
18
18
  else if (capitalization === CapitalizationType.LOWERCASE) {
19
19
  letterPart = letterPart.toLowerCase();
20
20
  }
21
- else if (capitalization === CapitalizationType.TITLE_CASE && letterPart.length > 0) {
22
- letterPart = letterPart.charAt(0).toUpperCase() + letterPart.slice(1).toLowerCase();
21
+ else if (capitalization === CapitalizationType.RANDOM) {
22
+ letterPart = Array.from(letterPart)
23
+ .map(char => (Math.random() < 0.5 ? char.toUpperCase() : char.toLowerCase()))
24
+ .join('');
23
25
  }
24
26
  // Order characters
25
27
  let finalCode = '';
@@ -40,10 +42,7 @@ export const generateRandomCodeWithConfig = ({ characterType, digitalNumbers, al
40
42
  export const generateCodeWithPrefixAndSuffix = (code, prefix, suffix, separator) => {
41
43
  let finalCode = code;
42
44
  // Apply prefix and suffix
43
- if (prefix)
44
- finalCode = `${prefix}${separator !== SeparatorType.NONE ? (separator === SeparatorType.HYPHEN ? '-' : separator === SeparatorType.DOT ? '.' : '_') : ''}${finalCode}`;
45
- if (suffix)
46
- finalCode = `${finalCode}${separator !== SeparatorType.NONE ? (separator === SeparatorType.HYPHEN ? '-' : separator === SeparatorType.DOT ? '.' : '_') : ''}${suffix}`;
45
+ finalCode = `${prefix}${separator !== SeparatorType.NONE ? (separator === SeparatorType.HYPHEN ? '-' : separator === SeparatorType.DOT ? '.' : '_') : ''}${finalCode}${separator !== SeparatorType.NONE ? (separator === SeparatorType.HYPHEN ? '-' : separator === SeparatorType.DOT ? '.' : '_') : ''}${suffix}`;
47
46
  return finalCode;
48
47
  };
49
48
  export const calculateTotalCodes = (numberOfLetters, numberOfDigits, characterType) => {
@@ -16,7 +16,7 @@ import { safeParseJson } from '@antscorp/antsomi-ui/es/utils';
16
16
  import { POST_MESSAGE_TYPES } from '@antscorp/antsomi-ui/es/constants';
17
17
  export const DrawerDetail = props => {
18
18
  // Props
19
- const { width, fullScreen: fullScreenProp = false, children, menuProps, closeIconProps, maxWidth, minWidth, defaultSize = 'max', headerProps, name, destroyOnClose = true, mask = false, classNames, onToggleCollapse, closable = false, ...restProps } = props;
19
+ const { width, fullScreen: fullScreenProp = false, children, menuProps, closeIconProps, maxWidth, minWidth, defaultSize = 'max', headerProps, name, destroyOnClose = true, mask = false, classNames, collapsed: propCollapsed, onToggleCollapse, closable = false, ...restProps } = props;
20
20
  const { show: showMenu = true, showExpandButton = true, showClose = true, items, selectedKeys, footer, onClick = () => { }, } = menuProps || {};
21
21
  const { children: headerChildren, ...restOfHeaderProps } = headerProps || {};
22
22
  const { onClose = () => { } } = props;
@@ -99,17 +99,22 @@ export const DrawerDetail = props => {
99
99
  }
100
100
  }
101
101
  }, [collapseDrawer, fullScreen, matchesSmallScreen, maxWidth, minWidth, width]);
102
- const handleToggleDrawerSize = () => {
102
+ const handleToggleDrawerSize = useCallback((updatedCollapsed) => {
103
103
  const localStorageValues = safeParseJson(localStorage.getItem(DRAWER_DETAIL_LOCAL_STORAGE_KEY), {});
104
- toggleCollapseDrawer(!collapseDrawer);
105
- onToggleCollapse?.(!collapseDrawer);
104
+ toggleCollapseDrawer(updatedCollapsed ?? !collapseDrawer);
105
+ onToggleCollapse?.(updatedCollapsed ?? !collapseDrawer);
106
106
  /**
107
107
  * Set local storage last collapsed
108
108
  */
109
109
  if (name) {
110
110
  localStorage.setItem(DRAWER_DETAIL_LOCAL_STORAGE_KEY, JSON.stringify({ ...localStorageValues, [name || '']: !collapseDrawer }));
111
111
  }
112
- };
112
+ }, [collapseDrawer, name, onToggleCollapse, toggleCollapseDrawer]);
113
+ useEffect(() => {
114
+ if (propCollapsed !== undefined) {
115
+ handleToggleDrawerSize(propCollapsed);
116
+ }
117
+ }, [propCollapsed, handleToggleDrawerSize]);
113
118
  return (_jsxs(StyledDrawer, { push: false, closable: closable, width: drawerWidth, motion: {
114
119
  visible: false,
115
120
  motionAppear: false,
@@ -14,6 +14,7 @@ export interface DrawerDetailProps extends Omit<DrawerProps, 'closeIcon' | 'titl
14
14
  classNames?: DrawerProps['classNames'] & {
15
15
  btnToogleSize?: string;
16
16
  };
17
+ collapsed?: boolean;
17
18
  onToggleCollapse?: (collapsed: boolean) => void;
18
19
  }
19
20
  export interface DrawerDetailCloseIconProps extends React.HtmlHTMLAttributes<HTMLDivElement> {
@@ -1,9 +1,11 @@
1
1
  .antsomi-input-dropdown-overlay {
2
- .antsomi-dropdown-menu {
3
- overflow: hidden;
2
+ &.antsomi-dropdown {
3
+ .antsomi-dropdown-menu {
4
+ overflow: hidden;
4
5
 
5
- :hover {
6
- overflow: auto;
6
+ &:hover {
7
+ overflow: auto;
8
+ }
7
9
  }
8
10
  }
9
11
  }
@@ -0,0 +1,2 @@
1
+ import { EditingListProps } from './types';
2
+ export declare const EditingListV2: (props: EditingListProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Libraries
3
+ import { useMemo } from 'react';
4
+ // Components
5
+ import { Suspense } from '../../atoms';
6
+ import { ListItem, LazyComponent } from './components';
7
+ const { Popover } = LazyComponent;
8
+ export const EditingListV2 = (props) => {
9
+ const { isLoading = false, addButtonLabel = 'Add', options = [], selected = [], removable = true, popupPlacement = 'right', className, onChange, } = props;
10
+ const selectedOptions = useMemo(() => options.filter(opt => selected.includes(opt.key)), [selected, options]);
11
+ // const isSelectAll = selectedOptions.length === options.length;
12
+ const handleRemove = (removedKey) => {
13
+ const selectedKeys = selectedOptions.filter(opt => opt.key !== removedKey).map(opt => opt.key);
14
+ onChange?.(selectedKeys);
15
+ };
16
+ return (_jsxs("div", { className: className, children: [_jsx(ListItem, { isLoading: isLoading, selectOptions: selectedOptions, removable: removable, onClickRemove: handleRemove }), !isLoading && (_jsx(Suspense, { children: _jsx(Popover, { placement: popupPlacement, options: options, selected: selected, addButtonLabel: addButtonLabel, onChange: onChange }) }))] }));
17
+ };
@@ -0,0 +1,9 @@
1
+ import { Option } from '../../types';
2
+ type ListProps = {
3
+ isLoading: boolean;
4
+ selectOptions: Option[];
5
+ removable?: boolean;
6
+ onClickRemove?: (key: string) => void;
7
+ };
8
+ export declare const ListItem: (props: ListProps) => import("react/jsx-runtime").JSX.Element | undefined;
9
+ export {};
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Libraries
3
+ import { useState } from 'react';
4
+ import { isEmpty } from 'lodash';
5
+ // Components
6
+ import { Spin, Typography } from '../../../../atoms';
7
+ import { List } from 'antd';
8
+ import { CloseIcon } from '@antscorp/antsomi-ui/es/components/icons';
9
+ // Utils
10
+ import { CLS } from '../../utils';
11
+ // Constants
12
+ import { globalToken } from '@antscorp/antsomi-ui/es/constants';
13
+ export const ListItem = (props) => {
14
+ const { isLoading, selectOptions, onClickRemove, removable } = props;
15
+ const [hover, setHover] = useState('');
16
+ const renderLabel = (label) => {
17
+ if (typeof label === 'string') {
18
+ return _jsx(Typography.Text, { ellipsis: { tooltip: true }, children: label });
19
+ }
20
+ return label;
21
+ };
22
+ const items = selectOptions.map(opt => ({
23
+ className: CLS.ListItem.default,
24
+ key: opt.key,
25
+ label: renderLabel(opt.label),
26
+ }));
27
+ if (isLoading) {
28
+ return _jsx(Spin, { indicatorSize: 24 });
29
+ }
30
+ if (isEmpty(selectOptions)) {
31
+ return;
32
+ }
33
+ return (_jsx(List, { dataSource: items, renderItem: item => (_jsxs(List.Item, { style: {
34
+ display: 'flex',
35
+ alignItems: 'center',
36
+ border: '1px solid #B8CFE6',
37
+ borderRadius: '4px',
38
+ padding: '10px',
39
+ marginBottom: '10px',
40
+ minHeight: '40px',
41
+ }, onMouseEnter: () => setHover(item.key), onMouseLeave: () => setHover(''), children: [item.label, ' ', hover === item.key && removable && (_jsx(CloseIcon, { size: 18, color: globalToken?.bw8, style: { flexShrink: 0, cursor: 'pointer' }, onClick: onClickRemove ? () => onClickRemove(item.key) : undefined }))] })) }));
42
+ };
@@ -0,0 +1 @@
1
+ export { ListItem } from './List';
@@ -0,0 +1 @@
1
+ export { ListItem } from './List';
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ export declare const Popover: import("react").LazyExoticComponent<(props: {
3
+ placement?: "leftTop" | "leftBottom" | "rightTop" | "rightBottom" | "left" | "right" | "bottom" | "top" | "bottomLeft" | "topLeft" | "topRight" | "bottomRight" | undefined;
4
+ options: import("../types").Option[];
5
+ selected: string[];
6
+ addButtonLabel: import("react").ReactNode;
7
+ onChange?: ((selected: string[]) => void) | undefined;
8
+ }) => import("react/jsx-runtime").JSX.Element>;
@@ -0,0 +1,2 @@
1
+ import { lazy } from 'react';
2
+ export const Popover = lazy(() => import('./Popover').then(module => ({ default: module.Popover })));
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ import { Option } from '../../types';
3
+ type PopoverProps = {
4
+ placement?: 'left' | 'right' | 'top' | 'bottom' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom';
5
+ options: Option[];
6
+ selected: string[];
7
+ addButtonLabel: React.ReactNode;
8
+ onChange?: (selected: string[]) => void;
9
+ };
10
+ export declare const Popover: (props: PopoverProps) => import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Components
3
+ import { Button } from '@antscorp/antsomi-ui/es/components/atoms';
4
+ import { PopoverAddField } from '../../../SearchPopover';
5
+ // Icons
6
+ import { AddIcon } from '../../../../icons';
7
+ export const Popover = (props) => {
8
+ const { options, selected, addButtonLabel, onChange, placement } = props;
9
+ return (_jsx(PopoverAddField, { style: { margin: 0 }, fields: options, placement: placement, selected: selected, onApply: onChange, children: _jsxs(Button, { type: "text", children: [_jsx(AddIcon, { size: 14 }), addButtonLabel] }) }));
10
+ };
@@ -0,0 +1 @@
1
+ export { Popover } from './Popover';
@@ -0,0 +1 @@
1
+ export { Popover } from './Popover';
@@ -0,0 +1,3 @@
1
+ export { ListItem } from './List';
2
+ export { Popover } from './Popover';
3
+ export * as LazyComponent from './Loadable';
@@ -0,0 +1,3 @@
1
+ export { ListItem } from './List';
2
+ export { Popover } from './Popover';
3
+ export * as LazyComponent from './Loadable';
@@ -0,0 +1,2 @@
1
+ export { EditingListV2 } from './EditingList';
2
+ export type { EditingListProps } from './types';
@@ -0,0 +1 @@
1
+ export { EditingListV2 } from './EditingList';
@@ -0,0 +1,18 @@
1
+ /// <reference types="react" />
2
+ export type Option = {
3
+ key: string;
4
+ label: React.ReactNode;
5
+ search?: string;
6
+ };
7
+ export type EditingListProps = {
8
+ popupPlacement?: 'left' | 'right' | 'top' | 'bottom' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom';
9
+ addButtonLabel?: string;
10
+ options?: Option[];
11
+ selected?: string[];
12
+ showNum?: boolean;
13
+ className?: string;
14
+ isLoading?: boolean;
15
+ emptyDescription?: string;
16
+ removable?: boolean;
17
+ onChange?: (selected: string[]) => void;
18
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ export declare const componentCls: (className: string) => string;
2
+ export declare const CLS: {
3
+ readonly Root: {
4
+ readonly default: string;
5
+ };
6
+ readonly Title: {
7
+ readonly default: string;
8
+ };
9
+ readonly Search: {
10
+ readonly default: string;
11
+ };
12
+ readonly RemoveButton: {
13
+ readonly default: string;
14
+ };
15
+ readonly AddButton: {
16
+ readonly default: string;
17
+ };
18
+ readonly ListWapper: {
19
+ readonly default: string;
20
+ };
21
+ readonly List: {
22
+ readonly default: string;
23
+ };
24
+ readonly ListItem: {
25
+ readonly default: string;
26
+ };
27
+ };
@@ -0,0 +1,28 @@
1
+ import { antsomiClsx } from '@antscorp/antsomi-ui/es/utils';
2
+ export const componentCls = antsomiClsx('editing-list');
3
+ export const CLS = {
4
+ Root: {
5
+ default: componentCls('root'),
6
+ },
7
+ Title: {
8
+ default: componentCls('title'),
9
+ },
10
+ Search: {
11
+ default: componentCls('search'),
12
+ },
13
+ RemoveButton: {
14
+ default: componentCls('remove-btn'),
15
+ },
16
+ AddButton: {
17
+ default: componentCls('add-btn'),
18
+ },
19
+ ListWapper: {
20
+ default: componentCls('selected-list-wrapper'),
21
+ },
22
+ List: {
23
+ default: componentCls('selected-list'),
24
+ },
25
+ ListItem: {
26
+ default: componentCls('selected-list-item'),
27
+ },
28
+ };
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  // Libraries
3
3
  import { memo, useCallback, useMemo, useState } from 'react';
4
- import { get, keyBy, upperFirst } from 'lodash';
4
+ import { get, has, keyBy, upperFirst } from 'lodash';
5
5
  import { Flex, Form, Select, Tooltip, Typography } from 'antd';
6
6
  // Translations
7
7
  import { translate, translations } from '@antscorp/antsomi-ui/es/locales';
@@ -14,6 +14,7 @@ import { EmptyData } from '../EmptyData';
14
14
  import { Dashboard30Icon, ErrorIcon } from '../../icons';
15
15
  // Constants
16
16
  import { THEME } from '@antscorp/antsomi-ui/es/constants';
17
+ import { TAG_TYPE } from '../TagifyInput';
17
18
  const InputSelectAttribute = (props) => {
18
19
  const { value, errorMsg, label, isErrorTag, sourceOptions = [], mapCodeOptions = {}, onChange, } = props;
19
20
  const [form] = Form.useForm();
@@ -27,7 +28,7 @@ const InputSelectAttribute = (props) => {
27
28
  return [];
28
29
  }, [sourceValue, mapCodeOptions]);
29
30
  const initCodeTitleField = useMemo(() => {
30
- if (sourceValue === 'allocated_code') {
31
+ if (sourceValue === TAG_TYPE.PROMOTION_CODE) {
31
32
  return 'Allocated Code';
32
33
  }
33
34
  return upperFirst(translate(translations._ITEM_NAME_ATTRIBUTE, 'attribute'));
@@ -40,7 +41,8 @@ const InputSelectAttribute = (props) => {
40
41
  const getCodeDefaultBySource = useCallback((source) => get(mapCodeOptions, [source, '0', 'value'], ''), [mapCodeOptions]);
41
42
  const onOpenModal = useCallback(() => {
42
43
  if (value && typeof value !== 'string') {
43
- form.setFieldsValue({ source: value?.source, code: value?.code });
44
+ const isExist = has(mapCodeBySource, [value?.code, 'label']);
45
+ form.setFieldsValue({ source: value?.source, code: isExist ? value?.code : undefined });
44
46
  }
45
47
  else {
46
48
  const source = sourceOptions[0]?.value || '';
@@ -48,7 +50,7 @@ const InputSelectAttribute = (props) => {
48
50
  form.setFieldsValue({ source, code });
49
51
  }
50
52
  setOpenModal(true);
51
- }, [value, form, sourceOptions, getCodeDefaultBySource]);
53
+ }, [value, mapCodeBySource, form, sourceOptions, getCodeDefaultBySource]);
52
54
  const onDeselect = useCallback(() => {
53
55
  onChange({ value: '', valueType: 'input' });
54
56
  }, [onChange]);
@@ -97,7 +99,9 @@ const InputSelectAttribute = (props) => {
97
99
  height: 32,
98
100
  padding: '4px 12px 4px 4px',
99
101
  borderBottom: `1px solid ${errorMsg ? THEME.token?.colorError : THEME.token?.blue1}`,
100
- }, children: [_jsx("div", { style: { width: '100%', cursor: 'pointer' }, onClick: onOpenModal, children: isObjValue && (_jsx(Tag, { isError: isErrorTag, children: isErrorTag ? (_jsxs(Flex, { gap: 5, align: "center", children: ["Unknown", _jsx(Tooltip, { title: "The used dynamic content is removed", children: _jsx(ErrorIcon, { size: 16 }) })] })) : (get(mapCodeBySource, [value?.code, 'label'], value?.code)) })) }), _jsx(Icon, { type: "icon-ants-remove", style: { fontSize: 10, color: '#222', cursor: 'pointer' }, onClick: onDeselect })] }));
102
+ }, children: [_jsx("div", { style: { width: '100%', cursor: 'pointer' }, onClick: onOpenModal, children: isObjValue && (_jsx(Tag, { isError: isErrorTag, children: isErrorTag ? (_jsxs(Flex, { gap: 5, align: "center", children: ["Unknown", _jsx(Tooltip, { title: "The used dynamic content is removed", children: _jsx(ErrorIcon, { size: 16 }) })] })) : (_jsx(Typography.Text, { ellipsis: {
103
+ tooltip: get(mapCodeBySource, [value?.code, 'label'], value?.code),
104
+ }, style: { maxWidth: 150 }, children: get(mapCodeBySource, [value?.code, 'label'], value?.code) })) })) }), _jsx(Icon, { type: "icon-ants-remove", style: { fontSize: 10, color: '#222', cursor: 'pointer' }, onClick: onDeselect })] }));
101
105
  }
102
106
  else {
103
107
  element = (_jsx(StyledSelect, { mode: "multiple", options: [{ value: '', label: 'Or select a field' }], notFoundContent: null, onSelect: onOpenModal, style: { width: '100%', borderTop: 'none', borderLeft: 'none', borderRight: 'none' }, onDeselect: onDeselect, autoClearSearchValue: false, searchValue: typeof value === 'string' ? value : '', onSearch: onChangeInput, status: errorMsg ? 'error' : undefined, placeholder: typeof value === 'string' ? value : translate(translations.inputYourValue.title), "$isPlaceholder": !value, "$isError": !!errorMsg, dropdownStyle: {
@@ -113,11 +113,11 @@ export const PopoverSelect = (props) => {
113
113
  key: opt.key,
114
114
  label: (_jsx(Checkbox, { onChange: e => handleToggleField(opt, e.target.checked), checked: selectedKeys.has(opt.key), children: renderCheckBoxLabel(opt) })),
115
115
  }));
116
- return (_jsx(SearchPopover, { destroyTooltipOnHide: true, ...rest, content: _jsxs(_Fragment, { children: [optionsProp.length > 0 && (_jsxs(StyledAction, { children: [_jsx(Button, { type: "link", size: "small", onClick: () => setShowSelected(current => !current), children: showSelected ? showAllLabel : showSelectedLabel }), selectedKeys.size === options.length ? (_jsx(Button, { type: "link", onClick: handleDeselectAll, children: deselectAllLabel })) : (_jsx(Button, { type: "link", onClick: handleSelectAll, children: selectAllLabel }))] })), filteredOptions.length ? (_jsx(StyledListFieldsWrapper, { "$minHeight": calDefaultListHeightInPopover({
116
+ return (_jsx(SearchPopover, { destroyTooltipOnHide: true, placement: "bottomLeft", ...rest, content: _jsxs(_Fragment, { children: [optionsProp.length > 0 && (_jsxs(StyledAction, { children: [_jsx(Button, { type: "link", size: "small", onClick: () => setShowSelected(current => !current), children: showSelected ? showAllLabel : showSelectedLabel }), selectedKeys.size === options.length ? (_jsx(Button, { type: "link", onClick: handleDeselectAll, children: deselectAllLabel })) : (_jsx(Button, { type: "link", onClick: handleSelectAll, children: selectAllLabel }))] })), filteredOptions.length ? (_jsx(StyledListFieldsWrapper, { "$minHeight": calDefaultListHeightInPopover({
117
117
  listLength: filteredOptions.length,
118
118
  itemSize,
119
119
  itemSpacing,
120
- }), children: _jsx(VirtualizedMenu, { ...menuProps, itemSize: itemSize, items: items }) })) : (_jsx(EmptyData, { showIcon: false, description: t(translations.noData).toString() })), _jsxs(StyledFooter, { children: [_jsx(Button, { onClick: handleCancel, children: "Cancel" }), _jsx(Button, { onClick: handleApply, disabled: applyDisabled, type: "primary", children: "Apply" })] })] }), trigger: ['click'], placement: "bottomLeft", open: open, inputSearchProps: {
120
+ }), children: _jsx(VirtualizedMenu, { ...menuProps, itemSize: itemSize, items: items }) })) : (_jsx(EmptyData, { showIcon: false, description: t(translations.noData).toString() })), _jsxs(StyledFooter, { children: [_jsx(Button, { onClick: handleCancel, children: "Cancel" }), _jsx(Button, { onClick: handleApply, disabled: applyDisabled, type: "primary", children: "Apply" })] })] }), trigger: ['click'], open: open, inputSearchProps: {
121
121
  ...restInputSearchProps,
122
122
  value: search,
123
123
  onAfterChange: handleOnSearch,
@@ -6,6 +6,7 @@ export { Select } from './Select';
6
6
  export { SelectV2 } from './SelectV2';
7
7
  export { DatePicker } from './DatePicker';
8
8
  export { ChatBox, ChatBoxInsight } from './ChatBox';
9
+ export { EditingListV2 } from './EditingListV2';
9
10
  export { PopupDraggable } from './PopupDraggable';
10
11
  export { CaptureScreen } from './CaptureScreen';
11
12
  export { SettingWrapper } from './SettingWrapper';
@@ -6,6 +6,7 @@ export { Select } from './Select';
6
6
  export { SelectV2 } from './SelectV2';
7
7
  export { DatePicker } from './DatePicker';
8
8
  export { ChatBox, ChatBoxInsight } from './ChatBox';
9
+ export { EditingListV2 } from './EditingListV2';
9
10
  export { PopupDraggable } from './PopupDraggable';
10
11
  export { CaptureScreen } from './CaptureScreen';
11
12
  export { SettingWrapper } from './SettingWrapper';
@@ -3,4 +3,5 @@
3
3
  * Asynchronously loads the component for TemplateListing
4
4
  *
5
5
  */
6
+ /// <reference types="react" />
6
7
  export declare const TemplateListing: (props: import("./types").TemplateListingProps<{}>) => JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/antsomi-ui",
3
- "version": "1.3.6-beta.002",
3
+ "version": "1.3.6-beta.20",
4
4
  "description": "An enterprise-class UI design language and React UI library.",
5
5
  "sideEffects": [
6
6
  "dist/*",
@@ -61,7 +61,7 @@
61
61
  "not op_mini all"
62
62
  ],
63
63
  "dependencies": {
64
- "@antscorp/antsomi-locales": "1.0.35",
64
+ "@antscorp/antsomi-locales": "1.0.37",
65
65
  "@ant-design/cssinjs": "^1.6.2",
66
66
  "@antscorp/icons": "0.27.56",
67
67
  "@antscorp/image-editor": "1.0.2",