@capillarytech/creatives-library 8.0.329 → 8.0.330-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 (89) hide show
  1. package/constants/unified.js +4 -0
  2. package/package.json +1 -1
  3. package/utils/commonUtils.js +19 -1
  4. package/utils/templateVarUtils.js +35 -6
  5. package/utils/tests/tagValidations.test.js +20 -0
  6. package/utils/tests/templateVarUtils.test.js +44 -0
  7. package/v2Components/CapActionButton/constants.js +7 -0
  8. package/v2Components/CapActionButton/index.js +167 -109
  9. package/v2Components/CapActionButton/index.scss +157 -6
  10. package/v2Components/CapActionButton/messages.js +19 -3
  11. package/v2Components/CapActionButton/tests/index.test.js +41 -17
  12. package/v2Components/CapTagList/index.js +28 -23
  13. package/v2Components/CapTagList/style.scss +29 -0
  14. package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
  15. package/v2Components/CapTagListWithInput/index.js +4 -0
  16. package/v2Components/CapWhatsappCTA/index.js +2 -0
  17. package/v2Components/CommonTestAndPreview/ExistingCustomerModal.js +1 -0
  18. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +160 -15
  19. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js.rej +18 -0
  20. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +323 -77
  21. package/v2Components/CommonTestAndPreview/index.js +49 -57
  22. package/v2Components/CommonTestAndPreview/messages.js +8 -0
  23. package/v2Components/CommonTestAndPreview/reducer.js +3 -1
  24. package/v2Components/CommonTestAndPreview/sagas.js +2 -1
  25. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
  26. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
  27. package/v2Components/FormBuilder/index.js +1 -0
  28. package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
  29. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
  30. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
  31. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
  32. package/v2Components/SmsFallback/smsFallbackUtils.js +14 -3
  33. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +16 -0
  34. package/v2Components/TemplatePreview/_templatePreview.scss +33 -23
  35. package/v2Components/TemplatePreview/constants.js +2 -0
  36. package/v2Components/TemplatePreview/index.js +143 -28
  37. package/v2Components/TemplatePreview/tests/index.test.js +142 -0
  38. package/v2Components/TestAndPreviewSlidebox/index.js +5 -0
  39. package/v2Components/mockdata.js +1 -0
  40. package/v2Containers/BeeEditor/index.js +19 -1
  41. package/v2Containers/CreativesContainer/SlideBoxContent.js +28 -1
  42. package/v2Containers/CreativesContainer/index.js +9 -3
  43. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +5 -0
  44. package/v2Containers/Email/index.js +78 -39
  45. package/v2Containers/Email/reducer.js +2 -2
  46. package/v2Containers/Email/sagas.js +3 -1
  47. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -2
  48. package/v2Containers/Email/tests/sagas.test.js +230 -0
  49. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +6 -1
  50. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
  51. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
  52. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
  53. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -1
  54. package/v2Containers/EmailWrapper/index.js +4 -0
  55. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
  56. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
  57. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +1 -0
  58. package/v2Containers/MobilePush/Create/index.js +2 -0
  59. package/v2Containers/MobilePush/Edit/index.js +2 -0
  60. package/v2Containers/MobilepushWrapper/index.js +3 -1
  61. package/v2Containers/Rcs/constants.js +85 -7
  62. package/v2Containers/Rcs/index.js +1592 -156
  63. package/v2Containers/Rcs/index.js.rej +1336 -0
  64. package/v2Containers/Rcs/index.scss +191 -0
  65. package/v2Containers/Rcs/index.scss.rej +74 -0
  66. package/v2Containers/Rcs/messages.js +28 -2
  67. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +20 -0
  68. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +69178 -117691
  69. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap.rej +128 -0
  70. package/v2Containers/Rcs/tests/index.test.js +132 -94
  71. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +67 -0
  72. package/v2Containers/Rcs/tests/utils.test.js +276 -38
  73. package/v2Containers/Rcs/utils.js +130 -7
  74. package/v2Containers/Sms/Edit/index.js +2 -0
  75. package/v2Containers/SmsTrai/Edit/index.js +27 -0
  76. package/v2Containers/SmsTrai/Edit/messages.js +5 -0
  77. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
  78. package/v2Containers/SmsWrapper/index.js +2 -0
  79. package/v2Containers/TagList/index.js +73 -20
  80. package/v2Containers/TagList/messages.js +4 -0
  81. package/v2Containers/TagList/tests/TagList.test.js +124 -20
  82. package/v2Containers/TagList/tests/mockdata.js +17 -0
  83. package/v2Containers/Templates/_templates.scss +99 -0
  84. package/v2Containers/Templates/index.js +29 -14
  85. package/v2Containers/Viber/index.js +3 -0
  86. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
  87. package/v2Containers/WebPush/Create/index.js +10 -2
  88. package/v2Containers/Whatsapp/index.js +5 -0
  89. package/v2Containers/Zalo/index.js +2 -0
