@capillarytech/creatives-library 8.0.126 → 8.0.127-alpha.1

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 (78) hide show
  1. package/containers/App/constants.js +1 -0
  2. package/index.html +3 -1
  3. package/package.json +1 -1
  4. package/services/api.js +4 -4
  5. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
  6. package/tests/integration/TemplateCreation/api-response.js +5 -0
  7. package/tests/integration/TemplateCreation/msw-handler.js +42 -63
  8. package/utils/common.js +7 -0
  9. package/utils/commonUtils.js +2 -6
  10. package/utils/createPayload.js +272 -0
  11. package/utils/tests/createPayload.test.js +761 -0
  12. package/v2Components/CapImageUpload/index.js +59 -46
  13. package/v2Components/CapInAppCTA/index.js +1 -0
  14. package/v2Components/CapMpushCTA/constants.js +25 -0
  15. package/v2Components/CapMpushCTA/index.js +332 -0
  16. package/v2Components/CapMpushCTA/index.scss +95 -0
  17. package/v2Components/CapMpushCTA/messages.js +89 -0
  18. package/v2Components/CapTagList/index.js +177 -120
  19. package/v2Components/CapVideoUpload/constants.js +3 -0
  20. package/v2Components/CapVideoUpload/index.js +167 -110
  21. package/v2Components/CapVideoUpload/messages.js +16 -0
  22. package/v2Components/Carousel/index.js +15 -13
  23. package/v2Components/CustomerSearchSection/index.js +12 -7
  24. package/v2Components/ErrorInfoNote/style.scss +1 -0
  25. package/v2Components/MobilePushPreviewV2/index.js +37 -5
  26. package/v2Components/TemplatePreview/_templatePreview.scss +114 -72
  27. package/v2Components/TemplatePreview/assets/images/Android _ With date and time.svg +29 -0
  28. package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
  29. package/v2Components/TemplatePreview/assets/images/iOS _ With date and time.svg +26 -0
  30. package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
  31. package/v2Components/TemplatePreview/index.js +178 -50
  32. package/v2Components/TemplatePreview/messages.js +4 -0
  33. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +169 -0
  34. package/v2Components/TestAndPreviewSlidebox/LeftPanelContent.js +95 -0
  35. package/v2Components/TestAndPreviewSlidebox/PreviewSection.js +69 -0
  36. package/v2Components/TestAndPreviewSlidebox/SendTestMessage.js +68 -0
  37. package/v2Components/TestAndPreviewSlidebox/index.js +67 -246
  38. package/v2Components/TestAndPreviewSlidebox/tests/CustomValuesEditor.test.js +425 -0
  39. package/v2Components/TestAndPreviewSlidebox/tests/LeftPanelContent.test.js +400 -0
  40. package/v2Components/TestAndPreviewSlidebox/tests/SendTestMessage.test.js +448 -0
  41. package/v2Containers/CreativesContainer/SlideBoxContent.js +9 -9
  42. package/v2Containers/CreativesContainer/index.js +191 -136
  43. package/v2Containers/Email/index.js +15 -2
  44. package/v2Containers/InApp/constants.js +1 -0
  45. package/v2Containers/InApp/index.js +13 -13
  46. package/v2Containers/MobilePush/Create/index.js +1 -0
  47. package/v2Containers/MobilePush/commonMethods.js +7 -14
  48. package/v2Containers/MobilePushNew/actions.js +116 -0
  49. package/v2Containers/MobilePushNew/components/CtaButtons.js +170 -0
  50. package/v2Containers/MobilePushNew/components/MediaUploaders.js +754 -0
  51. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +279 -0
  52. package/v2Containers/MobilePushNew/components/index.js +5 -0
  53. package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +779 -0
  54. package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +2114 -0
  55. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +343 -0
  56. package/v2Containers/MobilePushNew/constants.js +115 -0
  57. package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1299 -0
  58. package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1223 -0
  59. package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +246 -0
  60. package/v2Containers/MobilePushNew/hooks/useUpload.js +726 -0
  61. package/v2Containers/MobilePushNew/index.js +2280 -0
  62. package/v2Containers/MobilePushNew/index.scss +308 -0
  63. package/v2Containers/MobilePushNew/messages.js +226 -0
  64. package/v2Containers/MobilePushNew/reducer.js +160 -0
  65. package/v2Containers/MobilePushNew/sagas.js +198 -0
  66. package/v2Containers/MobilePushNew/selectors.js +55 -0
  67. package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
  68. package/v2Containers/MobilePushNew/tests/sagas.test.js +863 -0
  69. package/v2Containers/MobilePushNew/tests/selectors.test.js +425 -0
  70. package/v2Containers/MobilePushNew/tests/utils.test.js +322 -0
  71. package/v2Containers/MobilePushNew/utils.js +33 -0
  72. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +5 -5
  73. package/v2Containers/TagList/index.js +56 -10
  74. package/v2Containers/Templates/_templates.scss +101 -1
  75. package/v2Containers/Templates/index.js +147 -35
  76. package/v2Containers/Templates/messages.js +8 -0
  77. package/v2Containers/Templates/sagas.js +2 -0
  78. package/v2Containers/Whatsapp/constants.js +1 -0
