@antscorp/antsomi-ui 2.0.107 → 2.0.108

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 (67) hide show
  1. package/es/components/molecules/EditingListV2/components/List/List.d.ts +1 -1
  2. package/es/components/molecules/EditingListV2/components/List/List.js +16 -7
  3. package/es/components/molecules/TagifyInput/TagifyInput.js +15 -4
  4. package/es/components/molecules/TagifyInput/constants.d.ts +7 -3
  5. package/es/components/molecules/TagifyInput/constants.js +7 -2
  6. package/es/components/molecules/TagifyInput/patternHandlers.js +34 -1
  7. package/es/components/molecules/TagifyInput/types.d.ts +13 -3
  8. package/es/components/molecules/TagifyInput/utils.d.ts +1 -0
  9. package/es/components/molecules/TagifyInput/utils.js +2 -1
  10. package/es/components/molecules/UnsubscribePreferences/constants.d.ts +27 -0
  11. package/es/components/molecules/UnsubscribePreferences/constants.js +28 -0
  12. package/es/components/molecules/UnsubscribePreferences/index.d.ts +17 -0
  13. package/es/components/molecules/UnsubscribePreferences/index.js +203 -0
  14. package/es/components/molecules/UnsubscribePreferences/styled.d.ts +2 -0
  15. package/es/components/molecules/UnsubscribePreferences/styled.js +11 -0
  16. package/es/components/molecules/UnsubscribePreferences/utils.d.ts +15 -0
  17. package/es/components/molecules/UnsubscribePreferences/utils.js +56 -0
  18. package/es/components/molecules/UnsubscribePreview/components/PreferencesPage/index.d.ts +12 -0
  19. package/es/components/molecules/UnsubscribePreview/components/PreferencesPage/index.js +159 -0
  20. package/es/components/molecules/UnsubscribePreview/components/ResultPage/index.d.ts +13 -0
  21. package/es/components/molecules/UnsubscribePreview/components/ResultPage/index.js +28 -0
  22. package/es/components/molecules/UnsubscribePreview/components/TestAlert/index.d.ts +9 -0
  23. package/es/components/molecules/UnsubscribePreview/components/TestAlert/index.js +18 -0
  24. package/es/components/molecules/UnsubscribePreview/components/UnsubscribedPage/index.d.ts +13 -0
  25. package/es/components/molecules/UnsubscribePreview/components/UnsubscribedPage/index.js +85 -0
  26. package/es/components/molecules/UnsubscribePreview/components/index.d.ts +3 -0
  27. package/es/components/molecules/UnsubscribePreview/components/index.js +3 -0
  28. package/es/components/molecules/UnsubscribePreview/components/styled.d.ts +13 -0
  29. package/es/components/molecules/UnsubscribePreview/components/styled.js +65 -0
  30. package/es/components/molecules/UnsubscribePreview/index.d.ts +10 -0
  31. package/es/components/molecules/UnsubscribePreview/index.js +66 -0
  32. package/es/components/molecules/UnsubscribePreview/styled.d.ts +9 -0
  33. package/es/components/molecules/UnsubscribePreview/styled.js +51 -0
  34. package/es/components/molecules/UnsubscribePreview/type.d.ts +5 -0
  35. package/es/components/molecules/UnsubscribePreview/type.js +1 -0
  36. package/es/components/molecules/UnsubscribePreview/utils.d.ts +9 -0
  37. package/es/components/molecules/UnsubscribePreview/utils.js +27 -0
  38. package/es/components/molecules/UploadImage/index.d.ts +4 -0
  39. package/es/components/molecules/UploadImage/index.js +2 -2
  40. package/es/components/molecules/index.d.ts +4 -0
  41. package/es/components/molecules/index.js +2 -0
  42. package/es/components/organism/PreviewCollections/WhatsappMessage/FooterMessage/index.js +3 -1
  43. package/es/constants/index.d.ts +1 -0
  44. package/es/constants/index.js +1 -0
  45. package/es/constants/queries.d.ts +5 -0
  46. package/es/constants/queries.js +6 -0
  47. package/es/constants/unsubscribe.d.ts +56 -0
  48. package/es/constants/unsubscribe.js +77 -0
  49. package/es/queries/Unsubscribe/index.d.ts +5 -0
  50. package/es/queries/Unsubscribe/index.js +5 -0
  51. package/es/queries/Unsubscribe/useGetUnsubscribeList.d.ts +8 -0
  52. package/es/queries/Unsubscribe/useGetUnsubscribeList.js +18 -0
  53. package/es/queries/Unsubscribe/useGetUnsubscribeListByIdentifier.d.ts +8 -0
  54. package/es/queries/Unsubscribe/useGetUnsubscribeListByIdentifier.js +11 -0
  55. package/es/queries/Unsubscribe/useGetUnsubscribeListPermission.d.ts +8 -0
  56. package/es/queries/Unsubscribe/useGetUnsubscribeListPermission.js +17 -0
  57. package/es/queries/Unsubscribe/useGetUnsubscribePreferences.d.ts +23 -0
  58. package/es/queries/Unsubscribe/useGetUnsubscribePreferences.js +26 -0
  59. package/es/services/Unsubscribe/index.d.ts +41 -0
  60. package/es/services/Unsubscribe/index.js +78 -0
  61. package/es/types/index.d.ts +1 -0
  62. package/es/types/index.js +1 -0
  63. package/es/types/unsubscribe.d.ts +25 -0
  64. package/es/types/unsubscribe.js +1 -0
  65. package/es/utils/common.d.ts +1 -0
  66. package/es/utils/common.js +3 -0
  67. package/package.json +1 -1
@@ -5,5 +5,5 @@ type ListProps = {
5
5
  removable?: boolean;
6
6
  onClickRemove?: (key: string) => void;
7
7
  };
8
- export declare const ListItem: (props: ListProps) => import("react/jsx-runtime").JSX.Element | undefined;
8
+ export declare const ListItem: (props: ListProps) => import("react/jsx-runtime").JSX.Element | null;
9
9
  export {};
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // Libraries
3
- import { useState } from 'react';
4
2
  import { isEmpty } from 'lodash';