@@ -168,6 +168,10 @@ export const COMBINED_SMS_TEMPLATE_VAR_REGEX = /\{\{[^}]+\}\}|\{\#[^#]*\#\}/g;
168
168
  export const MUSTACHE_VAR_TOKEN_FULL_STRING_REGEX = /^\{\{[^}]+\}\}$/;
169
169
  /** Full-string check: one DLT hash token. */
170
170
  export const DLT_HASH_VAR_TOKEN_FULL_STRING_REGEX = /^\{\#[^#]*\#\}$/;
171
+ /** Full-string with capture group: inner name for `{{ name }}`-style tokens (whitespace-tolerant). */
172
+ export const MUSTACHE_TOKEN_INNER_NAME_REGEX = /^\{\{\s*([^}]+?)\s*\}\}$/;
173
+ /** Full-string with capture group: inner name/body for `{# name #}` DLT tokens (whitespace-tolerant). */
174
+ export const DLT_HASH_TOKEN_INNER_NAME_REGEX = /^\{#\s*(.*?)\s*#\}$/;
171
175
  /** Global with capture group: inner name inside `{{name}}`. */
172
176
  export const MUSTACHE_VAR_NAME_CAPTURE_REGEX = /\{\{([^}]+)\}\}/g;
173
177
  /** Global with capture group: inner body inside `{#body#}`. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.329",
4
+ "version": "8.0.330-alpha.1",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -539,4 +539,22 @@ export const isValidMobile = (mobile) => PHONE_REGEX.test(mobile);
539
539
  export const formatPhoneNumber = (phone) => {
540
540
  if (!phone) return '';
541
541
  return String(phone).replace(/[^\d]/g, '');
542
- };
542
+ };
543
+
544
+ /**
545
+ * TRAI sender IDs on persisted RCS SMS fallback: may live on the merged object, under
546
+ * `templateConfigs`, or (legacy) `templateConfigs.header`. Same resolution order as
547
+ * `createPayload` in `Rcs/index.js`.
548
+ */
549
+ export function extractRegisteredSenderIdsFromSmsFallbackRecord(record) {
550
+ if (!record || typeof record !== 'object') return null;
551
+ const tc = record.templateConfigs && typeof record.templateConfigs === 'object'
552
+ ? record.templateConfigs
553
+ : {};
554
+ const candidates = [record.registeredSenderIds, tc.registeredSenderIds, tc.header];
555
+ for (let i = 0; i < candidates.length; i += 1) {
556
+ const a = candidates[i];
557
+ if (Array.isArray(a) && a.length > 0) return a;
558
+ }
559
+ return null;
560
+ }
@@ -7,7 +7,9 @@ import {
7
7
  COMBINED_SMS_TEMPLATE_VAR_REGEX,
8
8
  DEFAULT_MUSTACHE_VAR_REGEX,
9
9
  DLT_HASH_VAR_TOKEN_FULL_STRING_REGEX,
10
+ DLT_HASH_TOKEN_INNER_NAME_REGEX,
10
11
  DLT_VAR_BODY_CAPTURE_REGEX,
12
+ MUSTACHE_TOKEN_INNER_NAME_REGEX,
11
13
  MUSTACHE_VAR_NAME_CAPTURE_REGEX,
12
14
  MUSTACHE_VAR_TOKEN_FULL_STRING_REGEX,
13
15
  } from '../constants/unified';
@@ -115,13 +117,36 @@ export const extractTemplateVariables = (templateStr = '', captureRegex) => {
115
117
  return variables;
116
118
  };
