@capillarytech/creatives-library 8.0.353-alpha.6 → 8.0.354

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 (127) hide show
  1. package/constants/unified.js +0 -29
  2. package/index.html +1 -0
  3. package/package.json +1 -1
  4. package/services/tests/api.test.js +20 -35
  5. package/utils/cdnTransformation.js +63 -3
  6. package/utils/commonUtils.js +1 -19
  7. package/utils/tests/cdnTransformation.test.js +111 -0
  8. package/v2Components/CapActionButton/constants.js +0 -7
  9. package/v2Components/CapActionButton/index.js +108 -166
  10. package/v2Components/CapActionButton/index.scss +6 -157
  11. package/v2Components/CapActionButton/messages.js +3 -19
  12. package/v2Components/CapActionButton/tests/index.test.js +17 -41
  13. package/v2Components/CapTagList/index.js +0 -10
  14. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -72
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -213
  17. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  20. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
  21. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  22. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +15 -157
  23. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -346
  24. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
  25. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  26. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  27. package/v2Components/CommonTestAndPreview/index.js +186 -691
  28. package/v2Components/CommonTestAndPreview/messages.js +3 -45
  29. package/v2Components/CommonTestAndPreview/sagas.js +6 -25
  30. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -308
  31. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  32. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  33. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  34. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  35. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  36. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  37. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  38. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -132
  39. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +26 -36
  40. package/v2Components/FormBuilder/index.js +6 -11
  41. package/v2Components/TemplatePreview/_templatePreview.scss +23 -38
  42. package/v2Components/TemplatePreview/index.js +31 -143
  43. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  44. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  45. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  46. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  47. package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
  48. package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
  49. package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
  50. package/v2Containers/CreativesContainer/constants.js +0 -9
  51. package/v2Containers/CreativesContainer/index.js +103 -322
  52. package/v2Containers/CreativesContainer/index.scss +1 -51
  53. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
  54. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  55. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  56. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
  57. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  58. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  59. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  60. package/v2Containers/Rcs/constants.js +10 -119
  61. package/v2Containers/Rcs/index.js +818 -2450
  62. package/v2Containers/Rcs/index.scss +8 -280
  63. package/v2Containers/Rcs/messages.js +3 -34
  64. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +70073 -98018
  65. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
  66. package/v2Containers/Rcs/tests/index.test.js +121 -152
  67. package/v2Containers/Rcs/tests/mockData.js +0 -38
  68. package/v2Containers/Rcs/tests/utils.test.js +30 -646
  69. package/v2Containers/Rcs/utils.js +11 -478
  70. package/v2Containers/Sms/Create/index.js +40 -106
  71. package/v2Containers/SmsTrai/Create/index.js +4 -9
  72. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  73. package/v2Containers/SmsTrai/Edit/index.js +130 -640
  74. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  75. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2296 -4249
  76. package/v2Containers/SmsWrapper/index.js +8 -37
  77. package/v2Containers/TagList/index.js +0 -6
  78. package/v2Containers/Templates/_templates.scss +9 -166
  79. package/v2Containers/Templates/actions.js +0 -11
  80. package/v2Containers/Templates/constants.js +0 -2
  81. package/v2Containers/Templates/index.js +52 -120
  82. package/v2Containers/Templates/sagas.js +18 -57
  83. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1017 -1062
  84. package/v2Containers/Templates/tests/sagas.test.js +39 -205
  85. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
  86. package/v2Containers/TemplatesV2/index.js +23 -86
  87. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  88. package/v2Containers/Whatsapp/index.js +20 -3
  89. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  90. package/utils/rcsPayloadUtils.js +0 -92
  91. package/utils/templateVarUtils.js +0 -201
  92. package/utils/tests/rcsPayloadUtils.test.js +0 -226
  93. package/utils/tests/templateVarUtils.test.js +0 -204
  94. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  95. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  96. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
  97. package/v2Components/SmsFallback/constants.js +0 -73
  98. package/v2Components/SmsFallback/index.js +0 -956
  99. package/v2Components/SmsFallback/index.scss +0 -265
  100. package/v2Components/SmsFallback/messages.js +0 -78
  101. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -119
  102. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  103. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  104. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  105. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -223
  106. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
  107. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  108. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  109. package/v2Components/TemplatePreview/constants.js +0 -2
  110. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  111. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  112. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  113. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
  114. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
  115. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  116. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  117. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  118. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
  119. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  120. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  121. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  122. package/v2Containers/SmsTrai/Edit/index.scss +0 -121
  123. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  124. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  125. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  126. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  127. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