3
+ import styled from 'styled-components';
5
4
  // Components
6
5
  import { Spin, Typography, Tooltip } from '../../../../atoms';
7
6
  import { List } from 'antd';
@@ -10,9 +9,19 @@ import { CloseIcon, WarningIcon } from '@antscorp/antsomi-ui/es/components/icons
10
9
  import { CLS } from '../../utils';
11
10
  // Constants
12
11
  import { globalToken } from '@antscorp/antsomi-ui/es/constants';
12
+ const ListItemStyled = styled(List.Item) `
13
+ .close-icon {
14
+ display: none;
15
+ }
16
+
17
+ &:hover .close-icon {
18
+ display: flex;
19
+ }
20
+
21
+ `;
13
22
  export const ListItem = (props) => {
14
23
  const { isLoading, selectOptions, onClickRemove, removable } = props;
15
- const [hover, setHover] = useState('');
24
+ // const [hover, setHover] = useState('');
16
25
  const renderLabel = (label) => {
17
26
  if (typeof label === 'string') {
18
27
  return _jsx(Typography.Text, { ellipsis: { tooltip: true }, children: label });
@@ -29,9 +38,9 @@ export const ListItem = (props) => {
29
38
  return _jsx(Spin, { indicatorSize: 24 });
30
39
  }
31
40
  if (isEmpty(selectOptions)) {
32
- return;
41
+ return null;
33
42
  }
34
- return (_jsx(List, { dataSource: items, renderItem: item => (_jsxs(List.Item, { style: {
43
+ return (_jsx(List, { dataSource: items, renderItem: item => (_jsxs(ListItemStyled, { style: {
35
44
  display: 'flex',
36
45
  alignItems: 'center',
37
46
  border: `1px solid ${item.errorMessage ? '#EF3340' : '#B8CFE6'}`,
@@ -39,10 +48,10 @@ export const ListItem = (props) => {
39
48
  padding: '10px',
40
49
  marginBottom: '10px',
41
50
  minHeight: '40px',
42
- }, onMouseEnter: () => setHover(item.key), onMouseLeave: () => setHover(''), children: [item.label, _jsxs("div", { style: {
51
+ }, children: [item.label, _jsxs("div", { style: {
43
52
  flexShrink: 0,
44
53
  display: 'flex',
45
54
  alignItems: 'center',
46
55
  gap: '5px',
47
- }, children: [item.errorMessage && (_jsx(Tooltip, { title: item.errorMessage, children: _jsx(WarningIcon, { size: 18 }) })), hover === item.key && removable && (_jsx(CloseIcon, { size: 18, color: globalToken?.bw8, style: { cursor: 'pointer' }, onClick: onClickRemove ? () => onClickRemove(item.key) : undefined }))] })] })) }));
56
+ }, children: [item.errorMessage && (_jsx(Tooltip, { title: item.errorMessage, children: _jsx(WarningIcon, { size: 18 }) })), removable && (_jsx(CloseIcon, { size: 18, className: "close-icon", color: globalToken?.bw8, style: { cursor: 'pointer' }, onClick: onClickRemove ? () => onClickRemove(item.key) : undefined }))] })] })) }));
48
57
  };
@@ -20,10 +20,10 @@ import { TagTextArea, TagifyWrapper, WrapperPlaceHolder } from './styled';
20
20
  import { parseTagStringToTagify, convertInputStringToOriginal, emojiManufacturer, getEmojiTag, isPersonalizeTagType, generateTagContent, unescapeString, hasLineBreak, selectRange, isTagClickable, findURLInTextNodes, getAttributesString, isAnchorNodeChildOfElement, isShortLinkTagType, isCaretAtEndOfTextNodeWithNextTag, getCurrentSelectionAndCloneRange, handleEnterWithNextTag, handleTextNodeBackspace, } from './utils';
21
21
  import { acceptablePatternChecking, detectURLRegex, getCachedRegex, getPersonalizeTagInfo, getShortLinkTagInfo, patternHandlers, } from './patternHandlers';
22
22
  // Constants
23
- import { DETECT_LINK, EMOJI, FORCE_SHOW_TOOLTIP, INVALID_TAG, MESSAGE_TAG, NO_VIEW_TAG, PERSONALIZE_PTN, PROMOTION_CODE, READONLY_TAG, REMOVED_TAG, SHORT_LINK, SHORT_LINK_PTN, SHORT_LINK_V2, defaultCssVariables, tagifyDefaultProps, } from './constants';
23
+ import { DETECT_LINK, EMOJI, FORCE_SHOW_TOOLTIP, INVALID_TAG, MESSAGE_TAG, NO_VIEW_TAG, PERSONALIZE_PTN, PROMOTION_CODE, READONLY_TAG, REMOVED_TAG, SHORT_LINK, SHORT_LINK_PTN, SHORT_LINK_V2, UNSUBSCRIBE_WHATSAPP, defaultCssVariables, tagifyDefaultProps, } from './constants';
24
24
  const TagifyInput = forwardRef((props, ref) => {
25
25
  // Props
26
- const { initialValue, escapeHTML, status, readonly, readonlyTag, realtime, disabled, maxLength, maxHeight, minWidth, placeholder, minWidthPlaceholder, isSingleLineText, acceptableTagPattern, mapAttributes, mapErrorAttributes, maxPersonalizeTags, name, children, cssTagifyVariables, onTagClick, onChange, } = props;
26
+ const { initialValue, escapeHTML, status, readonly, readonlyTag, readonlyText, realtime, disabled, maxLength, maxHeight, minWidth, placeholder, minWidthPlaceholder, isSingleLineText, acceptableTagPattern, mapAttributes, mapErrorAttributes, maxPersonalizeTags, name, children, cssTagifyVariables, onTagClick, onChange, } = props;
27
27
  // States
28
28
  const [isLineBreak, setIsLineBreak] = useState(hasLineBreak(initialValue));
29
29
  const [tooltipRefresher, setTooltipRefresher] = useState(1);
@@ -371,7 +371,7 @@ const TagifyInput = forwardRef((props, ref) => {
371
371
  if (newTag && tagifyRef.current) {
372
372
  const { settings, value: currentTags } = tagifyRef.current;
373
373
  const { readonly, maxTags } = settings;
374
- const currentPersonalizeTags = currentTags.filter(tag => ![EMOJI, SHORT_LINK, SHORT_LINK_V2].includes(tag.type));
374
+ const currentPersonalizeTags = currentTags.filter(tag => ![EMOJI, SHORT_LINK, SHORT_LINK_V2, UNSUBSCRIBE_WHATSAPP].includes(tag.type));
375
375
  const currentPersonalizeTagsLength = currentPersonalizeTags.length;
376
376
  // Check readonly
377
377
  if (readonly)
@@ -387,7 +387,7 @@ const TagifyInput = forwardRef((props, ref) => {
387
387
  * Validate the max limit before add new tag
388
388
  * For emoji and short link, it will be passed
389
389
  */
390
- if (![EMOJI, SHORT_LINK, SHORT_LINK_V2].includes(type) &&
390
+ if (![EMOJI, SHORT_LINK, SHORT_LINK_V2, UNSUBSCRIBE_WHATSAPP].includes(type) &&
391
391
  currentPersonalizeTagsLength >= maxTags)
392
392
  return;
393
393
  // Create new tag
@@ -722,6 +722,17 @@ const TagifyInput = forwardRef((props, ref) => {
722
722
  });
723
723
  }
724
724
  }, [maxLength, customizeTag]);
725
+ useEffect(() => {
726
+ if (!tagifyRef.current)
727
+ return;
728
+ const inputEl = tagifyRef.current.DOM.input;
729
+ if (readonlyText) {
730
+ inputEl.setAttribute('contenteditable', 'false');
731
+ }
732
+ else {
733
+ inputEl.setAttribute('contenteditable', 'true');
734
+ }
735
+ }, [readonlyText]);
725
736
  const onTagifyWrapperClick = useCallback(event => {
726
737
  event.preventDefault();
727
738
  event.stopPropagation();
@@ -38,9 +38,11 @@ export declare const PATTERN_CACHE_TYPE: {
38
38
  readonly LINE_EMOJI_PTN: "line_emoji_pattern";
39
39
  readonly PERSONALIZE_PTN: "personalize_pattern";
40
40
  readonly VIBER_EMOJI_PTN: "viber_emoji_pattern";
41
+ readonly UNSUBSCRIBE_WHATSAPP_PTN: "unsubscribe_whatsapp_pattern";
42
+ readonly UNSUBSCRIBE_PTN: "unsubscribe_pattern";
41
43
  };
42
- export declare const SHORT_LINK_PTN: "shortlink_pattern", SHORT_LINK_INDIVIDUAL_PTN: "shortlink_individual_pattern", SHORT_LINK_GENERAL_PTN: "shortlink_general_pattern", SHORT_LINK_V2_INDIVIDUAL_PTN: "shortlink_v2_individual_pattern", SHORT_LINK_V2_GENERAL_PTN: "shortlink_v2_general_pattern", LINE_EMOJI_PTN: "line_emoji_pattern", PERSONALIZE_PTN: "personalize_pattern", VIBER_EMOJI_PTN: "viber_emoji_pattern";
43
- export declare const DEFAULT_ACCEPT_TAGS: ("shortlink_pattern" | "line_emoji_pattern" | "personalize_pattern" | "viber_emoji_pattern")[];
44
+ export declare const SHORT_LINK_PTN: "shortlink_pattern", SHORT_LINK_INDIVIDUAL_PTN: "shortlink_individual_pattern", SHORT_LINK_GENERAL_PTN: "shortlink_general_pattern", SHORT_LINK_V2_INDIVIDUAL_PTN: "shortlink_v2_individual_pattern", SHORT_LINK_V2_GENERAL_PTN: "shortlink_v2_general_pattern", LINE_EMOJI_PTN: "line_emoji_pattern", PERSONALIZE_PTN: "personalize_pattern", VIBER_EMOJI_PTN: "viber_emoji_pattern", UNSUBSCRIBE_WHATSAPP_PTN: "unsubscribe_whatsapp_pattern", UNSUBSCRIBE_PTN: "unsubscribe_pattern";
45
+ export declare const DEFAULT_ACCEPT_TAGS: ("shortlink_pattern" | "line_emoji_pattern" | "personalize_pattern" | "viber_emoji_pattern" | "unsubscribe_pattern")[];
44
46
  export declare const tagifyDefaultProps: TagifyInputProps;
45
47
  export declare const TAG_TYPE: {
46
48
  readonly CUSTOMER: "customer";
@@ -57,8 +59,9 @@ export declare const TAG_TYPE: {
57
59
  readonly SHORT_LINK_V2: "shortlink_v2";
58
60
  readonly DETECT_LINK: "detect_link";
59
61
  readonly CONTENT_SOURCE_GROUP: "groups";
62
+ readonly UNSUBSCRIBE_WHATSAPP: "unsubscribe_whatsapp";
60
63
  };
61
- export declare const CUSTOMER: "customer", VISITOR: "visitor", EVENT: "event", JOURNEY: "story", CAMPAIGN: "campaign", VARIANT: "variant", PROMOTION_CODE: "promotion_code", CUSTOM_FN: "custom", EMOJI: "emoji", DETECT_LINK: "detect_link", SHORT_LINK: "shortlink", SHORT_LINK_V2: "shortlink_v2", OBJECT_WIDGET: "objectWidget", CONTENT_SOURCE_GROUP: "groups";
64
+ export declare const CUSTOMER: "customer", VISITOR: "visitor", EVENT: "event", JOURNEY: "story", CAMPAIGN: "campaign", VARIANT: "variant", PROMOTION_CODE: "promotion_code", CUSTOM_FN: "custom", EMOJI: "emoji", DETECT_LINK: "detect_link", SHORT_LINK: "shortlink", SHORT_LINK_V2: "shortlink_v2", OBJECT_WIDGET: "objectWidget", CONTENT_SOURCE_GROUP: "groups", UNSUBSCRIBE_WHATSAPP: "unsubscribe_whatsapp";
62
65
  export declare const SHORT_LINK_TYPE: {
63
66
  readonly INDIVIDUAL: "shortlink";
64
67
  readonly GENERAL: "shortlink_static";
@@ -88,6 +91,7 @@ export declare const TAG_COLOR: {
88
91
  readonly custom: "#bbefbe";
89
92
  readonly groups: "#ffdd9f";
90
93
  readonly emoji: "transparent";
94
+ readonly unsubscribe_whatsapp: "#cafedd";
91
95
  };
92
96
  export declare const EMOJI_COLLECTIONS: {
93
97
  readonly COMMON: "common";
@@ -39,13 +39,16 @@ export const PATTERN_CACHE_TYPE = {
39
39
  LINE_EMOJI_PTN: 'line_emoji_pattern',
40
40
  PERSONALIZE_PTN: 'personalize_pattern',
41
41
  VIBER_EMOJI_PTN: 'viber_emoji_pattern',
42
+ UNSUBSCRIBE_WHATSAPP_PTN: 'unsubscribe_whatsapp_pattern',
43
+ UNSUBSCRIBE_PTN: 'unsubscribe_pattern',
42
44
  };
43
- export const { SHORT_LINK_PTN, SHORT_LINK_INDIVIDUAL_PTN, SHORT_LINK_GENERAL_PTN, SHORT_LINK_V2_INDIVIDUAL_PTN, SHORT_LINK_V2_GENERAL_PTN, LINE_EMOJI_PTN, PERSONALIZE_PTN, VIBER_EMOJI_PTN, } = PATTERN_CACHE_TYPE;
45
+ export const { SHORT_LINK_PTN, SHORT_LINK_INDIVIDUAL_PTN, SHORT_LINK_GENERAL_PTN, SHORT_LINK_V2_INDIVIDUAL_PTN, SHORT_LINK_V2_GENERAL_PTN, LINE_EMOJI_PTN, PERSONALIZE_PTN, VIBER_EMOJI_PTN, UNSUBSCRIBE_WHATSAPP_PTN, UNSUBSCRIBE_PTN, } = PATTERN_CACHE_TYPE;
44
46
  export const DEFAULT_ACCEPT_TAGS = [
45
47
  SHORT_LINK_PTN,
46
48
  PERSONALIZE_PTN,
47
49
  VIBER_EMOJI_PTN,
48
50
  LINE_EMOJI_PTN,
51
+ UNSUBSCRIBE_PTN,
49
52
  ];
50
53
  export const tagifyDefaultProps = {
51
54
  initialValue: '',
@@ -72,8 +75,9 @@ export const TAG_TYPE = {
72
75
  SHORT_LINK_V2: 'shortlink_v2',
73
76
  DETECT_LINK: 'detect_link',
74
77
  CONTENT_SOURCE_GROUP: 'groups',
78
+ UNSUBSCRIBE_WHATSAPP: 'unsubscribe_whatsapp',
75
79
  };
76
- export const { CUSTOMER, VISITOR, EVENT, JOURNEY, CAMPAIGN, VARIANT, PROMOTION_CODE, CUSTOM_FN, EMOJI, DETECT_LINK, SHORT_LINK, SHORT_LINK_V2, OBJECT_WIDGET, CONTENT_SOURCE_GROUP, } = TAG_TYPE;
80
+ export const { CUSTOMER, VISITOR, EVENT, JOURNEY, CAMPAIGN, VARIANT, PROMOTION_CODE, CUSTOM_FN, EMOJI, DETECT_LINK, SHORT_LINK, SHORT_LINK_V2, OBJECT_WIDGET, CONTENT_SOURCE_GROUP, UNSUBSCRIBE_WHATSAPP, } = TAG_TYPE;
77
81
  export const SHORT_LINK_TYPE = {
78
82
  INDIVIDUAL: 'shortlink', // Individual link
79
83
  GENERAL: 'shortlink_static', // General link
@@ -103,6 +107,7 @@ export const TAG_COLOR = {
103
107
  [CUSTOM_FN]: '#bbefbe',
104
108
  [CONTENT_SOURCE_GROUP]: '#ffdd9f',
105
109
  [EMOJI]: 'transparent',
110
+ [UNSUBSCRIBE_WHATSAPP]: '#cafedd',
106
111
  };
107
112
  export const EMOJI_COLLECTIONS = {
108
113
  COMMON: 'common',
@@ -9,7 +9,7 @@ import { isViberEmoji } from './iconsViber';
9
9
  import { random } from '@antscorp/antsomi-ui/es/utils';
10
10
  import { containsTagType } from './utils';
11
11
  // Constants
12
- import { CONTENT_SOURCE_GROUP, EMOJI, EMOJI_COLLECTIONS, LINE_EMOJI_PTN, PERSONALIZE_PTN, PREFIX_PATTERN_LINE_MESSAGE, PROMOTION_CODE, SHORT_LINK, SHORT_LINK_GENERAL_PTN, SHORT_LINK_INDIVIDUAL_PTN, SHORT_LINK_PTN, SHORT_LINK_TYPE, SHORT_LINK_V2, SHORT_LINK_V2_GENERAL_PTN, SHORT_LINK_V2_INDIVIDUAL_PTN, VIBER_EMOJI_PTN, } from './constants';
12
+ import { CONTENT_SOURCE_GROUP, EMOJI, EMOJI_COLLECTIONS, LINE_EMOJI_PTN, PERSONALIZE_PTN, PREFIX_PATTERN_LINE_MESSAGE, PROMOTION_CODE, SHORT_LINK, SHORT_LINK_GENERAL_PTN, SHORT_LINK_INDIVIDUAL_PTN, SHORT_LINK_PTN, SHORT_LINK_TYPE, SHORT_LINK_V2, SHORT_LINK_V2_GENERAL_PTN, SHORT_LINK_V2_INDIVIDUAL_PTN, VIBER_EMOJI_PTN, UNSUBSCRIBE_WHATSAPP, UNSUBSCRIBE_WHATSAPP_PTN, UNSUBSCRIBE_PTN, } from './constants';
13
13
  /*
14
14
  * Usage to cache compiled regular expressions:
15
15
  * const regex = getCachedRegex(pattern, flags);
@@ -594,6 +594,30 @@ const handleShortlinkV2GeneralPattern = match => {
594
594
  const tag = createTagPattern(tagData);
595
595
  return { isValid, tag, tagData };
596
596
  };
597
+ /**
598
+ * Function to handle whatsapp#public/unsubscribe/${id} pattern
599
+ */
600
+ const handleUnsubscribeWhatsappPattern = match => {
601
+ const [fullMatch, id] = match;
602
+ const isValid = Boolean(id && id.trim().length > 0);
603
+ if (!isValid) {
604
+ console.error(`Invalid WhatsApp unsubscribe pattern: fullMatch:: ${fullMatch}`);
605
+ return {
606
+ isValid,
607
+ tag: '[[Invalid WhatsApp unsubscribe]]',
608
+ tagData: undefined,
609
+ };
610
+ }
611
+ const label = `whatsapp${fullMatch}`;
612
+ const tagData = {
613
+ type: UNSUBSCRIBE_WHATSAPP,
614
+ label,
615
+ value: fullMatch,
616
+ id,
617
+ };
618
+ const tag = createTagPattern(tagData);
619
+ return { isValid, tag, tagData };
620
+ };
597
621
  // Map of regex patterns to their respective wrapped handlers
598
622
  export const patternHandlers = {
599
623
  /*
@@ -653,4 +677,13 @@ export const patternHandlers = {
653
677
  acceptablePattern: VIBER_EMOJI_PTN,
654
678
  handler: errorWrapper(handleViberPattern),
655
679
  },
680
+ /**
681
+ * NOTE: WhatsApp unsubscribe patterns
682
+ */
683
+ [UNSUBSCRIBE_WHATSAPP_PTN]: {
684
+ pattern: '#public\\/unsubscribe\\/([A-Za-z0-9_-]+)(?:\\?(?=.*\\btype=whatsapp\\b).*)',
685
+ name: UNSUBSCRIBE_WHATSAPP_PTN, // Used to cache the regex, please keep the name unique for each pattern
686
+ acceptablePattern: UNSUBSCRIBE_PTN,
687
+ handler: errorWrapper(handleUnsubscribeWhatsappPattern),
688
+ },
656
689
  };
@@ -125,6 +125,10 @@ export interface TagifyInputProps {
125
125
  * @default () => {}
126
126
  */
127
127
  onChange: (inputValue: string) => void;
128
+ /**
129
+ * Defines whether the input text is read but not the whole tags.
130
+ */
131
+ readonlyText?: boolean;
128
132
  }
129
133
  export interface TagifyInputRef {
130
134
  onAddNewTag: (newTag: TagDataCustomize | string) => void;
@@ -135,8 +139,8 @@ export type EmojiCollection = (typeof EMOJI_COLLECTIONS)[keyof typeof EMOJI_COLL
135
139
  export type TagType = (typeof TAG_TYPE)[keyof typeof TAG_TYPE];
136
140
  export type ShortLinkType = (typeof SHORT_LINK_TYPE)[keyof typeof SHORT_LINK_TYPE];
137
141
  export type PatternCacheType = (typeof PATTERN_CACHE_TYPE)[keyof typeof PATTERN_CACHE_TYPE];
138
- export type PatterTagName = Exclude<PatternCacheType, 'shortlink_pattern'>;
139
- export type AcceptablePattern = Exclude<PatternCacheType, 'shortlink_individual_pattern' | 'shortlink_general_pattern'>;
142
+ export type PatterTagName = Exclude<PatternCacheType, 'shortlink_pattern' | 'unsubscribe_pattern'>;
143
+ export type AcceptablePattern = Exclude<PatternCacheType, 'shortlink_individual_pattern' | 'shortlink_general_pattern' | 'unsubscribe_whatsapp_pattern'>;
140
144
  export interface TagDataText extends TagData {
141
145
  value: string;
142
146
  label: string;
@@ -152,7 +156,13 @@ export interface TagDataShortLink extends Omit<TagDataText, 'type'> {
152
156
  type: Extract<TagType, 'shortlink' | 'shortlink_v2'>;
153
157
  shortlinkType: ShortLinkType;
154
158
  }
155
- export type TagDataCustomize = TagDataEmoji | TagDataText | TagDataShortLink;
159
+ export interface TagDataUnsubscribe extends Omit<TagDataText, 'type'> {
160
+ value: string;
161
+ label: string;
162
+ id: string;
163
+ type: Extract<TagType, 'unsubscribe_whatsapp'>;
164
+ }
165
+ export type TagDataCustomize = TagDataEmoji | TagDataText | TagDataShortLink | TagDataUnsubscribe;
156
166
  export interface EmojiTag {
157
167
  src?: string;
158
168
  emoji: string;
@@ -47,6 +47,7 @@ export declare const emojiManufacturer: (text: string, collectionType: EmojiColl
47
47
  export declare const getEmojiTag: ({ src, emoji, code }: EmojiTag) => string;
48
48
  export declare const isPersonalizeTagType: (type: TagType) => boolean;
49
49
  export declare const isShortLinkTagType: (type: TagType) => boolean;
50
+ export declare const isUnsubscribeTagType: (type: TagType) => boolean;
50
51
  export declare const generateTagContent: (params: {
51
52
  tagData: TagDataCustomize;
52
53
  content: string;
@@ -1,7 +1,7 @@
1
1
  // Libraries
2
2
  import stringReplaceToArray from 'string-replace-to-array';
3
3
  // Constants
4
- import { EMOJI_COLLECTIONS, PREFIX_PATTERN_LINE_MESSAGE, READONLY_TAG, SHORT_LINK_V2, TAG_TYPE, } from './constants';
4
+ import { EMOJI_COLLECTIONS, PREFIX_PATTERN_LINE_MESSAGE, READONLY_TAG, SHORT_LINK_V2, TAG_TYPE, UNSUBSCRIBE_WHATSAPP, } from './constants';
5
5
  import { iconsViber } from './iconsViber';
6
6
  // Utils
7
7
  import { acceptablePatternChecking, detectURLRegex, getCachedRegex, patternHandlers, tagRegexStringPattern, } from './patternHandlers';
@@ -402,6 +402,7 @@ export const isPersonalizeTagType = (type) => [
402
402
  CONTENT_SOURCE_GROUP,
403
403
  ].includes(type);
404
404
  export const isShortLinkTagType = (type) => [SHORT_LINK_V2].includes(type);
405
+ export const isUnsubscribeTagType = (type) => [UNSUBSCRIBE_WHATSAPP].includes(type);
405
406
  export const generateTagContent = (params) => {
406
407
  const { tagData, content } = params;
407
408
  let dataAttrsString = '';
@@ -0,0 +1,27 @@
1
+ export declare const UNSUBSCRIBE_LIST_TYPE: {
2
+ readonly EMAIL: "email";
3
+ readonly PHONE: "phone";
4
+ readonly WHATSAPP: "whatsapp";
5
+ };
6
+ export declare const UNSUBSCRIBE_LIST_STATUS: {
7
+ ACTIVE: string;
8
+ INACTIVE: string;
9
+ };
10
+ export declare const UNSUBSCRIBE_LIST_MESSAGE_ERRORS: {
11
+ UNAUTHORIZED: string;
12
+ DISABLED: string;
13
+ };
14
+ export declare const CUSTOM_SEGMENT: {
15
+ value: string;
16
+ label: string;
17
+ };
18
+ export declare const LANDING_PAGE_TYPE: {
19
+ CUSTOM_PAGE: {
20
+ value: string;
21
+ label: string;
22
+ };
23
+ SPECIFIC_LINK: {
24
+ value: string;
25
+ label: string;
26
+ };
27
+ };
@@ -0,0 +1,28 @@
1
+ import { translate, translations } from '@antscorp/antsomi-locales';
2
+ export const UNSUBSCRIBE_LIST_TYPE = {
3
+ EMAIL: 'email',
4
+ PHONE: 'phone',
5
+ WHATSAPP: 'whatsapp',
6
+ };
7
+ export const UNSUBSCRIBE_LIST_STATUS = {
8
+ ACTIVE: '1',
9
+ INACTIVE: '2',
10
+ };
11
+ export const UNSUBSCRIBE_LIST_MESSAGE_ERRORS = {
12
+ UNAUTHORIZED: translate(translations._NOTI_SEGMENT_NO_PERMISSION, 'You do not have permission for this object'),
13
+ DISABLED: 'This unsubscribed list is disabled',
14
+ };
15
+ export const CUSTOM_SEGMENT = {
16
+ value: 'customLink',
17
+ label: translate('', 'Custom link'),
18
+ };
19
+ export const LANDING_PAGE_TYPE = {
20
+ CUSTOM_PAGE: {
21
+ value: 'custom-page',
22
+ label: translate(translations._TITLE_UNSUBSCRIBE_CUSTOM_PAGE, 'Custom page'),
23
+ },
24
+ SPECIFIC_LINK: {
25
+ value: 'specific-link',
26
+ label: translate(translations._TITLE_UNSUBSCRIBE_SPECIFIC_LINK, 'Specific link'),
27
+ },
28
+ };
@@ -0,0 +1,17 @@
1
+ import { TUnsubscribeSettings, TUnsubscribeType } from '@antscorp/antsomi-ui/es/types';
2
+ import { TUnsubscribePayloadInfo } from '@antscorp/antsomi-ui/es/services/Unsubscribe';
3
+ export type TUnsubscribePreferencesProps = {
4
+ type: TUnsubscribeType;
5
+ apiConfig: TUnsubscribePayloadInfo;
6
+ unsubscribePreferences: TUnsubscribeSettings['unsubscribePreferences'];
7
+ hideLandingPageType?: boolean;
8
+ fieldPath?: string;
9
+ required?: string[];
10
+ onChange: (unsubscribePreferences: Record<string, any>, payload: TUpdateUnsubscribeSetting[]) => void;
11
+ };
12
+ type TUpdateUnsubscribeSetting = {
13
+ fieldPath: string;
14
+ data: string;
15
+ };
16
+ export declare const UnsubscribePreferences: (props: TUnsubscribePreferencesProps) => import("react/jsx-runtime").JSX.Element;
17
+ export {};
@@ -0,0 +1,203 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // Libraries
3
+ import { useMemo } from 'react';
4
+ import { translate, translations } from '@antscorp/antsomi-locales';
5
+ // Queries
6
+ import { useGetUnsubscribeListPermission } from '@antscorp/antsomi-ui/es/queries/Unsubscribe';
7
+ // Constants
8
+ import { CUSTOM_SEGMENT, LANDING_PAGE_TYPE, UNSUBSCRIBE_LIST_MESSAGE_ERRORS } from './constants';
9
+ import { GLOBAL_UNSUBSCRIBED_LIST, GLOBAL_UNSUBSCRIBED_WHATSAPP, } from '@antscorp/antsomi-ui/es/constants';
10
+ // Utils
11
+ import { buildOptionPreferencesList, buildOptionUnsubscribedList, checkUnsubscribeList, unsubscribeListNotExist, } from './utils';
12
+ import { compareStrings, handleError } from '@antscorp/antsomi-ui/es/utils';
13
+ // Components
14
+ import { EditingListV2, Input, RadioGroup, SelectV2, SettingWrapper, Space, Spin, Switch, UploadImage, } from '../../index';
15
+ import { TextStyled } from './styled';
16
+ const PATH = 'antsomi-ui/src/components/molecules/UnsubscribePreferences/index.tsx';
17
+ export const UnsubscribePreferences = (props) => {
18
+ const { type, apiConfig, unsubscribePreferences, hideLandingPageType, fieldPath = 'settings.unsubscribePreferences', required = ['unsubscribeListId', 'title', 'description'], onChange, } = props;
19
+ const { segmentId, logo, title, description, customLink, haveResubscribeButton, unsubscribeListId, } = unsubscribePreferences || {};
20
+ const preferenceListIds = useMemo(() => Array.isArray(unsubscribePreferences.preferenceListIds)
21
+ ? [...unsubscribePreferences.preferenceListIds]
22
+ : unsubscribePreferences.preferenceListIds
23
+ ? [`${unsubscribePreferences.preferenceListIds}`]
24
+ : [], [unsubscribePreferences.preferenceListIds]);
25
+ const landingPageType = unsubscribePreferences?.landingPageType ||
26
+ (segmentId === CUSTOM_SEGMENT.value
27
+ ? LANDING_PAGE_TYPE.SPECIFIC_LINK.value
28
+ : LANDING_PAGE_TYPE.CUSTOM_PAGE.value);
29
+ const isGlobalUnsubscribedList = [GLOBAL_UNSUBSCRIBED_LIST, GLOBAL_UNSUBSCRIBED_WHATSAPP].some(({ list_id }) => compareStrings(list_id, unsubscribeListId) === 0);
30
+ const { data: unsubscribeDataPermission, isFetching: isLoadingUnsubscribeListPermission } = useGetUnsubscribeListPermission({
31
+ args: {
32
+ data: {
33
+ type,
34
+ portalId: apiConfig.portalId || 0,
35
+ },
36
+ },
37
+ options: {
38
+ enabled: !!apiConfig.portalId,
39
+ },
40
+ }, apiConfig);
41
+ // Memoized
42
+ const unsubscribeList = useMemo(() => {
43
+ if (isLoadingUnsubscribeListPermission)
44
+ return [];
45
+ return unsubscribeDataPermission?.entries[0] || [];
46
+ }, [unsubscribeDataPermission, isLoadingUnsubscribeListPermission]);
47
+ const memoizedUnsubscribedLists = useMemo(() => buildOptionUnsubscribedList(unsubscribeList || [], unsubscribeListId?.toString() || [])?.map(({ list_id, list_name }) => ({
48
+ value: list_id,
49
+ label: list_name,
50
+ })), [unsubscribeList, unsubscribeListId]);
51
+ const memoizedPreferencesLists = useMemo(() => {
52
+ const list = buildOptionPreferencesList(unsubscribeList || [], unsubscribeListId?.toString() || []);
53
+ return ([
54
+ ...(preferenceListIds?.map(key => {
55
+ const select = list?.find(opt => `${opt.key}` === `${key}`);
56
+ if (!select) {
57
+ return {
58
+ value: key,
59
+ label: `[ID - ${key}]`,
60
+ key,
61
+ errorMessage: UNSUBSCRIBE_LIST_MESSAGE_ERRORS.UNAUTHORIZED,
62
+ };
63
+ }
64
+ return null;
65
+ }) || []),
66
+ ...(list || []),
67
+ ]?.filter((item) => Boolean(item)) || []);
68
+ }, [unsubscribeList, unsubscribeListId, preferenceListIds]);
69
+ const { errorMessage: unsubscribeListErrorMessage } = checkUnsubscribeList({
70
+ listUnsubscribe: unsubscribeList || [],
71
+ unsubscribeId: `${unsubscribeListId}`,
72
+ });
73
+ const handleChange = (key, value) => {
74
+ try {
75
+ switch (key) {
76
+ case 'unsubscribeListId': {
77
+ const newPreferenceListIds = buildOptionPreferencesList(unsubscribeList || [], value || [])
78
+ ?.filter(each => !each.errorMessage)
79
+ .map(item => item.value);
80
+ onChange({
81
+ ...unsubscribePreferences,
82
+ unsubscribeListId: value,
83
+ preferenceListIds: newPreferenceListIds,
84
+ }, [
85
+ {
86
+ fieldPath: `${fieldPath}.unsubscribeListId`,
87
+ data: value,
88
+ },
89
+ {
90
+ fieldPath: `${fieldPath}.preferenceListIds`,
91
+ data: newPreferenceListIds,
92
+ },
93
+ ]);
94
+ break;
95
+ }
96
+ case 'landingPageType': {
97
+ onChange({
98
+ ...unsubscribePreferences,
99
+ landingPageType: value,
100
+ }, [
101
+ {
102
+ fieldPath: `${fieldPath}.landingPageType`,
103
+ data: value,
104
+ },
105
+ ]);
106
+ break;
107
+ }
108
+ case 'customLink': {
109
+ onChange({
110
+ ...unsubscribePreferences,
111
+ customLink: value,
112
+ }, [
113
+ {
114
+ fieldPath: `${fieldPath}.customLink`,
115
+ data: value,
116
+ },
117
+ ]);
118
+ break;
119
+ }
120
+ case 'logo': {
121
+ onChange({
122
+ ...unsubscribePreferences,
123
+ logo: value,
124
+ }, [
125
+ {
126
+ fieldPath: `${fieldPath}.logo`,
127
+ data: value,
128
+ },
129
+ ]);
130
+ break;
131
+ }
132
+ case 'title': {
133
+ onChange({
134
+ ...unsubscribePreferences,
135
+ title: value,
136
+ }, [
137
+ {
138
+ fieldPath: `${fieldPath}.title`,
139
+ data: value,
140
+ },
141
+ ]);
142
+ break;
143
+ }
144
+ case 'description': {
145
+ onChange({
146
+ ...unsubscribePreferences,
147
+ description: value,
148
+ }, [
149
+ {
150
+ fieldPath: `${fieldPath}.description`,
151
+ data: value,
152
+ },
153
+ ]);
154
+ break;
155
+ }
156
+ case 'haveResubscribeButton': {
157
+ onChange({
158
+ ...unsubscribePreferences,
159
+ haveResubscribeButton: value,
160
+ }, [
161
+ {
162
+ fieldPath: `${fieldPath}.haveResubscribeButton`,
163
+ data: value,
164
+ },
165
+ ]);
166
+ break;
167
+ }
168
+ case 'preferenceListIds': {
169
+ onChange({
170
+ ...unsubscribePreferences,
171
+ preferenceListIds: value,
172
+ }, [
173
+ {
174
+ fieldPath: `${fieldPath}.preferenceListIds`,
175
+ data: value,
176
+ },
177
+ ]);
178
+ break;
179
+ }
180
+ default:
181
+ break;
182
+ }
183
+ }
184
+ catch (error) {
185
+ handleError(error, {
186
+ path: PATH,
187
+ name: 'handleChange',
188
+ args: { key, value },
189
+ });
190
+ }
191
+ };
192
+ return (_jsxs(Space, { className: "unsubscribe-preferences", size: 20, direction: "vertical", children: [_jsx(SelectV2, { showSearch: true, label: _jsx(TextStyled, { color: "#666666", required: required.includes('unsubscribeListId'), children: translate(translations._TITLE_UNSUBSCRIBED_LIST, 'Unsubscribed list') }), placeholder: translate('', 'Select Unsubscribed List'), loading: isLoadingUnsubscribeListPermission, options: memoizedUnsubscribedLists, value: unsubscribeListNotExist(unsubscribeList, unsubscribeListId?.toString()), errorMsg: unsubscribeListErrorMessage, status: !isLoadingUnsubscribeListPermission && unsubscribeListErrorMessage !== '' ? 'error' : '', onChange: value => {
193
+ handleChange('unsubscribeListId', value);
194
+ } }), !hideLandingPageType && (_jsx(SettingWrapper, { label: translate(translations._TITLE_UNSUBSCRIBE_LANDING_PAGE, 'Landing page'), children: _jsx(RadioGroup, { value: landingPageType, options: Object.values(LANDING_PAGE_TYPE), onChange: e => {
195
+ handleChange('landingPageType', e.target.value);
196
+ } }) })), landingPageType === LANDING_PAGE_TYPE.SPECIFIC_LINK.value ? (_jsxs(Space, { size: 5, direction: "vertical", children: [_jsx(TextStyled, { color: "#666666", required: required.includes('customLink'), children: translate(translations._TITLE_UNSUBSCRIBE_PAGE_URL, 'Page URL') }), _jsx(Input, { value: customLink, placeholder: translate('_', 'Enter text here...'), onAfterChange: value => handleChange('customLink', value) })] })) : (_jsxs(_Fragment, { children: [_jsx(UploadImage, { domainMedia: `${apiConfig.url}`, slug: "", paramConfigs: apiConfig, title: translate('_', 'Logo'), disableRemove: true, isInputMode: false, selectedImage: {
197
+ url: logo,
198
+ }, onChangeImage: image => {
199
+ handleChange('logo', image.url);
200
+ }, onRemoveImage: () => {
201
+ handleChange('logo', '');
202
+ }, required: required.includes('logo') }), _jsxs(Space, { size: 5, direction: "vertical", children: [_jsx(TextStyled, { color: "#666666", required: required.includes('title'), children: translate(translations._TITLE_TICKET_TITLE, 'Title') }), _jsx(Input, { value: title, placeholder: translate('_', 'Enter text here...'), maxLength: 70, onAfterChange: value => handleChange('title', value) })] }), _jsxs(Space, { size: 5, direction: "vertical", children: [_jsx(TextStyled, { color: "#666666", required: required.includes('description'), children: translate(translations._TITL_DESCRIPTION, 'Description') }), _jsx(Input, { value: description, placeholder: translate('_', 'Enter text here...'), maxLength: 255, onAfterChange: value => handleChange('description', value) })] }), isGlobalUnsubscribedList ? (_jsxs(Space, { size: 5, direction: "horizontal", style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx(TextStyled, { color: "#666666", required: required.includes('haveResubscribeButton'), children: translate(`${translations._TITLE_DISPLAY_RESUBSCRIBE_BUTTON}?`, 'Display Resubscribe button?') }), _jsx(Switch, { checked: haveResubscribeButton || false, onChange: checked => handleChange('haveResubscribeButton', checked) })] })) : (_jsxs(Space, { size: 5, direction: "vertical", children: [_jsx(TextStyled, { color: "#666666", required: required.includes('preferenceListIds'), children: translate(translations._TITLE_PREFERENCES, 'Preferences') }), isLoadingUnsubscribeListPermission ? (_jsx(Spin, { spinning: true, className: "ants-flex ants-justify-center", size: "small" })) : (_jsx(EditingListV2, { className: "ants-mt-2", addButtonLabel: translate(translations._ACT_ADD_UNSUBSCRIBED_LIST, 'Add unsubscribed list'), options: memoizedPreferencesLists, selected: preferenceListIds, onChange: value => handleChange('preferenceListIds', value) }))] }))] }))] }));
203
+ };
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare const TextStyled: import("styled-components").StyledComponent<import("react").FC<import("../../atoms/Text").TextProps>, any, {}, never>;
@@ -0,0 +1,11 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { Text } from '../../index';
3
+ export const TextStyled = styled(Text) `
4
+ ${({ required }) => required &&
5
+ css `
6
+ &::after {
7
+ content: ' *';
8
+ color: #ef3340;
9
+ }
10
+ `}
11
+ `;
@@ -0,0 +1,15 @@
1
+ import { TUnsubscribeList } from '@antscorp/antsomi-ui/es/types';
2
+ export declare const buildOptionUnsubscribedList: (list: TUnsubscribeList[], selected: any) => TUnsubscribeList[];
3
+ export declare const unsubscribeListNotExist: (options: any, value: any) => any;
4
+ export declare const checkUnsubscribeList: ({ listUnsubscribe, unsubscribeId, }: {
5
+ listUnsubscribe?: any[];
6
+ unsubscribeId?: string;
7
+ }) => {
8
+ errorMessage: string;
9
+ };
10
+ export declare const buildOptionPreferencesList: (list: TUnsubscribeList[], selected: any) => {
11
+ value: string;
12
+ label: string;
13
+ key: string;
14
+ errorMessage: any;
15
+ }[];