117
119
 
120
+ /**
121
+ * Looks up the inner name of a `{{name}}` or `{#name#}` token in a flat key→value map.
122
+ * Handles both exact matches and dot-path suffixes (e.g. `tag.FORMAT_1` → name `FORMAT_1`).
123
+ * Returns the resolved string value, or `undefined` if not found / blank.
124
+ */
125
+ function resolveUserVarForToken(segment, userVarMap) {
126
+ if (!userVarMap || typeof userVarMap !== 'object') return undefined;
127
+ const mMustache = segment.match(MUSTACHE_TOKEN_INNER_NAME_REGEX);
128
+ const mDlt = segment.match(DLT_HASH_TOKEN_INNER_NAME_REGEX);
129
+ const innerName = ((mMustache ? mMustache[1] : (mDlt ? mDlt[1] : '')) ?? '').trim();
130
+ if (!innerName) return undefined;
131
+ const direct = userVarMap[innerName];
132
+ if (direct != null && String(direct).trim() !== '') return String(direct);
133
+ const hit = Object.keys(userVarMap).find((k) => k === innerName || k.endsWith(`.${innerName}`));
134
+ if (hit != null && userVarMap[hit] != null && String(userVarMap[hit]).trim() !== '') return String(userVarMap[hit]);
135
+ return undefined;
136
+ }
137
+
118
138
  /**
119
139
  * SMS / DLT template preview: replace `{{…}}` / `{#…#}` tokens using `varMapData` keys `${token}_${index}`.
120
140
  * Used by SmsTraiEdit (RCS SMS fallback) and UnifiedPreview fallback SMS bubble.
121
141
  * DLT `{#…#}`: empty / unset slot values show the raw token (matches DLT preview UX); mustache `{{…}}` still
122
142
  * resolves to empty when the slot is cleared.
143
+ *
144
+ * @param {string} templateStr
145
+ * @param {Object} varMapData - Slot map (`${token}_${index}` → value)
146
+ * @param {Object|null} [userVarMap] - Optional Test & Preview custom values; used as fallback when a slot
147
+ * is absent or blank. When omitted the function behaves identically to its original two-argument form.
123
148
  */
124
- export const getFallbackResolvedContent = (templateStr = '', varMapData = {}) => {
149
+ export const getFallbackResolvedContent = (templateStr = '', varMapData = {}, userVarMap = null) => {
125
150
  const fallbackVarSlotMap = varMapData ?? {};
126
151
  const templateSegments = splitTemplateVarString(templateStr, COMBINED_SMS_TEMPLATE_VAR_REGEX);
127
152
  return templateSegments
@@ -132,13 +157,17 @@ export const getFallbackResolvedContent = (templateStr = '', varMapData = {}) =>
132
157
  if (Object.prototype.hasOwnProperty.call(fallbackVarSlotMap, slotKey)) {
133
158
  const slotValue = fallbackVarSlotMap[slotKey];
134
159
  if (isDltHashVarToken(segment)) {
135
- if (slotValue == null) return segment;
136
- const str = String(slotValue);
137
- if (str.trim() === '') return segment;
138
- return str;
160
+ if (slotValue == null || String(slotValue).trim() === '') {
161
+ if (userVarMap) { const uv = resolveUserVarForToken(segment, userVarMap); if (uv !== undefined) return uv; }
162
+ return segment;
163
+ }
164
+ return String(slotValue);
139
165
  }
140
- return slotValue == null ? '' : String(slotValue);
166
+ if (slotValue != null && String(slotValue).trim() !== '') return String(slotValue);
167
+ if (userVarMap) { const uv = resolveUserVarForToken(segment, userVarMap); if (uv !== undefined) return uv; }
168
+ return '';
141
169
  }
170
+ if (userVarMap) { const uv = resolveUserVarForToken(segment, userVarMap); if (uv !== undefined) return uv; }
142
171
  if (isDltHashVarToken(segment)) return segment;
143
172
  return '';
144
173
  })
@@ -360,6 +360,26 @@ describe("validateTags", () => {
360
360
  expect(resultWhitespace.valid).toBe(true);
361
361
  expect(resultWhitespace.unsupportedTags ?? []).toEqual([]);
362
362
  });