@@ -1,253 +0,0 @@
1
- import {
2
- getSmsMessageFromFormData,
3
- getSmsEmbeddedFooterValidity,
4
- } from '../smsFormDataHelpers';
5
-
6
- // ---------------------------------------------------------------------------
7
- // getSmsMessageFromFormData
8
- // ---------------------------------------------------------------------------
9
-
10
- describe('getSmsMessageFromFormData', () => {
11
- describe('null / invalid formData guard', () => {
12
- it('returns empty string when formData is null', () => {
13
- expect(getSmsMessageFromFormData(null, 1)).toBe('');
14
- });
15
-
16
- it('returns empty string when formData is undefined', () => {
17
- expect(getSmsMessageFromFormData(undefined, 1)).toBe('');
18
- });
19
-
20
- it('returns empty string when formData is a string (not an object)', () => {
21
- expect(getSmsMessageFromFormData('bad', 1)).toBe('');
22
- });
23
-
24
- it('returns empty string when formData is a number', () => {
25
- expect(getSmsMessageFromFormData(42, 1)).toBe('');
26
- });
27
- });
28
-
29
- describe('currentTab normalisation', () => {
30
- it('defaults to tab 1 when currentTab is null', () => {
31
- const formData = { 0: { 'sms-editor': 'hello' } };
32
- expect(getSmsMessageFromFormData(formData, null)).toBe('hello');
33
- });
34
-
35
- it('defaults to tab 1 when currentTab is undefined', () => {
36
- const formData = { 0: { 'sms-editor': 'hello' } };
37
- expect(getSmsMessageFromFormData(formData, undefined)).toBe('hello');
38
- });
39
-
40
- it('defaults to tab 1 when currentTab is 0', () => {
41
- const formData = { 0: { 'sms-editor': 'hello' } };
42
- expect(getSmsMessageFromFormData(formData, 0)).toBe('hello');
43
- });
44
-
45
- it('defaults to tab 1 when currentTab is negative', () => {
46
- const formData = { 0: { 'sms-editor': 'hello' } };
47
- expect(getSmsMessageFromFormData(formData, -5)).toBe('hello');
48
- });
49
- });
50
-
51
- describe('versioned key lookup', () => {
52
- it('uses "sms-editor" key for tab 1', () => {
53
- const formData = { 0: { 'sms-editor': 'tab1 msg' } };
54
- expect(getSmsMessageFromFormData(formData, 1)).toBe('tab1 msg');
55
- });
56
-
57
- it('uses "sms-editor2" versioned key for tab 2', () => {
58
- const formData = { 1: { 'sms-editor2': 'tab2 msg', 'sms-editor': 'fallback' } };
59
- expect(getSmsMessageFromFormData(formData, 2)).toBe('tab2 msg');
60
- });
61
-
62
- it('uses "sms-editor3" versioned key for tab 3', () => {
63
- const formData = { 2: { 'sms-editor3': 'tab3 msg' } };
64
- expect(getSmsMessageFromFormData(formData, 3)).toBe('tab3 msg');
65
- });
66
-
67
- it('returns empty string when versioned key exists but is null (cleared version)', () => {
68
- const formData = { 1: { 'sms-editor2': null } };
69
- expect(getSmsMessageFromFormData(formData, 2)).toBe('');
70
- });
71
-
72
- it('returns empty string when versioned key exists but is empty string', () => {
73
- const formData = { 1: { 'sms-editor2': '' } };
74
- expect(getSmsMessageFromFormData(formData, 2)).toBe('');
75
- });
76
-
77
- it('coerces a numeric value in versioned key to string', () => {
78
- const formData = { 1: { 'sms-editor2': 12345 } };
79
- expect(getSmsMessageFromFormData(formData, 2)).toBe('12345');
80
- });
81
- });
82
-
83
- describe('"sms-editor" flat key fallback (versioned key absent)', () => {
84
- it('falls back to "sms-editor" when versioned key is absent for tab 2', () => {
85
- const formData = { 1: { 'sms-editor': 'flat fallback' } };
86
- expect(getSmsMessageFromFormData(formData, 2)).toBe('flat fallback');
87
- });
88
- });
89
-
90
- describe('activeTab nested fallback', () => {
91
- it('falls back to activeTab["sms-editor"] when neither versioned key nor flat "sms-editor" is present', () => {
92
- // The versioned key must be absent entirely for the activeTab fallback to be reached.
93
- // (If 'sms-editor' exists but is null, the function commits to '' without falling through.)
94
- const formData = {
95
- 0: {
96
- activeTab: 'variant1',
97
- variant1: { 'sms-editor': 'variant msg' },
98
- },
99
- };
100
- expect(getSmsMessageFromFormData(formData, 1)).toBe('variant msg');
101
- });
102
-
103
- it('falls back to base["sms-editor"] when activeTab entry lacks "sms-editor" and flat key is absent', () => {
104
- const formData = {
105
- 0: {
106
- activeTab: 'variant1',
107
- variant1: {},
108
- base: { 'sms-editor': 'base msg' },
109
- },
110
- };
111
- expect(getSmsMessageFromFormData(formData, 1)).toBe('base msg');
112
- });
113
-
114
- it('defaults activeTab to "base" when activeTab prop is not set and flat key is absent', () => {
115
- const formData = {
116
- 0: {
117
- base: { 'sms-editor': 'default base msg' },
118
- },
119
- };
120
- expect(getSmsMessageFromFormData(formData, 1)).toBe('default base msg');
121
- });
122
- });
123
-
124
- describe('root formData.base fallback', () => {
125
- it('falls back to formData.base["sms-editor"] when tab slot is missing', () => {
126
- const formData = {
127
- base: { 'sms-editor': 'root base msg' },
128
- };
129
- expect(getSmsMessageFromFormData(formData, 1)).toBe('root base msg');
130
- });
131
-
132
- it('returns empty string when even root base has no "sms-editor"', () => {
133
- const formData = { base: {} };
134
- expect(getSmsMessageFromFormData(formData, 1)).toBe('');
135
- });
136
-
137
- it('returns empty string when formData has no relevant keys at all', () => {
138
- expect(getSmsMessageFromFormData({}, 1)).toBe('');
139
- });
140
- });
141
- });
142
-
143
- // ---------------------------------------------------------------------------
144
- // getSmsEmbeddedFooterValidity
145
- // ---------------------------------------------------------------------------
146
-
147
- describe('getSmsEmbeddedFooterValidity', () => {
148
- describe('isTemplateNameEmpty', () => {
149
- it('is true when template-name is absent', () => {
150
- const formData = { 0: { 'sms-editor': 'msg' } };
151
- const { isTemplateNameEmpty } = getSmsEmbeddedFooterValidity(formData, 1);
152
- expect(isTemplateNameEmpty).toBe(true);
153
- });
154
-
155
- it('is true when template-name is empty string', () => {
156
- const formData = { 'template-name': '', 0: { 'sms-editor': 'msg' } };
157
- const { isTemplateNameEmpty } = getSmsEmbeddedFooterValidity(formData, 1);
158
- expect(isTemplateNameEmpty).toBe(true);
159
- });
160
-
161
- it('is true when template-name is whitespace only', () => {
162
- const formData = { 'template-name': ' ', 0: { 'sms-editor': 'msg' } };
163
- const { isTemplateNameEmpty } = getSmsEmbeddedFooterValidity(formData, 1);
164
- expect(isTemplateNameEmpty).toBe(true);
165
- });
166
-
167
- it('is false when template-name is a non-empty string', () => {
168
- const formData = { 'template-name': 'My Template', 0: { 'sms-editor': 'msg' } };
169
- const { isTemplateNameEmpty } = getSmsEmbeddedFooterValidity(formData, 1);
170
- expect(isTemplateNameEmpty).toBe(false);
171
- });
172
- });
173
-
174
- describe('isMessageEmpty — single tab', () => {
175
- it('is true when message is empty string', () => {
176
- const formData = { 'template-name': 'T', 0: { 'sms-editor': '' } };
177
- const { isMessageEmpty } = getSmsEmbeddedFooterValidity(formData, 1);
178
- expect(isMessageEmpty).toBe(true);
179
- });
180
-
181
- it('is true when message is whitespace only', () => {
182
- const formData = { 'template-name': 'T', 0: { 'sms-editor': ' ' } };
183
- const { isMessageEmpty } = getSmsEmbeddedFooterValidity(formData, 1);
184
- expect(isMessageEmpty).toBe(true);
185
- });
186
-
187
- it('is true when no sms-editor key at all', () => {
188
- const formData = { 'template-name': 'T', 0: {} };
189
- const { isMessageEmpty } = getSmsEmbeddedFooterValidity(formData, 1);
190
- expect(isMessageEmpty).toBe(true);
191
- });
192
-
193
- it('is false when message is non-empty', () => {
194
- const formData = { 'template-name': 'T', 0: { 'sms-editor': 'Hello world' } };
195
- const { isMessageEmpty } = getSmsEmbeddedFooterValidity(formData, 1);
196
- expect(isMessageEmpty).toBe(false);
197
- });
198
- });
199
-
200
- describe('isMessageEmpty — multiple tabs', () => {
201
- it('is false when all tabs have non-empty messages', () => {
202
- const formData = {
203
- 'template-name': 'T',
204
- 0: { 'sms-editor': 'Tab 1 message' },
205
- 1: { 'sms-editor2': 'Tab 2 message' },
206
- 2: { 'sms-editor3': 'Tab 3 message' },
207
- };
208
- const { isMessageEmpty } = getSmsEmbeddedFooterValidity(formData, 3);
209
- expect(isMessageEmpty).toBe(false);
210
- });
211
-
212
- it('is true when the second tab has an empty message', () => {
213
- const formData = {
214
- 'template-name': 'T',
215
- 0: { 'sms-editor': 'Tab 1 message' },
216
- 1: { 'sms-editor2': '' },
217
- };
218
- const { isMessageEmpty } = getSmsEmbeddedFooterValidity(formData, 2);
219
- expect(isMessageEmpty).toBe(true);
220
- });
221
-
222
- it('is true when the third tab has no message', () => {
223
- const formData = {
224
- 'template-name': 'T',
225
- 0: { 'sms-editor': 'msg1' },
226
- 1: { 'sms-editor2': 'msg2' },
227
- 2: {},
228
- };
229
- const { isMessageEmpty } = getSmsEmbeddedFooterValidity(formData, 3);
230
- expect(isMessageEmpty).toBe(true);
231
- });
232
-
233
- it('treats tabCount=1 as single-tab check even when not explicitly provided', () => {
234
- const formData = { 'template-name': 'T', 0: { 'sms-editor': 'msg' } };
235
- const { isMessageEmpty } = getSmsEmbeddedFooterValidity(formData);
236
- expect(isMessageEmpty).toBe(false);
237
- });
238
- });
239
-
240
- describe('both fields together', () => {
241
- it('returns both empty when template name absent and message empty', () => {
242
- const formData = { 0: { 'sms-editor': '' } };
243
- const result = getSmsEmbeddedFooterValidity(formData, 1);
244
- expect(result).toEqual({ isTemplateNameEmpty: true, isMessageEmpty: true });
245
- });
246
-
247
- it('returns both non-empty when template name and message are present', () => {
248
- const formData = { 'template-name': 'My Template', 0: { 'sms-editor': 'Hello!' } };
249
- const result = getSmsEmbeddedFooterValidity(formData, 1);
250
- expect(result).toEqual({ isTemplateNameEmpty: false, isMessageEmpty: false });
251
- });
252
- });
253
- });
@@ -1,121 +0,0 @@
1
- @import '~@capillarytech/cap-ui-library/styles/_variables';
2
-
3
- .sms-trai-segmented-editor {
4
- .ant-input {
5
- margin-bottom: 0.125rem;
6
- }
7
- }
8
-
9
- /*
10
- * DLT SMS fallback edit only: mirror RCS rich-card message box (`.cap-rcs-creatives` + default
11
- * VarSegment `rcs-edit-template-message-input` / `rcs-edit-template-message-split`).
12
- */
13
- .sms-trai-edit-rcs-fallback {
14
- width: 100%;
15
-
16
- .rcs_text_area_wrapper {
17
- position: relative;
18
- width: 100%;
19
- }
20
-
21
- .rcs_text_area_wrapper .rcs-edit-template-message-input {
22
- background-color: $CAP_G10;
23
- padding: $CAP_SPACE_12 $CAP_SPACE_16;
24
- }
25
-
26
- .rcs_text_area_wrapper .rcs-edit-template-message-split {
27
- margin-bottom: $CAP_SPACE_08;
28
- overflow: hidden;
29
- text-overflow: ellipsis;
30
- color: $FONT_COLOR_03;
31
- font-weight: 500;
32
- }
33
-
34
- .rcs_text_area_wrapper .rcs-edit-template-message-input .ant-input,
35
- .rcs_text_area_wrapper .rcs-edit-template-message-input textarea.ant-input {
36
- width: 100%;
37
- box-sizing: border-box;
38
- min-height: 2.5rem;
39
- padding-top: $CAP_SPACE_08;
40
- padding-bottom: $CAP_SPACE_08;
41
- border-color: $CAP_G07;
42
- box-shadow: none;
43
- overflow: hidden;
44
- }
45
-
46
- .rcs_text_area_wrapper .rcs-edit-template-message-input .ant-input:focus,
47
- .rcs_text_area_wrapper .rcs-edit-template-message-input .ant-input:active,
48
- .rcs_text_area_wrapper .rcs-edit-template-message-input textarea.ant-input:focus,
49
- .rcs_text_area_wrapper .rcs-edit-template-message-input textarea.ant-input:active {
50
- border-color: $CAP_G07;
51
- box-shadow: none;
52
- outline: none;
53
- }
54
-
55
- /*
56
- * DLT per-slot hint: long selector (under CapSpin + message row) for specificity without !important.
57
- */
58
- .rcs_text_area_wrapper .rcs-edit-template-message-input .var-segment-message-editor__var-slot {
59
- display: flex;
60
- flex-direction: column;
61
- align-items: stretch;
62
- }
63
-
64
- .rcs_text_area_wrapper
65
- .rcs-edit-template-message-input
66
- .var-segment-message-editor__var-slot
67
- span.sms-trai-rcs-fallback-var-hint {
68
- display: block;
69
- box-sizing: border-box;
70
- flex-shrink: 0;
71
- margin-top: $CAP_SPACE_04;
72
- margin-left: auto;
73
- margin-right: 0;
74
- width: fit-content;
75
- max-width: 100%;
76
- text-align: right;
77
- color: $FONT_COLOR_02;
78
- font-weight: 400;
79
- font-size: 0.75rem;
80
- line-height: 1rem;
81
- opacity: 0.92;
82
- }
83
-
84
- /* Footer “1 SMS (n characters)” — match RCS message typography, not muted gray */
85
- .rcs-character-count,
86
- .rcs-character-count--compact {
87
- color: $FONT_COLOR_03;
88
- font-weight: 500;
89
- }
90
- }
91
-
92
- .rcs-character-count {
93
- display: block;
94
- margin-top: $CAP_SPACE_16;
95
- margin-bottom: $CAP_SPACE_04;
96
- text-align: right;
97
- color: $FONT_COLOR_02;
98
- width: 100%;
99
- }
100
-
101
- .rcs-character-count--compact {
102
- font-size: 0.75rem;
103
- line-height: 1rem;
104
- font-weight: 400;
105
- }
106
-
107
- /* Non–RCS fallback: segmented editor shell + character count row (was inline styles on CapRow) */
108
- .sms-trai-editor-segment-row {
109
- background-color: $CAP_G10;
110
- padding: $CAP_SPACE_16;
111
- }
112
-
113
- .sms-trai-length-row {
114
- display: flex;
115
- justify-content: flex-end;
116
- margin-top: $CAP_SPACE_04;
117
- }
118
-
119
- .sms-trai-edit-bottom-spacer {
120
- margin-bottom: 6.25rem;
121
- }
@@ -1,101 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import CapInput from '@capillarytech/cap-ui-library/CapInput';
4
- import CapButton from '@capillarytech/cap-ui-library/CapButton';
5
-
6
- /**
7
- * Reusable action bar for template pickers.
8
- * Layout and spacing live in `_templates.scss` (`.action-container`, `.action-container__toolbar-row`).
9
- * Default search field width: `.action-container__toolbar-row .search-text` (13.125rem).
10
- * Pass `searchInputClassName` / `searchInputStyle` to override (defaults match Templates list: 210px per master).
11
- */
12
- const TemplatesActionBar = ({
13
- searchValue,
14
- onSearchChange,
15
- onSearch,
16
- onClear,
17
- searchPlaceholder,
18
- searchInputClassName,
19
- searchInputStyle,
20
- ctaLabel,
21
- onCtaClick,
22
- ctaDisabled,
23
- ctaClassName,
24
- ctaNode,
25
- children,
26
- showCta = true,
27
- }) => (
28
- <div className="action-container">
29
- <div className="action-container__toolbar-row">
30
- {searchPlaceholder && (
31
- <CapInput.Search
32
- className={['search-text', searchInputClassName].filter(Boolean).join(' ')}
33
- placeholder={searchPlaceholder}
34
- value={searchValue}
35
- onChange={onSearchChange}
36
- /* antd `Input` (used by CapInput.Search) has no `onSearch`; only `Input.Search` does. */
37
- onPressEnter={(e) => {
38
- if (onSearch) {
39
- const v = e?.target && 'value' in e.target ? e.target.value : searchValue;
40
- onSearch(v);
41
- }
42
- }}
43
- onSearch={onSearch}
44
- onClear={onClear}
45
- onScroll={(e) => e.stopPropagation()}
46
- />
47
- )}
48
- {children}
49
- </div>
50
- {showCta && (
51
- <div>
52
- {ctaNode || (
53
- <CapButton
54
- className={ctaClassName}
55
- type="primary"
56
- disabled={ctaDisabled}
57
- onClick={onCtaClick}
58
- >
59
- {ctaLabel}
60
- </CapButton>
61
- )}
62
- </div>
63
- )}
64
- </div>
65
- );
66
-
67
- TemplatesActionBar.propTypes = {
68
- searchValue: PropTypes.string,
69
- onSearchChange: PropTypes.func,
70
- onSearch: PropTypes.func,
71
- onClear: PropTypes.func,
72
- searchPlaceholder: PropTypes.string,
73
- searchInputClassName: PropTypes.string,
74
- searchInputStyle: PropTypes.object,
75
- ctaLabel: PropTypes.node,
76
- onCtaClick: PropTypes.func,
77
- ctaDisabled: PropTypes.bool,
78
- ctaClassName: PropTypes.string,
79
- ctaNode: PropTypes.node,
80
- children: PropTypes.node,
81
- showCta: PropTypes.bool,
82
- };
83
-
84
- TemplatesActionBar.defaultProps = {
85
- searchValue: '',
86
- onSearchChange: () => {},
87
- onSearch: () => {},
88
- onClear: () => {},
89
- searchPlaceholder: '',
90
- searchInputClassName: '',
91
- searchInputStyle: { width: '210px' },
92
- ctaLabel: null,
93
- onCtaClick: () => {},
94
- ctaDisabled: false,
95
- ctaClassName: '',
96
- ctaNode: null,
97
- children: null,
98
- };
99
-
100
- export default TemplatesActionBar;
101
-
@@ -1,120 +0,0 @@
1
- /**
2
- * @jest-environment jsdom
3
- */
4
- import React from 'react';
5
- import { render, screen, fireEvent } from '@testing-library/react';
6
- import '@testing-library/jest-dom';
7
- import TemplatesActionBar from '../TemplatesActionBar';
8
-
9
- jest.mock('@capillarytech/cap-ui-library/CapInput', () => {
10
- const React = require('react');
11
- function Search(props) {
12
- return React.createElement('input', {
13
- 'data-testid': 'cap-input-search',
14
- value: props?.value,
15
- placeholder: props?.placeholder,
16
- onChange: props?.onChange,
17
- onKeyDown: (e) => {
18
- if (e.key === 'Enter' && props.onPressEnter) {
19
- props.onPressEnter(e);
20
- }
21
- },
22
- });
23
- }
24
- function CapInput() {
25
- return null;
26
- }
27
- CapInput.Search = Search;
28
- return { __esModule: true, default: CapInput };
29
- });
30
-
31
- jest.mock('@capillarytech/cap-ui-library/CapButton', () => {
32
- const React = require('react');
33
- return function CapButton(props) {
34
- return React.createElement('button', {
35
- type: 'button',
36
- 'data-testid': 'cta',
37
- onClick: props?.onClick,
38
- disabled: props?.disabled,
39
- }, props?.children);
40
- };
41
- });
42
-
43
- describe('TemplatesActionBar', () => {
44
- it('renders search when searchPlaceholder is set', () => {
45
- render(
46
- <TemplatesActionBar
47
- searchPlaceholder="Find templates"
48
- searchValue="hi"
49
- ctaLabel="Create"
50
- />,
51
- );
52
- expect(screen.getByTestId('cap-input-search')).toHaveAttribute('placeholder', 'Find templates');
53
- });
54
-
55
- it('omits search when searchPlaceholder is empty', () => {
56
- const { container } = render(
57
- <TemplatesActionBar searchPlaceholder="" ctaLabel="Go" />,
58
- );
59
- expect(container.querySelector('[data-testid="cap-input-search"]')).toBeNull();
60
- });
61
-
62
- it('fires onSearchChange and onCtaClick', () => {
63
- const onSearchChange = jest.fn();
64
- const onCtaClick = jest.fn();
65
- render(
66
- <TemplatesActionBar
67
- searchPlaceholder="S"
68
- onSearchChange={onSearchChange}
69
- ctaLabel="New"
70
- onCtaClick={onCtaClick}
71
- />,
72
- );
73
- fireEvent.change(screen.getByTestId('cap-input-search'), { target: { value: 'x' } });
74
- fireEvent.click(screen.getByTestId('cta'));
75
- expect(onSearchChange).toHaveBeenCalled();
76
- expect(onCtaClick).toHaveBeenCalled();
77
- });
78
-
79
- it('fires onSearch when Enter is pressed (antd Input has no native onSearch)', () => {
80
- const onSearch = jest.fn();
81
- render(
82
- <TemplatesActionBar
83
- searchPlaceholder="S"
84
- searchValue="query"
85
- onSearch={onSearch}
86
- ctaLabel="New"
87
- />,
88
- );
89
- const input = screen.getByTestId('cap-input-search');
90
- fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
91
- expect(onSearch).toHaveBeenCalledWith('query');
92
- });
93
-
94
- it('renders ctaNode instead of default button when provided', () => {
95
- render(
96
- <TemplatesActionBar
97
- searchPlaceholder="S"
98
- ctaNode={<span data-testid="custom-cta">Custom</span>}
99
- />,
100
- );
101
- expect(screen.getByTestId('custom-cta')).toBeInTheDocument();
102
- expect(screen.queryByTestId('cta')).toBeNull();
103
- });
104
-
105
- it('hides CTA area when showCta is false', () => {
106
- const { container } = render(
107
- <TemplatesActionBar searchPlaceholder="S" showCta={false} ctaLabel="X" />,
108
- );
109
- expect(container.querySelector('[data-testid="cta"]')).toBeNull();
110
- });
111
-
112
- it('renders children in toolbar row', () => {
113
- render(
114
- <TemplatesActionBar searchPlaceholder="S" ctaLabel="C">
115
- <span data-testid="child">extra</span>
116
- </TemplatesActionBar>,
117
- );
118
- expect(screen.getByTestId('child')).toBeInTheDocument();
119
- });
120
- });