@capillarytech/creatives-library 9.0.15-alpha.3 → 9.0.16-beta.0

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 (146) hide show
  1. package/AppRoot.js +80 -0
  2. package/app.js +5 -3
  3. package/constants/unified.js +0 -29
  4. package/entry.js +67 -1
  5. package/global-styles.js +1 -1
  6. package/mfe-exposed-components.js +2 -4
  7. package/package.json +2 -2
  8. package/services/api.js +1 -1
  9. package/services/tests/api.test.js +20 -35
  10. package/styles/containers/layout/_layoutPage.scss +8 -6
  11. package/utils/commonUtils.js +1 -19
  12. package/utils/getDataLayer.js +15 -0
  13. package/utils/gtmTrackers/gtmEvents/creativeDetails.js +2 -1
  14. package/utils/mfeDetect.js +1 -0
  15. package/v2Components/CapActionButton/constants.js +1 -8
  16. package/v2Components/CapActionButton/index.js +144 -202
  17. package/v2Components/CapActionButton/index.scss +14 -232
  18. package/v2Components/CapActionButton/messages.js +3 -19
  19. package/v2Components/CapActionButton/tests/index.test.js +18 -42
  20. package/v2Components/CapImageUpload/index.js +2 -2
  21. package/v2Components/CapTagList/index.js +0 -10
  22. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +48 -70
  23. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  24. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -214
  25. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  26. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +9 -83
  27. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  28. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -60
  29. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  30. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +22 -202
  31. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +80 -381
  32. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +8 -155
  33. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  34. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  35. package/v2Components/CommonTestAndPreview/index.js +222 -761
  36. package/v2Components/CommonTestAndPreview/messages.js +3 -45
  37. package/v2Components/CommonTestAndPreview/sagas.js +6 -25
  38. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -1
  39. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +267 -284
  40. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  41. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  42. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  43. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  44. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  45. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  46. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  47. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -133
  48. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +24 -31
  49. package/v2Components/NavigationBar/index.js +9 -7
  50. package/v2Components/NavigationBar/mfeModuleHeader.config.js +16 -0
  51. package/v2Components/Pagination/_pagination.scss +2 -0
  52. package/v2Components/TemplatePreview/_templatePreview.scss +25 -45
  53. package/v2Components/TemplatePreview/index.js +32 -147
  54. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  55. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  56. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  57. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  58. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  59. package/v2Containers/Cap/constants.js +1 -0
  60. package/v2Containers/Cap/index.js +47 -21
  61. package/v2Containers/Cap/sagas.js +19 -0
  62. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +1 -4
  63. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +0 -4
  64. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  65. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -37
  66. package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -14
  67. package/v2Containers/CreativesContainer/SlideBoxHeader.js +5 -36
  68. package/v2Containers/CreativesContainer/constants.js +0 -11
  69. package/v2Containers/CreativesContainer/index.js +104 -323
  70. package/v2Containers/CreativesContainer/index.scss +1 -83
  71. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -79
  72. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  73. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  74. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +90 -333
  75. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  76. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  77. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  78. package/v2Containers/Rcs/constants.js +11 -131
  79. package/v2Containers/Rcs/index.js +829 -2682
  80. package/v2Containers/Rcs/index.scss +8 -443
  81. package/v2Containers/Rcs/messages.js +6 -45
  82. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +39409 -74176
  83. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +74 -10
  84. package/v2Containers/Rcs/tests/index.test.js +40 -151
  85. package/v2Containers/Rcs/tests/mockData.js +0 -38
  86. package/v2Containers/Rcs/tests/utils.test.js +30 -643
  87. package/v2Containers/Rcs/utils.js +12 -466
  88. package/v2Containers/Sms/Create/index.js +48 -115
  89. package/v2Containers/SmsTrai/Create/index.js +4 -9
  90. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  91. package/v2Containers/SmsTrai/Edit/index.js +169 -678
  92. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  93. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2854 -5455
  94. package/v2Containers/SmsWrapper/index.js +8 -37
  95. package/v2Containers/TagList/index.js +0 -6
  96. package/v2Containers/Templates/_templates.scss +11 -196
  97. package/v2Containers/Templates/actions.js +0 -11
  98. package/v2Containers/Templates/constants.js +0 -2
  99. package/v2Containers/Templates/index.js +60 -131
  100. package/v2Containers/Templates/sagas.js +13 -57
  101. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1015 -1060
  102. package/v2Containers/Templates/tests/sagas.test.js +16 -199
  103. package/v2Containers/TemplatesV2/TemplatesV2.style.js +10 -75
  104. package/v2Containers/TemplatesV2/index.js +43 -86
  105. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  106. package/v2Containers/Whatsapp/index.js +25 -4
  107. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  108. package/utils/rcsPayloadUtils.js +0 -92
  109. package/utils/templateVarUtils.js +0 -201
  110. package/utils/tests/rcsPayloadUtils.test.js +0 -226
  111. package/utils/tests/templateVarUtils.test.js +0 -204
  112. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  113. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  114. package/v2Components/CommonTestAndPreview/utils.js +0 -84
  115. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
  116. package/v2Components/SmsFallback/constants.js +0 -94
  117. package/v2Components/SmsFallback/index.js +0 -958
  118. package/v2Components/SmsFallback/index.scss +0 -266
  119. package/v2Components/SmsFallback/messages.js +0 -78
  120. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -120
  121. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  122. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  123. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  124. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -208
  125. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
  126. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  127. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  128. package/v2Components/TemplatePreview/constants.js +0 -2
  129. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  130. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  131. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  132. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -17
  133. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
  134. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  135. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  136. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  137. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -227
  138. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  139. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  140. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  141. package/v2Containers/SmsTrai/Edit/index.scss +0 -126
  142. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  143. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  144. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  145. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  146. 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,126 +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-char-count-heading {
120
- margin-top: $CAP_SPACE_04;
121
- margin-bottom: 0;
122
- }
123
-
124
- .sms-trai-edit-bottom-spacer {
125
- margin-bottom: 6.25rem;
126
- }
@@ -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
- });