@capillarytech/creatives-library 9.0.15-alpha.1 → 9.0.16

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 (132) hide show
  1. package/constants/unified.js +0 -29
  2. package/global-styles.js +1 -1
  3. package/package.json +1 -1
  4. package/services/tests/api.test.js +20 -35
  5. package/utils/commonUtils.js +1 -19
  6. package/v2Components/CapActionButton/constants.js +0 -7
  7. package/v2Components/CapActionButton/index.js +109 -168
  8. package/v2Components/CapActionButton/index.scss +5 -156
  9. package/v2Components/CapActionButton/messages.js +3 -19
  10. package/v2Components/CapActionButton/tests/index.test.js +18 -42
  11. package/v2Components/CapImageUpload/index.js +2 -2
  12. package/v2Components/CapTagList/index.js +0 -10
  13. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +48 -70
  14. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -214
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  17. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +9 -83
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -60
  20. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  21. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +23 -201
  22. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -355
  23. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +8 -155
  24. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  25. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  26. package/v2Components/CommonTestAndPreview/index.js +222 -761
  27. package/v2Components/CommonTestAndPreview/messages.js +3 -45
  28. package/v2Components/CommonTestAndPreview/sagas.js +6 -25
  29. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -1
  30. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +267 -284
  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 -133
  39. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +24 -31
  40. package/v2Components/TemplatePreview/_templatePreview.scss +22 -41
  41. package/v2Components/TemplatePreview/index.js +31 -143
  42. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  43. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  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/CommunicationFlow/Tests/CommunicationFlow.test.js +1 -4
  48. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +0 -4
  49. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  50. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -36
  51. package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -14
  52. package/v2Containers/CreativesContainer/SlideBoxHeader.js +5 -36
  53. package/v2Containers/CreativesContainer/constants.js +0 -11
  54. package/v2Containers/CreativesContainer/index.js +104 -323
  55. package/v2Containers/CreativesContainer/index.scss +1 -83
  56. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -79
  57. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  58. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  59. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +90 -333
  60. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  61. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  62. package/v2Containers/Email/index.js +5 -2
  63. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  64. package/v2Containers/Rcs/constants.js +11 -131
  65. package/v2Containers/Rcs/index.js +810 -2605
  66. package/v2Containers/Rcs/index.scss +8 -289
  67. package/v2Containers/Rcs/messages.js +3 -34
  68. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +38537 -73535
  69. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +8 -0
  70. package/v2Containers/Rcs/tests/index.test.js +36 -147
  71. package/v2Containers/Rcs/tests/mockData.js +0 -38
  72. package/v2Containers/Rcs/tests/utils.test.js +30 -646
  73. package/v2Containers/Rcs/utils.js +11 -478
  74. package/v2Containers/Sms/Create/index.js +48 -115
  75. package/v2Containers/SmsTrai/Create/index.js +4 -9
  76. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  77. package/v2Containers/SmsTrai/Edit/index.js +169 -678
  78. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  79. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2854 -5455
  80. package/v2Containers/SmsWrapper/index.js +8 -37
  81. package/v2Containers/TagList/index.js +0 -6
  82. package/v2Containers/Templates/_templates.scss +12 -171
  83. package/v2Containers/Templates/actions.js +0 -11
  84. package/v2Containers/Templates/constants.js +0 -2
  85. package/v2Containers/Templates/index.js +55 -125
  86. package/v2Containers/Templates/sagas.js +13 -57
  87. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1015 -1060
  88. package/v2Containers/Templates/tests/sagas.test.js +16 -199
  89. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
  90. package/v2Containers/TemplatesV2/index.js +23 -86
  91. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  92. package/v2Containers/Whatsapp/index.js +20 -3
  93. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  94. package/utils/rcsPayloadUtils.js +0 -92
  95. package/utils/templateVarUtils.js +0 -201
  96. package/utils/tests/rcsPayloadUtils.test.js +0 -226
  97. package/utils/tests/templateVarUtils.test.js +0 -204
  98. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  99. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  100. package/v2Components/CommonTestAndPreview/utils.js +0 -84
  101. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
  102. package/v2Components/SmsFallback/constants.js +0 -94
  103. package/v2Components/SmsFallback/index.js +0 -958
  104. package/v2Components/SmsFallback/index.scss +0 -266
  105. package/v2Components/SmsFallback/messages.js +0 -78
  106. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -120
  107. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  108. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  109. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  110. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -208
  111. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
  112. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  113. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  114. package/v2Components/TemplatePreview/constants.js +0 -2
  115. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  116. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  117. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  118. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -17
  119. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
  120. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  121. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  122. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  123. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -227
  124. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  125. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  126. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  127. package/v2Containers/SmsTrai/Edit/index.scss +0 -126
  128. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  129. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  130. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  131. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  132. 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
- });