@@ -0,0 +1,246 @@
1
+ // eslint-disable-next-line jsx-a11y/href-no-hash
2
+ import { useCallback, useEffect, useRef } from 'react';
3
+ import {
4
+ ANDROID, GIF, IMAGE, IOS, VIDEO,
5
+ } from '../constants';
6
+ import { NONE } from '../../Whatsapp/constants';
7
+
8
+ /**
9
+ * Custom hook to manage content synchronization between Android and iOS platforms
10
+ * @param {Object} params Configuration parameters
11
+ * @param {boolean} params.sameContent Whether sync is enabled
12
+ * @param {Function} params.setAndroidContent Android content setter
13
+ * @param {Function} params.setIosContent iOS content setter
14
+ * @param {Function} params.validateTitle Title validation function
15
+ * @param {Function} params.validateMessage Message validation function
16
+ * @param {Function} params.setAndroidTitleError Android title error setter
17
+ * @param {Function} params.setAndroidMessageError Android message error setter
18
+ * @param {Function} params.setIosTitleError iOS title error setter
19
+ * @param {Function} params.setIosMessageError iOS message error setter
20
+ * @param {Object} params.androidContent Current Android content
21
+ * @param {Object} params.iosContent Current iOS content
22
+ * @param {Function} params.updateOnMpushImageReUpload Image re-upload handler
23
+ * @param {Function} params.updateOnMpushVideoReUpload Video re-upload handler
24
+ * @param {Object} params.changeSourceRef Ref to track last changed platform
25
+ */
26
+ const DEBOUNCE_DELAY = 500;
27
+
28
+ const usePlatformSync = ({
29
+ setAndroidContent,
30
+ setIosContent,
31
+ validateTitle,
32
+ validateMessage,
33
+ setAndroidTitleError,
34
+ setAndroidMessageError,
35
+ setIosTitleError,
36
+ setIosMessageError,
37
+ androidContent,
38
+ iosContent,
39
+ updateOnMpushImageReUpload,
40
+ updateOnMpushVideoReUpload,
41
+ sameContent,
42
+ changeSourceRef,
43
+ }) => {
44
+ // Debounce refs
45
+ const debounceTimeoutRef = useRef(null);
46
+
47
+ // Debounced sync effect
48
+ useEffect(() => {
49
+ if (!sameContent || !changeSourceRef?.current) return undefined;
50
+ if (debounceTimeoutRef.current) clearTimeout(debounceTimeoutRef.current);
51
+ debounceTimeoutRef.current = setTimeout(() => {
52
+ if (changeSourceRef.current === 'android') {
53
+ setIosContent(androidContent);
54
+ } else if (changeSourceRef.current === 'ios') {
55
+ setAndroidContent(iosContent);
56
+ }
57
+ }, DEBOUNCE_DELAY);
58
+ return () => {
59
+ if (debounceTimeoutRef.current) clearTimeout(debounceTimeoutRef.current);
60
+ };
61
+ // eslint-disable-next-line react-hooks/exhaustive-deps
62
+ }, [androidContent, iosContent, sameContent]);
63
+
64
+ // Utility to deeply sync content between platforms (except platform-specific fields)
65
+ const deepSyncContent = useCallback((sourceContent, targetContent, targetPlatform) => {
66
+ // Deep copy all fields except platform-specific ones
67
+ const synced = {
68
+ ...targetContent,
69
+ ...sourceContent,
70
+ // For buttons, remap platform property
71
+ buttons: Array.isArray(sourceContent.buttons)
72
+ ? sourceContent.buttons.map((btn) => ({
73
+ ...btn,
74
+ platform: targetPlatform,
75
+ }))
76
+ : [],
77
+ };
78
+ return synced;
79
+ }, []);
80
+
81
+ // Handle title changes
82
+ const handleTitleChange = useCallback((platform, value) => {
83
+ const setContent = platform === ANDROID ? setAndroidContent : setIosContent;
84
+ const setError = platform === ANDROID ? setAndroidTitleError : setIosTitleError;
85
+ const otherSetContent = platform === ANDROID ? setIosContent : setAndroidContent;
86
+ const otherSetError = platform === ANDROID ? setIosTitleError : setAndroidTitleError;
87
+ const otherContent = platform === ANDROID ? iosContent : androidContent;
88
+ const refObj = changeSourceRef;
89
+ if (refObj && Object.prototype.hasOwnProperty.call(refObj, 'current')) {
90
+ refObj.current = platform === ANDROID ? 'android' : 'ios';
91
+ }
92
+ const currentContent = platform === ANDROID ? androidContent : iosContent;
93
+ const newContent = { ...currentContent, title: value };
94
+ setContent(newContent);
95
+ setError(validateTitle(value));
96
+ if (sameContent) {
97
+ const targetPlatform = platform === ANDROID ? IOS : ANDROID;
98
+ const synced = deepSyncContent(newContent, otherContent, targetPlatform);
99
+ otherSetContent(synced);
100
+ otherSetError(validateTitle(value));
101
+ }
102
+ }, [setAndroidContent, setIosContent, setAndroidTitleError, setIosTitleError, validateTitle, changeSourceRef, sameContent, androidContent, iosContent, deepSyncContent]);
103
+
104
+ // Handle message changes
105
+ const handleMessageChange = useCallback((platform, value) => {
106
+ const setContent = platform === ANDROID ? setAndroidContent : setIosContent;
107
+ const setError = platform === ANDROID ? setAndroidMessageError : setIosMessageError;
108
+ const otherSetContent = platform === ANDROID ? setIosContent : setAndroidContent;
109
+ const otherSetError = platform === ANDROID ? setIosMessageError : setAndroidMessageError;
110
+ const otherContent = platform === ANDROID ? iosContent : androidContent;
111
+ const refObj = changeSourceRef;
112
+ if (refObj && Object.prototype.hasOwnProperty.call(refObj, 'current')) {
113
+ refObj.current = platform === ANDROID ? 'android' : 'ios';
114
+ }
115
+ const currentContent = platform === ANDROID ? androidContent : iosContent;
116
+ const newContent = { ...currentContent, message: value };
117
+ setContent(newContent);
118
+ setError(validateMessage(value));
119
+ if (sameContent) {
120
+ const targetPlatform = platform === ANDROID ? IOS : ANDROID;
121
+ const synced = deepSyncContent(newContent, otherContent, targetPlatform);
122
+ otherSetContent(synced);
123
+ otherSetError(validateMessage(value));
124
+ }
125
+ }, [setAndroidContent, setIosContent, setAndroidMessageError, setIosMessageError, validateMessage, changeSourceRef, sameContent, androidContent, iosContent, deepSyncContent]);
126
+
127
+ // Handle media type changes
128
+ const handleMediaTypeChange = useCallback((platform, value) => {
129
+ const setContent = platform === ANDROID ? setAndroidContent : setIosContent;
130
+ const otherSetContent = platform === ANDROID ? setIosContent : setAndroidContent;
131
+ const otherContent = platform === ANDROID ? iosContent : androidContent;
132
+ const currentContent = platform === ANDROID ? androidContent : iosContent;
133
+ const previousMediaType = currentContent.mediaType;
134
+ if (previousMediaType !== value) {
135
+ if ((previousMediaType === VIDEO || previousMediaType === GIF)
136
+ && (value === IMAGE || value === NONE)) {
137
+ updateOnMpushVideoReUpload();
138
+ } else if ((previousMediaType === VIDEO && value === GIF)
139
+ || (previousMediaType === GIF && value === VIDEO)) {
140
+ updateOnMpushVideoReUpload();
141
+ } else if (previousMediaType === IMAGE
142
+ && (value === VIDEO || value === GIF)) {
143
+ updateOnMpushImageReUpload();
144
+ }
145
+ }
146
+ const newContent = { ...currentContent, mediaType: value };
147
+ setContent(newContent);
148
+ if (sameContent) {
149
+ const targetPlatform = platform === ANDROID ? IOS : ANDROID;
150
+ const synced = deepSyncContent(newContent, otherContent, targetPlatform);
151
+ otherSetContent(synced);
152
+ }
153
+ }, [sameContent, setAndroidContent, setIosContent, updateOnMpushImageReUpload, updateOnMpushVideoReUpload, androidContent, iosContent, deepSyncContent]);
154
+
155
+ // Handle tag selection
156
+ const handleTagSelect = useCallback((platform, tag, isTitle) => {
157
+ const setContent = platform === ANDROID ? setAndroidContent : setIosContent;
158
+ const otherSetContent = platform === ANDROID ? setIosContent : setAndroidContent;
159
+ const otherSetError = platform === ANDROID ? setIosTitleError : setAndroidTitleError;
160
+ const otherContent = platform === ANDROID ? iosContent : androidContent;
161
+ const field = isTitle ? 'title' : 'message';
162
+ let setError;
163
+ let validate;
164
+ if (isTitle) {
165
+ setError = platform === ANDROID ? setAndroidTitleError : setIosTitleError;
166
+ validate = validateTitle;
167
+ } else {
168
+ setError = platform === ANDROID ? setAndroidMessageError : setIosMessageError;
169
+ validate = validateMessage;
170
+ }
171
+ const currentContent = platform === ANDROID ? androidContent : iosContent;
172
+ const newValue = `${(currentContent[field] || '')}{{${tag}}}`;
173
+ const newContent = { ...currentContent, [field]: newValue };
174
+ setContent(newContent);
175
+ setError(validate(newValue));
176
+ if (sameContent) {
177
+ const targetPlatform = platform === ANDROID ? IOS : ANDROID;
178
+ const synced = deepSyncContent(newContent, otherContent, targetPlatform);
179
+ otherSetContent(synced);
180
+ otherSetError(validate(newValue));
181
+ }
182
+ }, [androidContent, iosContent, setAndroidContent, setIosContent, setAndroidTitleError, setIosTitleError, setAndroidMessageError, setIosMessageError, validateTitle, validateMessage, sameContent, deepSyncContent]);
183
+
184
+ // Handle CTA/button changes
185
+ const handleButtonChange = useCallback((platform, buttons) => {
186
+ const setContent = platform === ANDROID ? setAndroidContent : setIosContent;
187
+ const otherSetContent = platform === ANDROID ? setIosContent : setAndroidContent;
188
+ const otherContent = platform === ANDROID ? iosContent : androidContent;
189
+ const currentContent = platform === ANDROID ? androidContent : iosContent;
190
+ const newContent = { ...currentContent, buttons };
191
+ setContent(newContent);
192
+ if (sameContent) {
193
+ const targetPlatform = platform === ANDROID ? IOS : ANDROID;
194
+ const mappedButtons = Array.isArray(buttons)
195
+ ? buttons.map((btn) => ({
196
+ ...btn,
197
+ platform: targetPlatform,
198
+ }))
199
+ : [];
200
+ const synced = deepSyncContent({ ...newContent, buttons: mappedButtons }, otherContent, targetPlatform);
201
+ otherSetContent(synced);
202
+ }
203
+ }, [androidContent, iosContent, setAndroidContent, setIosContent, sameContent, deepSyncContent]);
204
+
205
+ // Handle action on click changes
206
+ const handleActionOnClickChange = useCallback((platform, checked) => {
207
+ const setContent = platform === ANDROID ? setAndroidContent : setIosContent;
208
+ const otherSetContent = platform === ANDROID ? setIosContent : setAndroidContent;
209
+ const otherContent = platform === ANDROID ? iosContent : androidContent;
210
+ const currentContent = platform === ANDROID ? androidContent : iosContent;
211
+ const newContent = { ...currentContent, actionOnClick: checked };
212
+ setContent(newContent);
213
+ if (sameContent) {
214
+ const targetPlatform = platform === ANDROID ? IOS : ANDROID;
215
+ const synced = deepSyncContent(newContent, otherContent, targetPlatform);
216
+ otherSetContent(synced);
217
+ }
218
+ }, [androidContent, iosContent, setAndroidContent, setIosContent, sameContent, deepSyncContent]);
219
+
220
+ // Handle link type changes
221
+ const handleLinkTypeChange = useCallback((platform, linkType) => {
222
+ const setContent = platform === ANDROID ? setAndroidContent : setIosContent;
223
+ const otherSetContent = platform === ANDROID ? setIosContent : setAndroidContent;
224
+ const otherContent = platform === ANDROID ? iosContent : androidContent;
225
+ const currentContent = platform === ANDROID ? androidContent : iosContent;
226
+ const newContent = { ...currentContent, linkType, deepLinkValue: '', externalLinkValue: '' };
227
+ setContent(newContent);
228
+ if (sameContent) {
229
+ const targetPlatform = platform === ANDROID ? IOS : ANDROID;
230
+ const synced = deepSyncContent(newContent, otherContent, targetPlatform);
231
+ otherSetContent(synced);
232
+ }
233
+ }, [androidContent, iosContent, setAndroidContent, setIosContent, sameContent, deepSyncContent]);
234
+
235
+ return {
236
+ handleTitleChange,
237
+ handleMessageChange,
238
+ handleTagSelect,
239
+ handleMediaTypeChange,
240
+ handleButtonChange,
241
+ handleActionOnClickChange,
242
+ handleLinkTypeChange,
243
+ };
244
+ };
245
+
246
+ export default usePlatformSync;