@antscorp/antsomi-ui 1.3.5-beta.782 → 1.3.5-beta.784
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/components/molecules/TagifyInput/TagifyInput.js +79 -29
- package/es/components/molecules/TagifyInput/constants.js +2 -1
- package/es/components/molecules/TagifyInput/errorWrapper.js +2 -2
- package/es/components/molecules/TagifyInput/hooks/index.d.ts +1 -0
- package/es/components/molecules/TagifyInput/hooks/index.js +1 -0
- package/es/components/molecules/TagifyInput/hooks/useSettingsTagify.d.ts +7 -0
- package/es/components/molecules/TagifyInput/hooks/useSettingsTagify.js +30 -0
- package/es/components/molecules/TagifyInput/patternHandlers.d.ts +5 -1
- package/es/components/molecules/TagifyInput/patternHandlers.js +8 -8
- package/es/components/molecules/TagifyInput/types.d.ts +7 -6
- package/es/components/molecules/TagifyInput/utils.d.ts +6 -4
- package/es/components/molecules/TagifyInput/utils.js +7 -5
- package/es/components/organism/ActivityTimeline/ActivityTimeline.js +2 -3
- package/es/components/organism/ActivityTimeline/components/ProductCard/styled.js +5 -10
- package/es/components/organism/ActivityTimeline/styled.js +8 -2
- package/es/locales/en/google-sheet.json +18 -4
- package/es/locales/i18n.d.ts +42 -0
- package/es/locales/ja/google-sheet.json +84 -70
- package/es/locales/vi/google-sheet.json +18 -4
- package/package.json +3 -1
|
@@ -7,6 +7,7 @@ import { useDeepCompareMemo } from '@antscorp/antsomi-ui/es/hooks/useDeepCompare
|
|
|
7
7
|
import { useDebounce } from '@antscorp/antsomi-ui/es/hooks/useDebounce';
|
|
8
8
|
import { useUpdateEffect } from '@antscorp/antsomi-ui/es/hooks/useUpdateEffect';
|
|
9
9
|
import { useDeepCompareEffect } from '@antscorp/antsomi-ui/es/hooks/useDeepCompareEffect';
|
|
10
|
+
import { useSettingsTagify } from './hooks';
|
|
10
11
|
// Components
|
|
11
12
|
import Tagify from '@yaireo/tagify';
|
|
12
13
|
// Css
|
|
@@ -14,15 +15,16 @@ import '@yaireo/tagify/dist/tagify.css';
|
|
|
14
15
|
// Styled
|
|
15
16
|
import { TagTextArea, TagifyWrapper, WrapperPlaceHolder } from './styled';
|
|
16
17
|
// Utils
|
|
17
|
-
import { parseTagStringToTagify, convertInputStringToOriginal, emojiManufacturer, getEmojiTag, } from './utils';
|
|
18
|
+
import { parseTagStringToTagify, convertInputStringToOriginal, emojiManufacturer, getEmojiTag, isPersonalizeTagType, } from './utils';
|
|
19
|
+
import { acceptablePatternChecking, getCachedRegex, getPersonalizeTagInfo, patternHandlers, } from './patternHandlers';
|
|
18
20
|
// Constants
|
|
19
|
-
import { EMOJI, defaultCssVariables, tagifyDefaultProps } from './constants';
|
|
21
|
+
import { EMOJI, PERSONALIZE_PTN, SHORT_LINK, defaultCssVariables, tagifyDefaultProps, } from './constants';
|
|
20
22
|
const TagifyInput = forwardRef((props, ref) => {
|
|
21
23
|
// Props
|
|
22
|
-
const {
|
|
24
|
+
const { initialValue, readonly, disabled, maxLength, placeholder, acceptableTagPattern, mapAttributes, maxPersonalizeTags, name, children, cssTagifyVariables, onTagClick, onChange, } = props;
|
|
23
25
|
console.count('------------ re-render ------------');
|
|
24
26
|
// States
|
|
25
|
-
const [
|
|
27
|
+
const [inputTypeDebounce, , setInputTyping] = useDebounce(initialValue, 450);
|
|
26
28
|
// Refs
|
|
27
29
|
const inputRef = useRef(null);
|
|
28
30
|
const tagifyRef = useRef(null);
|
|
@@ -30,20 +32,22 @@ const TagifyInput = forwardRef((props, ref) => {
|
|
|
30
32
|
const placeHolderRef = useRef(null);
|
|
31
33
|
// Memoizations
|
|
32
34
|
const cssVariablesMemoized = useMemo(() => _.assign({}, defaultCssVariables, cssTagifyVariables || {}), [cssTagifyVariables]);
|
|
33
|
-
const
|
|
35
|
+
const parsedDefaultValue = useDeepCompareMemo(() => parseTagStringToTagify(initialValue, acceptableTagPattern), [initialValue, acceptableTagPattern]);
|
|
34
36
|
// Expose some methods
|
|
35
37
|
useImperativeHandle(ref, () => ({
|
|
36
38
|
onAddNewTag: (newTag) => {
|
|
37
39
|
if (newTag && tagifyRef.current) {
|
|
38
|
-
const { settings } = tagifyRef.current;
|
|
39
|
-
const { readonly } = settings;
|
|
40
|
+
const { settings, value: currentTags } = tagifyRef.current;
|
|
41
|
+
const { readonly, maxTags } = settings;
|
|
42
|
+
const currentPersonalizeTags = currentTags.filter(tag => ![EMOJI, SHORT_LINK].includes(tag.type));
|
|
43
|
+
const currentPersonalizeTagsLength = currentPersonalizeTags.length;
|
|
40
44
|
// Check readonly
|
|
41
45
|
if (readonly)
|
|
42
46
|
return;
|
|
43
47
|
// For case add new common emoji
|
|
44
48
|
if (typeof newTag === 'string') {
|
|
45
49
|
tagifyRef.current.injectAtCaret(newTag);
|
|
46
|
-
// Need to
|
|
50
|
+
// Need to re-select to keep the caret position
|
|
47
51
|
const selection = window.getSelection();
|
|
48
52
|
if (selection?.rangeCount) {
|
|
49
53
|
const range = selection.getRangeAt(0);
|
|
@@ -52,21 +56,26 @@ const TagifyInput = forwardRef((props, ref) => {
|
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
else {
|
|
59
|
+
// In case add new common tag
|
|
55
60
|
const { type } = newTag;
|
|
56
|
-
|
|
61
|
+
/*
|
|
62
|
+
* Validate the max limit before add new tag
|
|
63
|
+
* For emoji and short link, it will be passed
|
|
64
|
+
*/
|
|
65
|
+
if (![EMOJI, SHORT_LINK].includes(type) &&
|
|
66
|
+
currentPersonalizeTagsLength >= maxTags)
|
|
67
|
+
return;
|
|
68
|
+
// Create new tag
|
|
57
69
|
const newTagEle = tagifyRef.current.createTagElem(newTag);
|
|
70
|
+
// Add new tag
|
|
58
71
|
tagifyRef.current.injectAtCaret(newTagEle);
|
|
59
72
|
// Change data out before place the caret to keep valid caret positioning
|
|
60
73
|
const inputValue = tagifyRef.current.getInputValue();
|
|
61
74
|
const convertedValue = convertInputStringToOriginal(inputValue);
|
|
62
75
|
onChange(convertedValue);
|
|
63
|
-
if
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
tagifyRef.current.placeCaretAfterNode(newTagEle);
|
|
69
|
-
}
|
|
76
|
+
// NOTE: place to refactor if not need to add space after the tag
|
|
77
|
+
const spaceEle = tagifyRef.current.insertAfterTag(newTagEle, '\u00A0'); // <- adds space after the tag
|
|
78
|
+
tagifyRef.current.placeCaretAfterNode(spaceEle);
|
|
70
79
|
}
|
|
71
80
|
}
|
|
72
81
|
},
|
|
@@ -136,17 +145,19 @@ const TagifyInput = forwardRef((props, ref) => {
|
|
|
136
145
|
templates: {
|
|
137
146
|
tag: customizeTag,
|
|
138
147
|
},
|
|
139
|
-
maxTags,
|
|
140
|
-
readonly,
|
|
141
148
|
mode: 'mix',
|
|
142
|
-
placeholder,
|
|
149
|
+
placeholder: 'Enter your text...',
|
|
143
150
|
mixMode: {
|
|
144
151
|
insertAfterTag: '', // Not insert anything after tag
|
|
145
152
|
},
|
|
146
153
|
tagTextProp: 'label', // Use `tagify.label` to display the tags
|
|
147
154
|
enforceWhitelist: false, // Ensure that tags not in the whitelist can be added
|
|
148
155
|
duplicates: true, // Allow duplicate tags
|
|
149
|
-
editTags: false, //
|
|
156
|
+
editTags: false, // Not allow tag editing
|
|
157
|
+
dropdown: {
|
|
158
|
+
enabled: false, // Do not display the dropdown
|
|
159
|
+
},
|
|
160
|
+
pattern: /^$a/, // -> using this regex never match any character to "prevent" add new tag when press enter
|
|
150
161
|
hooks: {
|
|
151
162
|
beforeKeyDown: (event, data) => {
|
|
152
163
|
/*
|
|
@@ -174,7 +185,7 @@ const TagifyInput = forwardRef((props, ref) => {
|
|
|
174
185
|
},
|
|
175
186
|
});
|
|
176
187
|
}
|
|
177
|
-
}, [
|
|
188
|
+
}, [maxLength, customizeTag]);
|
|
178
189
|
// Initialization tagify
|
|
179
190
|
useLayoutEffect(() => {
|
|
180
191
|
initializeTagify();
|
|
@@ -184,14 +195,53 @@ const TagifyInput = forwardRef((props, ref) => {
|
|
|
184
195
|
}
|
|
185
196
|
};
|
|
186
197
|
}, [initializeTagify]);
|
|
187
|
-
//
|
|
198
|
+
// Settings some tagify attributes
|
|
199
|
+
useSettingsTagify(tagifyRef.current, {
|
|
200
|
+
disabled,
|
|
201
|
+
readonly,
|
|
202
|
+
maxPersonalizeTags,
|
|
203
|
+
placeholder,
|
|
204
|
+
});
|
|
205
|
+
/*
|
|
206
|
+
* Need to sync label of the tags if any map attribute is changed to make correct label
|
|
207
|
+
* */
|
|
188
208
|
useDeepCompareEffect(() => {
|
|
189
209
|
if (!_.isEmpty(mapAttributes) && tagifyRef.current) {
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
210
|
+
const tagElements = tagifyRef.current.getTagElms();
|
|
211
|
+
const { pattern, name: cachePatternName, acceptablePattern: acceptableType, } = patternHandlers[PERSONALIZE_PTN];
|
|
212
|
+
tagElements.forEach(tagElement => {
|
|
213
|
+
const { __tagifyTagData: tagData } = tagElement;
|
|
214
|
+
if (tagData) {
|
|
215
|
+
const { type, value } = tagData;
|
|
216
|
+
const isPersonalTag = isPersonalizeTagType(type);
|
|
217
|
+
if (isPersonalTag && value) {
|
|
218
|
+
const isAccepted = acceptablePatternChecking(acceptableType, acceptableTagPattern);
|
|
219
|
+
// No need to continue if pattern is not accepted
|
|
220
|
+
if (!isAccepted)
|
|
221
|
+
return;
|
|
222
|
+
// Use the cached regex instead of creating a new one each time
|
|
223
|
+
const regex = getCachedRegex(pattern, 'g', cachePatternName);
|
|
224
|
+
let match;
|
|
225
|
+
// Iterate over matches of the current pattern
|
|
226
|
+
// eslint-disable-next-line no-cond-assign
|
|
227
|
+
while ((match = regex.exec(value)) !== null) {
|
|
228
|
+
const [, personalizeContent] = match;
|
|
229
|
+
const [tagCode] = personalizeContent.split('||');
|
|
230
|
+
const { label: tagLabel } = getPersonalizeTagInfo(tagCode, mapAttributes);
|
|
231
|
+
const tagTextNode = tagifyRef.current?.getTagTextNode(tagElement);
|
|
232
|
+
if (tagTextNode) {
|
|
233
|
+
/*
|
|
234
|
+
* Just only update to the correct text of the tag
|
|
235
|
+
* NOTE: Do not actually affect raw data
|
|
236
|
+
*/
|
|
237
|
+
tagTextNode.textContent = tagLabel;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
193
243
|
}
|
|
194
|
-
}, [mapAttributes]);
|
|
244
|
+
}, [mapAttributes, acceptableTagPattern]);
|
|
195
245
|
// Listen to Tagify events
|
|
196
246
|
useEffect(() => {
|
|
197
247
|
const { current: tagifyInstance } = tagifyRef || {};
|
|
@@ -210,9 +260,9 @@ const TagifyInput = forwardRef((props, ref) => {
|
|
|
210
260
|
};
|
|
211
261
|
}, [onTagItemClick, onTagifyTyping, onTagifyRemoved]);
|
|
212
262
|
useUpdateEffect(() => {
|
|
213
|
-
const convertedValue = convertInputStringToOriginal(
|
|
263
|
+
const convertedValue = convertInputStringToOriginal(inputTypeDebounce);
|
|
214
264
|
onChange(convertedValue);
|
|
215
|
-
}, [
|
|
265
|
+
}, [inputTypeDebounce]);
|
|
216
266
|
useEffect(() => {
|
|
217
267
|
if (!tagifyRef.current?.DOM.scope)
|
|
218
268
|
return;
|
|
@@ -241,7 +291,7 @@ const TagifyInput = forwardRef((props, ref) => {
|
|
|
241
291
|
}
|
|
242
292
|
};
|
|
243
293
|
}, []);
|
|
244
|
-
return (_jsxs(TagifyWrapper, { ref: tagifyWrapperRef, "$cssTagifyVariables": cssVariablesMemoized, className: "tagify-container", id: "tagify-container", "data-test": "tagify-wrapper", children: [_jsx(TagTextArea, { id: "tagify-textarea", ref: inputRef, name: name, defaultValue:
|
|
294
|
+
return (_jsxs(TagifyWrapper, { ref: tagifyWrapperRef, "$cssTagifyVariables": cssVariablesMemoized, className: "tagify-container", id: "tagify-container", "data-test": "tagify-wrapper", children: [_jsx(TagTextArea, { id: "tagify-textarea", ref: inputRef, name: name, defaultValue: parsedDefaultValue, "data-test": "tagify-input" }), _jsx(WrapperPlaceHolder, { ref: placeHolderRef, "$isShow": !!children, children: children })] }));
|
|
245
295
|
});
|
|
246
296
|
TagifyInput.defaultProps = tagifyDefaultProps;
|
|
247
297
|
export default memo(TagifyInput);
|
|
@@ -36,9 +36,10 @@ export const DEFAULT_ACCEPT_TAGS = [
|
|
|
36
36
|
LINE_EMOJI_PTN,
|
|
37
37
|
];
|
|
38
38
|
export const tagifyDefaultProps = {
|
|
39
|
-
|
|
39
|
+
initialValue: '',
|
|
40
40
|
name: 'tagifyInput',
|
|
41
41
|
readonly: false,
|
|
42
|
+
disabled: false,
|
|
42
43
|
placeholder: undefined,
|
|
43
44
|
acceptableTagPattern: DEFAULT_ACCEPT_TAGS,
|
|
44
45
|
onChange: () => { },
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useSettingsTagify';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useSettingsTagify';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/// <reference types="yaireo__tagify" />
|
|
2
|
+
import Tagify from '@yaireo/tagify';
|
|
3
|
+
import type { TagDataCustomize, TagifyInputProps } from '../types';
|
|
4
|
+
type TagifyInstanceProps = Tagify<TagDataCustomize> | null;
|
|
5
|
+
type SettingsTagifyProps = Pick<TagifyInputProps, 'readonly' | 'disabled' | 'placeholder' | 'maxPersonalizeTags'>;
|
|
6
|
+
export declare const useSettingsTagify: (tagifyInstance: TagifyInstanceProps, settings: SettingsTagifyProps) => void;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/exhaustive-deps */
|
|
2
|
+
// Libraries
|
|
3
|
+
import { useLayoutEffect } from 'react';
|
|
4
|
+
export const useSettingsTagify = (tagifyInstance, settings) => {
|
|
5
|
+
const { readonly, disabled, placeholder, maxPersonalizeTags } = settings;
|
|
6
|
+
// Set read only
|
|
7
|
+
useLayoutEffect(() => {
|
|
8
|
+
if (tagifyInstance && typeof readonly !== 'undefined') {
|
|
9
|
+
tagifyInstance.setReadonly(readonly);
|
|
10
|
+
}
|
|
11
|
+
}, [readonly]);
|
|
12
|
+
// Set disabled
|
|
13
|
+
useLayoutEffect(() => {
|
|
14
|
+
if (tagifyInstance && typeof disabled !== 'undefined') {
|
|
15
|
+
tagifyInstance.setDisabled(disabled);
|
|
16
|
+
}
|
|
17
|
+
}, [disabled]);
|
|
18
|
+
// Set placeholder
|
|
19
|
+
useLayoutEffect(() => {
|
|
20
|
+
if (tagifyInstance && typeof placeholder !== 'undefined') {
|
|
21
|
+
tagifyInstance.setPlaceholder(placeholder);
|
|
22
|
+
}
|
|
23
|
+
}, [placeholder]);
|
|
24
|
+
// Set max personalize tags
|
|
25
|
+
useLayoutEffect(() => {
|
|
26
|
+
if (tagifyInstance && typeof maxPersonalizeTags !== 'undefined') {
|
|
27
|
+
tagifyInstance.settings.maxTags = maxPersonalizeTags;
|
|
28
|
+
}
|
|
29
|
+
}, [maxPersonalizeTags]);
|
|
30
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AcceptablePattern, PatterTagName, PatternHandlerWrapper } from './types';
|
|
1
|
+
import type { AcceptablePattern, MapAttributesProps, PatterTagName, PatternHandlerWrapper } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Retrieves a cached regular expression or compiles and caches it if not found.
|
|
4
4
|
* @param pattern The regex pattern string.
|
|
@@ -10,4 +10,8 @@ export declare function getCachedRegex(pattern: string, flags?: string, cacheKey
|
|
|
10
10
|
export declare const tagRegexStringPattern = "\\[\\[({.*?})\\]\\]";
|
|
11
11
|
export declare function acceptablePatternChecking(pattern: AcceptablePattern, acceptablePattern: Array<AcceptablePattern>): boolean;
|
|
12
12
|
export declare function validateURL(txt: string): boolean;
|
|
13
|
+
export declare const getPersonalizeTagInfo: (originalTag: string, mapAttributes?: MapAttributesProps) => {
|
|
14
|
+
label: string;
|
|
15
|
+
type: string;
|
|
16
|
+
};
|
|
13
17
|
export declare const patternHandlers: Record<PatterTagName, PatternHandlerWrapper>;
|
|
@@ -38,7 +38,7 @@ export function validateURL(txt) {
|
|
|
38
38
|
const regexUrl = getCachedRegex('^(https?:\\/\\/)?(([A-Za-z]{3,9}:)?(\\/\\/)?(?:[-;:&=+$,\\w]+@)?[A-Za-z0-9.-]+|(?:www\\.|[-;:&=+$,\\w]+@)[A-Za-z0-9.-]+)((\\/[+~%\\/\\.\\w-_]*)*(?:\\?[-+=&;%@\\.\\w_]*)?(#(?:[.!\\/\\\\\\w-]*)?)?)$', '', 'checkingURL');
|
|
39
39
|
return regexUrl.test(txt);
|
|
40
40
|
}
|
|
41
|
-
const getPersonalizeTagInfo = (originalTag, mapAttributes) => {
|
|
41
|
+
export const getPersonalizeTagInfo = (originalTag, mapAttributes) => {
|
|
42
42
|
try {
|
|
43
43
|
const [type, attributeName] = originalTag.split('.');
|
|
44
44
|
if (!mapAttributes || !mapAttributes[type]) {
|
|
@@ -87,7 +87,7 @@ const handleShortlinkIndividualPattern = match => {
|
|
|
87
87
|
const tag = createTagPattern({
|
|
88
88
|
label,
|
|
89
89
|
type: SHORT_LINK,
|
|
90
|
-
|
|
90
|
+
shortlinkType: SHORT_LINK_TYPE.INDIVIDUAL,
|
|
91
91
|
value: fullMatch,
|
|
92
92
|
});
|
|
93
93
|
return { isValid, tag };
|
|
@@ -114,7 +114,7 @@ const handleShortlinkGeneralPattern = match => {
|
|
|
114
114
|
const tag = createTagPattern({
|
|
115
115
|
label,
|
|
116
116
|
type: SHORT_LINK,
|
|
117
|
-
|
|
117
|
+
shortlinkType: SHORT_LINK_TYPE.GENERAL,
|
|
118
118
|
value: fullMatch,
|
|
119
119
|
});
|
|
120
120
|
return { isValid, tag };
|
|
@@ -140,17 +140,17 @@ const handleLinePattern = match => {
|
|
|
140
140
|
/*
|
|
141
141
|
* Function to handle generic of personalize #{...} pattern
|
|
142
142
|
*/
|
|
143
|
-
const handlePersonalizeTagPattern =
|
|
143
|
+
const handlePersonalizeTagPattern = match => {
|
|
144
144
|
const [personalizeTag, personalizeContent] = match;
|
|
145
145
|
const [tagCode] = personalizeContent.split('||');
|
|
146
|
-
const
|
|
147
|
-
if (!tagCode || !
|
|
146
|
+
const [type, attributeName] = tagCode.split('.');
|
|
147
|
+
if (!tagCode || !type) {
|
|
148
148
|
console.error('Invalid personalize pattern detected: ', tagCode);
|
|
149
149
|
return { isValid: false, tag: '[[Invalid Personalize]]' };
|
|
150
150
|
}
|
|
151
151
|
const tag = createTagPattern({
|
|
152
|
-
type:
|
|
153
|
-
label:
|
|
152
|
+
type: type,
|
|
153
|
+
label: attributeName || type,
|
|
154
154
|
value: personalizeTag,
|
|
155
155
|
});
|
|
156
156
|
return { isValid: true, tag };
|
|
@@ -9,10 +9,10 @@ export type MapAttributesProps = Record<string, Record<string, any>>;
|
|
|
9
9
|
*/
|
|
10
10
|
export interface TagifyInputProps {
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Initial value for the Tagify input field.
|
|
13
|
+
* Only used when the component is first rendered.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
initialValue: string;
|
|
16
16
|
/**
|
|
17
17
|
* Optional mapping configuration for custom attributes associated with tags.
|
|
18
18
|
* Defines how tag attributes are mapped and processed internally.
|
|
@@ -30,12 +30,13 @@ export interface TagifyInputProps {
|
|
|
30
30
|
classNames?: ClassNameSettings;
|
|
31
31
|
placeholder?: TagifySettings['placeholder'];
|
|
32
32
|
readonly?: TagifySettings['readonly'];
|
|
33
|
+
disabled?: boolean;
|
|
33
34
|
maxLength?: number;
|
|
34
35
|
/**
|
|
35
36
|
* Specifies the maximum number of tags that can be added to the input.
|
|
36
37
|
* Helps enforce constraints by limiting the number of tags a user can input.
|
|
37
38
|
*/
|
|
38
|
-
|
|
39
|
+
maxPersonalizeTags?: TagifySettings['maxTags'];
|
|
39
40
|
/**
|
|
40
41
|
* Defines acceptable patterns or validation rules for tags.
|
|
41
42
|
* Ensures only tags matching specified patterns can be added, enforcing content rules.
|
|
@@ -84,7 +85,7 @@ interface TagDataEmoji extends Omit<TagDataText, 'type'> {
|
|
|
84
85
|
interface TagDataShortLink extends Omit<TagDataText, 'type'> {
|
|
85
86
|
value: string;
|
|
86
87
|
type: Extract<TagType, 'shortlink'>;
|
|
87
|
-
|
|
88
|
+
shortlinkType: ShortLinkType;
|
|
88
89
|
}
|
|
89
90
|
export type TagDataCustomize = TagDataEmoji | TagDataText | TagDataShortLink;
|
|
90
91
|
export interface EmojiTag {
|
|
@@ -92,7 +93,7 @@ export interface EmojiTag {
|
|
|
92
93
|
emoji: string;
|
|
93
94
|
code: string;
|
|
94
95
|
}
|
|
95
|
-
export type PatternHandler = (match: RegExpExecArray
|
|
96
|
+
export type PatternHandler = (match: RegExpExecArray) => {
|
|
96
97
|
isValid: boolean;
|
|
97
98
|
tag: string;
|
|
98
99
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { AcceptablePattern, EmojiCollection, EmojiTag,
|
|
1
|
+
import { AcceptablePattern, EmojiCollection, EmojiTag, TagType } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Parses the input string and replaces matching patterns with processed tags.
|
|
4
4
|
* This function iterates over predefined regex patterns and replaces each match
|
|
5
5
|
* with a corresponding replacement string generated by pattern handlers.
|
|
6
6
|
*
|
|
7
7
|
* @param {string} input - The input string containing tags and patterns to be replaced.
|
|
8
|
-
* @param {
|
|
8
|
+
* @param {Array<AcceptablePattern>} acceptableTagPattern - An array of acceptable tag patterns
|
|
9
9
|
* passed to the pattern handler for tag processing.
|
|
10
10
|
* @returns {string} The modified string with all pattern matches replaced by their corresponding tags.
|
|
11
11
|
*
|
|
@@ -18,10 +18,11 @@ import { AcceptablePattern, EmojiCollection, EmojiTag, MapAttributesProps } from
|
|
|
18
18
|
* Example:
|
|
19
19
|
* ```javascript
|
|
20
20
|
* const input = "Here is some text with a #{shortlink(https://example.com)} pattern.";
|
|
21
|
-
* const
|
|
21
|
+
* const acceptableTagPattern = ['shortlink'];
|
|
22
|
+
* const result = parseTagStringToTagify(input, acceptableTagPattern);
|
|
22
23
|
* ```
|
|
23
24
|
*/
|
|
24
|
-
export declare const parseTagStringToTagify: (input: string, acceptableTagPattern: Array<AcceptablePattern
|
|
25
|
+
export declare const parseTagStringToTagify: (input: string, acceptableTagPattern: Array<AcceptablePattern>) => string;
|
|
25
26
|
/**
|
|
26
27
|
* Converts an input string containing JSON-like tags to a formatted string.
|
|
27
28
|
* @param input The input string with JSON-like tags.
|
|
@@ -43,3 +44,4 @@ export declare const getImageSourceViberEmoji: (fileName?: string) => any;
|
|
|
43
44
|
export declare const emojiManufacturer: (text: string, collectionType: EmojiCollection) => string[];
|
|
44
45
|
export declare const getEmojiTag: ({ src, emoji, code }: EmojiTag) => string;
|
|
45
46
|
export declare const getStyledTags: () => string;
|
|
47
|
+
export declare const isPersonalizeTagType: (type: TagType) => boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Libraries
|
|
2
2
|
import stringReplaceToArray from 'string-replace-to-array';
|
|
3
3
|
// Constants
|
|
4
|
-
import { EMOJI, EMOJI_COLLECTIONS, PREFIX_PATTERN_LINE_MESSAGE, TAG_COLOR, TAG_TYPE, } from './constants';
|
|
4
|
+
import { CUSTOMER, CUSTOM_FN, EMOJI, EMOJI_COLLECTIONS, EVENT, OBJECT_WIDGET, PREFIX_PATTERN_LINE_MESSAGE, PROMOTION_CODE, TAG_COLOR, TAG_TYPE, VISITOR, } from './constants';
|
|
5
5
|
import { iconsViber } from './iconsViber';
|
|
6
6
|
// Utils
|
|
7
7
|
import { acceptablePatternChecking, getCachedRegex, patternHandlers, tagRegexStringPattern, } from './patternHandlers';
|
|
@@ -11,7 +11,7 @@ import { acceptablePatternChecking, getCachedRegex, patternHandlers, tagRegexStr
|
|
|
11
11
|
* with a corresponding replacement string generated by pattern handlers.
|
|
12
12
|
*
|
|
13
13
|
* @param {string} input - The input string containing tags and patterns to be replaced.
|
|
14
|
-
* @param {
|
|
14
|
+
* @param {Array<AcceptablePattern>} acceptableTagPattern - An array of acceptable tag patterns
|
|
15
15
|
* passed to the pattern handler for tag processing.
|
|
16
16
|
* @returns {string} The modified string with all pattern matches replaced by their corresponding tags.
|
|
17
17
|
*
|
|
@@ -24,10 +24,11 @@ import { acceptablePatternChecking, getCachedRegex, patternHandlers, tagRegexStr
|
|
|
24
24
|
* Example:
|
|
25
25
|
* ```javascript
|
|
26
26
|
* const input = "Here is some text with a #{shortlink(https://example.com)} pattern.";
|
|
27
|
-
* const
|
|
27
|
+
* const acceptableTagPattern = ['shortlink'];
|
|
28
|
+
* const result = parseTagStringToTagify(input, acceptableTagPattern);
|
|
28
29
|
* ```
|
|
29
30
|
*/
|
|
30
|
-
export const parseTagStringToTagify = (input, acceptableTagPattern
|
|
31
|
+
export const parseTagStringToTagify = (input, acceptableTagPattern) => {
|
|
31
32
|
const resultParts = [];
|
|
32
33
|
let lastIndex = 0;
|
|
33
34
|
// Array to store all matches from all patterns with their positions
|
|
@@ -45,7 +46,7 @@ export const parseTagStringToTagify = (input, acceptableTagPattern, mapAttribute
|
|
|
45
46
|
// Iterate over matches of the current pattern
|
|
46
47
|
// eslint-disable-next-line no-cond-assign
|
|
47
48
|
while ((match = regex.exec(input)) !== null) {
|
|
48
|
-
const { isValid, tag } = handler(match
|
|
49
|
+
const { isValid, tag } = handler(match);
|
|
49
50
|
if (isValid) {
|
|
50
51
|
matches.push({ startIndex: match.index, endIndex: regex.lastIndex, replacement: tag });
|
|
51
52
|
}
|
|
@@ -325,3 +326,4 @@ export const getStyledTags = () => {
|
|
|
325
326
|
});
|
|
326
327
|
return styledTags.join('');
|
|
327
328
|
};
|
|
329
|
+
export const isPersonalizeTagType = (type) => [CUSTOMER, VISITOR, EVENT, PROMOTION_CODE, OBJECT_WIDGET, CUSTOM_FN].includes(type);
|
|
@@ -5,10 +5,9 @@ import { StyledNoData, StyldTitle, StyledRoot, TimelineBottom } from './styled';
|
|
|
5
5
|
import { Flex, Spin } from '../../atoms';
|
|
6
6
|
import { ItemEvent, TimeLineTitle, ItemGroupEvent } from './components';
|
|
7
7
|
import { useInView } from 'react-intersection-observer';
|
|
8
|
-
import { translate, translations } from '@antscorp/antsomi-
|
|
8
|
+
import { translate, translations } from '@antscorp/antsomi-locales';
|
|
9
9
|
import { isEmpty } from 'lodash';
|
|
10
10
|
import { differenceInMonths, formatDateTZ, startOfMonth, subMonths, } from '@antscorp/antsomi-ui/es/utils/date';
|
|
11
|
-
import { getTranslateMessage } from '@antscorp/antsomi-ui/es/locales/i18n';
|
|
12
11
|
import { EmptyData } from '../../molecules';
|
|
13
12
|
export const ActivityTimeline = (props) => {
|
|
14
13
|
const { timelines = [], isLoading = false, title = translate(translations._BLOCK_TIMELINE_CUS), timezone = Intl.DateTimeFormat().resolvedOptions().timeZone, objectName = '_THIS_PERSON_UPPERCASE', onFetchMore, eventTracking: eventTrackingProp = [], header, className, } = props;
|
|
@@ -92,7 +91,7 @@ export const ActivityTimeline = (props) => {
|
|
|
92
91
|
return (_jsxs(_Fragment, { children: [header, _jsx(Flex, { style: { height: 240 }, align: "center", justify: "center", children: _jsx(Spin, { indicatorSize: 24 }) })] }));
|
|
93
92
|
}
|
|
94
93
|
if (!timelines.length) {
|
|
95
|
-
return (_jsxs(_Fragment, { children: [header, _jsx(StyledNoData, {
|
|
94
|
+
return (_jsxs(_Fragment, { children: [header, _jsx(StyledNoData, { align: "center", justify: "center", children: _jsx(EmptyData, { showIcon: false, title: translate(translations._PROFILES_NO_DATA), description: translate(translations._PROFILES_MESSAGE_NO_DATA_TIMELINE).toString() }) })] }));
|
|
96
95
|
}
|
|
97
96
|
return (_jsxs(_Fragment, { children: [header, showMainContent(timelines, objectName), showBottomComponent()] }));
|
|
98
97
|
};
|
|
@@ -14,10 +14,13 @@ export const ImgPanel = styled.div `
|
|
|
14
14
|
height: 6.25rem;
|
|
15
15
|
position: relative;
|
|
16
16
|
border: 1px solid rgb(230, 230, 230);
|
|
17
|
+
border-radius: 10px;
|
|
18
|
+
|
|
17
19
|
@media screen and (max-width: 767px) {
|
|
18
20
|
width: 80px;
|
|
19
21
|
height: 80px;
|
|
20
22
|
}
|
|
23
|
+
|
|
21
24
|
&:before {
|
|
22
25
|
content: '';
|
|
23
26
|
position: absolute;
|
|
@@ -42,9 +45,11 @@ export const ImgPanel = styled.div `
|
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
}
|
|
48
|
+
|
|
45
49
|
a {
|
|
46
50
|
width: 100%;
|
|
47
51
|
height: 100%;
|
|
52
|
+
|
|
48
53
|
& > span {
|
|
49
54
|
display: block;
|
|
50
55
|
width: 100%;
|
|
@@ -80,15 +85,5 @@ export const LinkExtendTitle = styled(Typography.Link) `
|
|
|
80
85
|
`;
|
|
81
86
|
export const PlainCard = styled.div `
|
|
82
87
|
font-size: 0.875rem;
|
|
83
|
-
|
|
84
|
-
/* font-size: 0.75rem; */
|
|
85
|
-
|
|
86
88
|
line-height: 1.25;
|
|
87
|
-
/* &:last-of-type {
|
|
88
|
-
/* margin-top: 2.375rem;
|
|
89
|
-
margin-top: 3rem;
|
|
90
|
-
@media screen and (max-width: 767px) {
|
|
91
|
-
margin-top: 12px;
|
|
92
|
-
}
|
|
93
|
-
} */
|
|
94
89
|
`;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { Flex } from 'antd';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
|
-
export const StyledRoot = styled.div
|
|
3
|
+
export const StyledRoot = styled.div `
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
height: 100%;
|
|
7
|
+
`;
|
|
4
8
|
export const StyldTitle = styled.div `
|
|
5
9
|
font-size: 16px;
|
|
6
10
|
font-weight: bold;
|
|
7
11
|
`;
|
|
8
|
-
export const StyledNoData = styled(Flex)
|
|
12
|
+
export const StyledNoData = styled(Flex) `
|
|
13
|
+
height: 100%;
|
|
14
|
+
`;
|
|
9
15
|
export const WrapperContainerRedeem = styled.div `
|
|
10
16
|
display: flex;
|
|
11
17
|
justify-content: space-between;
|
|
@@ -1060,6 +1060,7 @@
|
|
|
1060
1060
|
"_TITL_DISPLAY_TIME_AS": "Display time as",
|
|
1061
1061
|
"_TITL_DISPLAY_FUNCTION_OUTPUT": "Display function output",
|
|
1062
1062
|
"_TITL_DOMAIN": "Domain",
|
|
1063
|
+
"_TITL_COOKIE_DOMAIN": "Cookie Domain",
|
|
1063
1064
|
"_TITL_DOWNLOAD_DATA_EXAMPLE": "Download data example",
|
|
1064
1065
|
"_TITL_DRAG_FILE_HERE": "Drag file here",
|
|
1065
1066
|
"_TITL_DRAG_IMAGE_HERE": "Drag image here",
|
|
@@ -2121,7 +2122,7 @@
|
|
|
2121
2122
|
"_PREDICT_MODEL_DESCRIBE_PLACEHOLDER": "Describe your RFM model",
|
|
2122
2123
|
"_PREDICT_MODEL_BO_DISABLE": "Data-updated of this Business Object has been disabled",
|
|
2123
2124
|
"_PREDICT_MODEL_CREATE_NEW_RFM": "Create new RFM",
|
|
2124
|
-
"_DES_DELIVERY_INTERVAL": "Delivery Interval
|
|
2125
|
+
"_DES_DELIVERY_INTERVAL": "Delivery Interval",
|
|
2125
2126
|
"_DES_BY_NUMBER_RECORD": "By number of record",
|
|
2126
2127
|
"_DES_BY_DAY": "By day(s)",
|
|
2127
2128
|
"_DES_BY_HOUR": "By hour(s)",
|
|
@@ -2612,12 +2613,12 @@
|
|
|
2612
2613
|
"_PROFILES_WIDGET_1": "Customer information",
|
|
2613
2614
|
"_PROFILES_WIDGET_2": "Item recommendation",
|
|
2614
2615
|
"_PROFILES_WIDGET_3": "User activity",
|
|
2615
|
-
"_PROFILES_WIDGET_4": "Visitor
|
|
2616
|
+
"_PROFILES_WIDGET_4": "Visitor information",
|
|
2616
2617
|
"_PROFILES_WIDGET_5": "Extended visualizations",
|
|
2617
2618
|
"_PROFILES_SETTINGS_TAB": "Data",
|
|
2618
2619
|
"_PROFILES_SETTINGS_1": "Avatar",
|
|
2619
2620
|
"_PROFILES_SETTINGS_2": "Full name",
|
|
2620
|
-
"_PROFILES_BTN_ADD_SOCIAL_GR": "Add
|
|
2621
|
+
"_PROFILES_BTN_ADD_SOCIAL_GR": "Add social group",
|
|
2621
2622
|
"_PROFILES_AUDIENCE_INFO_1": "Customer since",
|
|
2622
2623
|
"_PROFILES_AUDIENCE_INFO_2": "Last activity",
|
|
2623
2624
|
"_PROFILES_BTN_ADD_ATT": "Add attribute",
|
|
@@ -2628,5 +2629,18 @@
|
|
|
2628
2629
|
"_PROFILES_BTN_SET_DEFAULT": "Set as default",
|
|
2629
2630
|
"_PROFILES_DEFAULT_TEMP_TOOLTIP": "Default template",
|
|
2630
2631
|
"_PROFILES_MESSAGE_NO_TEMP": "You don't have any templates to visualize profiles",
|
|
2631
|
-
"_PROFILES_USER_GUIDE_2": "Click the button to create a template"
|
|
2632
|
+
"_PROFILES_USER_GUIDE_2": "Click the button to create a template",
|
|
2633
|
+
"_PROFILES_MESSAGE_NO_DATA_TIMELINE": "Modify the visualization to configure displayed events",
|
|
2634
|
+
"_PROFILES_MESSAGE_NO_DATA_INFOR": "Modify the visualization to configure displayed attributes",
|
|
2635
|
+
"_PROFILES_MESSAGE_NO_DATA_GROUP": "Please add attributes you want to display",
|
|
2636
|
+
"_PROFILES_ADD_EVENT": "Add event",
|
|
2637
|
+
"_COOKIE_DM_DEFINITION": "What is it?",
|
|
2638
|
+
"_COOKIE_DM_INSTRUCTION": "Instruction",
|
|
2639
|
+
"_COOKIE_DM_DEFINITION_1": "The cookie domain allows you to specify a domain where tracking cookies will be set, ensuring seamless data collection across subdomains. This helps maintain a consistent User ID, enabling accurate cross-subdomain tracking and preventing fragmented customer profiles. ",
|
|
2640
|
+
"_COOKIE_DM_DEFINITION_2": "By ensuring unified data collection, it enhances personalization, improves analytics, and provides a clearer view of customer behavior across your entire web ecosystem.",
|
|
2641
|
+
"_COOKIE_DM_INSTRUCTION_1_SUM": "Identify the Primary Domain: ",
|
|
2642
|
+
"_COOKIE_DM_INSTRUCTION_1_DES_1": "This is the base domain for all subdomains you want to track. ",
|
|
2643
|
+
"_COOKIE_DM_INSTRUCTION_1_DES_2": "Example: {{x}}",
|
|
2644
|
+
"_COOKIE_DM_INSTRUCTION_2_SUM": "Configure the Cookie Domain:",
|
|
2645
|
+
"_COOKIE_DM_INSTRUCTION_2_DES_1": "Input {{x}} to track data across all subdomains (eg: shop.antsomi.com or blog.antsomi.com)"
|
|
2632
2646
|
}
|