363
+
364
+ it('should treat tags from waitEventContextTags as supported', () => {
365
+ const content = 'Hello {{waitEvent.orderId}}';
366
+ const tagsParam = [];
367
+ const injectedTagsParams = [];
368
+ const location = { query: { module: 'DEFAULT' } };
369
+ const tagModule = null;
370
+
371
+ const result = validateTags({
372
+ content,
373
+ tagsParam,
374
+ injectedTagsParams,
375
+ location,
376
+ tagModule,
377
+ });
378
+
379
+ expect(result.valid).toEqual(true);
380
+ expect(result.missingTags).toEqual([]);
381
+ expect(result.isBraceError).toEqual(false);
382
+ });
363
383
  });
364
384
 
365
385
  describe('validateTags wrapper (v2 consumers)', () => {
@@ -157,4 +157,48 @@ describe('templateVarUtils', () => {
157
157
  expect(extractTemplateVariables('{{x}} {{y}}', globalRe)).toEqual(['x', 'y']);
158
158
  });
159
159
  });
160
+
161
+ describe('getFallbackResolvedContent — userVarMap (third param)', () => {
162
+ it('falls back to userVarMap for mustache slot absent from varMapData', () => {
163
+ expect(getFallbackResolvedContent('Hi {{name}}', {}, { name: 'Alice' })).toBe('Hi Alice');
164
+ });
165
+
166
+ it('falls back to userVarMap for DLT slot absent from varMapData', () => {
167
+ expect(getFallbackResolvedContent('{#city#}', {}, { city: 'Mumbai' })).toBe('Mumbai');
168
+ });
169
+
170
+ it('falls back to userVarMap when mustache slot is present but blank', () => {
171
+ expect(getFallbackResolvedContent('{{x}}', { '{{x}}_0': '' }, { x: 'val' })).toBe('val');
172
+ });
173
+
174
+ it('falls back to userVarMap when DLT slot is present but blank', () => {
175
+ expect(getFallbackResolvedContent('{#x#}', { '{#x#}_0': '' }, { x: 'val' })).toBe('val');
176
+ });
177
+
178
+ it('slot wins over userVarMap when mustache slot is non-empty', () => {
179
+ expect(getFallbackResolvedContent('{{x}}', { '{{x}}_0': 'slot-val' }, { x: 'user-val' })).toBe('slot-val');
180
+ });
181
+
182
+ it('slot wins over userVarMap when DLT slot is non-empty', () => {
183
+ expect(getFallbackResolvedContent('{#x#}', { '{#x#}_0': 'slot' }, { x: 'user' })).toBe('slot');
184
+ });
185
+
186
+ it('resolves dot-path suffix key from userVarMap', () => {
187
+ expect(
188
+ getFallbackResolvedContent('{{FORMAT_1}}', {}, { 'expiry.FORMAT_1': 'Dec 2025' }),
189
+ ).toBe('Dec 2025');
190
+ });
191
+
192
+ it('userVarMap null behaves identically to the two-argument form', () => {
193
+ expect(getFallbackResolvedContent('{{a}}', { '{{a}}_0': 'x' }, null)).toBe('x');
194
+ });
195
+
196
+ it('blank userVarMap value leaves mustache token as empty string', () => {
197
+ expect(getFallbackResolvedContent('{{a}}', {}, { a: '' })).toBe('');
198
+ });
199
+
200
+ it('blank userVarMap value leaves DLT token as raw token', () => {
201
+ expect(getFallbackResolvedContent('{#a#}', {}, { a: '' })).toBe('{#a#}');
202
+ });
203
+ });
160
204
  });
@@ -32,6 +32,13 @@ export const CTA_OPTIONS = [
32
32
  ];
33
33
 
34
34
  export const invalidVarRegex = /{{(.*?)}}/g;
35
+
36
+ /** URL CTA subtype (Figma: URL type dropdown). */
37
+ export const RCS_CTA_URL_TYPE = {
38
+ STATIC: 'STATIC',
39
+ DYNAMIC: 'DYNAMIC',
40
+ };
41
+
35
42
  export const BTN_MAX_LENGTH = 25;
36
43
  export const PHONE_NUMBER_MAX_LENGTH = 15;
37
44
  export const URL_MAX_LENGTH = 2000;