@capillarytech/creatives-library 9.0.15-alpha.0 → 9.0.15-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 (132) hide show
  1. package/constants/unified.js +29 -0
  2. package/global-styles.js +1 -1
  3. package/package.json +1 -1
  4. package/services/tests/api.test.js +35 -20
  5. package/utils/commonUtils.js +19 -1
  6. package/utils/rcsPayloadUtils.js +92 -0
  7. package/utils/templateVarUtils.js +201 -0
  8. package/utils/tests/rcsPayloadUtils.test.js +226 -0
  9. package/utils/tests/templateVarUtils.test.js +204 -0
  10. package/v2Components/CapActionButton/constants.js +7 -0
  11. package/v2Components/CapActionButton/index.js +168 -109
  12. package/v2Components/CapActionButton/index.scss +156 -5
  13. package/v2Components/CapActionButton/messages.js +19 -3
  14. package/v2Components/CapActionButton/tests/index.test.js +42 -18
  15. package/v2Components/CapImageUpload/index.js +2 -2
  16. package/v2Components/CapTagList/index.js +10 -0
  17. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -48
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +214 -21
  20. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
  21. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +83 -9
  22. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
  23. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +60 -11
  24. package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
  25. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +201 -23
  26. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +355 -76
  27. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +155 -8
  28. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
  29. package/v2Components/CommonTestAndPreview/constants.js +38 -2
  30. package/v2Components/CommonTestAndPreview/index.js +761 -222
  31. package/v2Components/CommonTestAndPreview/messages.js +45 -3
  32. package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
  33. package/v2Components/CommonTestAndPreview/sagas.js +25 -6
  34. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +1 -0
  35. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -267
  36. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +231 -65
  37. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
  38. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
  39. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
  40. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +34 -13
  41. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
  42. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
  43. package/v2Components/CommonTestAndPreview/tests/index.test.js +133 -4
  44. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
  45. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +31 -24
  46. package/v2Components/CommonTestAndPreview/utils.js +84 -0
  47. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
  48. package/v2Components/SmsFallback/constants.js +94 -0
  49. package/v2Components/SmsFallback/index.js +958 -0
  50. package/v2Components/SmsFallback/index.scss +266 -0
  51. package/v2Components/SmsFallback/messages.js +78 -0
  52. package/v2Components/SmsFallback/smsFallbackUtils.js +120 -0
  53. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
  54. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
  55. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
  56. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +208 -0
  57. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
  58. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
  59. package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
  60. package/v2Components/TemplatePreview/_templatePreview.scss +41 -22
  61. package/v2Components/TemplatePreview/constants.js +2 -0
  62. package/v2Components/TemplatePreview/index.js +143 -31
  63. package/v2Components/TemplatePreview/tests/index.test.js +142 -0
  64. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  65. package/v2Components/TestAndPreviewSlidebox/index.js +13 -1
  66. package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
  67. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
  68. package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
  69. package/v2Components/VarSegmentMessageEditor/index.js +125 -0
  70. package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
  71. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +4 -1
  72. package/v2Containers/CommunicationFlow/index.js +3 -3
  73. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +4 -0
  74. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  75. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +17 -0
  76. package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
  77. package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
  78. package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
  79. package/v2Containers/CreativesContainer/constants.js +11 -0
  80. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +79 -0
  81. package/v2Containers/CreativesContainer/index.js +323 -104
  82. package/v2Containers/CreativesContainer/index.scss +83 -1
  83. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
  84. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +79 -34
  85. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +79 -16
  86. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
  87. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +333 -90
  88. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
  89. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  90. package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
  91. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
  92. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  93. package/v2Containers/Rcs/constants.js +131 -11
  94. package/v2Containers/Rcs/index.js +2602 -807
  95. package/v2Containers/Rcs/index.scss +289 -8
  96. package/v2Containers/Rcs/messages.js +34 -3
  97. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +227 -0
  98. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +73535 -38537
  99. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -8
  100. package/v2Containers/Rcs/tests/index.test.js +147 -36
  101. package/v2Containers/Rcs/tests/mockData.js +38 -0
  102. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +318 -0
  103. package/v2Containers/Rcs/tests/utils.test.js +646 -30
  104. package/v2Containers/Rcs/utils.js +478 -11
  105. package/v2Containers/Sms/Create/index.js +115 -48
  106. package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
  107. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  108. package/v2Containers/SmsTrai/Create/index.js +9 -4
  109. package/v2Containers/SmsTrai/Edit/constants.js +2 -0
  110. package/v2Containers/SmsTrai/Edit/index.js +678 -169
  111. package/v2Containers/SmsTrai/Edit/index.scss +126 -0
  112. package/v2Containers/SmsTrai/Edit/messages.js +14 -4
  113. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +5615 -3014
  114. package/v2Containers/SmsWrapper/index.js +37 -8
  115. package/v2Containers/TagList/index.js +6 -0
  116. package/v2Containers/Templates/TemplatesActionBar.js +101 -0
  117. package/v2Containers/Templates/_templates.scss +171 -12
  118. package/v2Containers/Templates/actions.js +11 -0
  119. package/v2Containers/Templates/constants.js +2 -0
  120. package/v2Containers/Templates/index.js +125 -55
  121. package/v2Containers/Templates/sagas.js +57 -13
  122. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
  123. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1060 -1015
  124. package/v2Containers/Templates/tests/sagas.test.js +199 -16
  125. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
  126. package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
  127. package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
  128. package/v2Containers/TemplatesV2/index.js +86 -23
  129. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
  130. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  131. package/v2Containers/Whatsapp/index.js +3 -20
  132. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
@@ -8,6 +8,7 @@ import CapRow from '@capillarytech/cap-ui-library/CapRow';
8
8
  import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
9
9
  import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
10
10
  import CapHeader from "@capillarytech/cap-ui-library/CapHeader";
11
+ import CapRadioGroup from '@capillarytech/cap-ui-library/CapRadioGroup';
11
12
  import CapSelect from '@capillarytech/cap-ui-library/CapSelect';
12
13
  import CapInput from '@capillarytech/cap-ui-library/CapInput';
13
14
  import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
@@ -20,9 +21,16 @@ import globalMessages from '../../v2Containers/Cap/messages';import CapTagListWi
20
21
 
21
22
  import { isUrl, isValidText } from '../../v2Containers/Line/Container/Wrapper/utils';
22
23
  import messages from './messages';
23
- import { CTA_OPTIONS, BTN_MAX_LENGTH, URL_MAX_LENGTH, PHONE_NUMBER_MAX_LENGTH,invalidVarRegex, HANDLERS } from './constants';
24
+ import {
25
+ BTN_MAX_LENGTH,
26
+ URL_MAX_LENGTH,
27
+ PHONE_NUMBER_MAX_LENGTH,
28
+ invalidVarRegex,
29
+ HANDLERS,
30
+ RCS_CTA_URL_TYPE,
31
+ } from './constants';
24
32
  import './index.scss';
25
- import { INITIAL_SUGGESTIONS, RCS_BUTTON_TYPES} from '../../v2Containers/Rcs/constants';
33
+ import { INITIAL_SUGGESTIONS, RCS_BUTTON_TYPES, HOST_ICS} from '../../v2Containers/Rcs/constants';
26
34
 
27
35
  const { TextArea } = CapInput;
28
36
 
@@ -41,9 +49,12 @@ export const CapActionButton = (props) => {
41
49
  injectedTags = {},
42
50
  location = {},
43
51
  selectedOfferDetails = [],
44
-
52
+ host = '',
45
53
  onContextChange,
54
+ minSavedSuggestions = 0,
55
+ hideDeleteSuggestionIndexes = [],
46
56
  } = props;
57
+ const isHostIcs = host === HOST_ICS;
47
58
  const [urlError, setUrlError] = useState(false);
48
59
  const [buttonError, setButtonError] = useState(false);
49
60
  const updateHandler = (type, value, index) => {
@@ -66,6 +77,7 @@ export const CapActionButton = (props) => {
66
77
 
67
78
  const onCtaTypeChange = (value, index) => {
68
79
  let clonedCta = cloneDeep(suggestions[index]);
80
+ const isCta = value === RCS_BUTTON_TYPES.CTA;
69
81
  clonedCta = {
70
82
  ...clonedCta,
71
83
  type: value,
@@ -73,6 +85,7 @@ export const CapActionButton = (props) => {
73
85
  phoneNumber: '',
74
86
  postback: '',
75
87
  url: value === RCS_BUTTON_TYPES.PHONE_NUMBER ? null : '',
88
+ urlType: isCta ? RCS_CTA_URL_TYPE.STATIC : undefined,
76
89
  isSaved: false,
77
90
  };
78
91
  setUrlError(false);
@@ -92,39 +105,61 @@ export const CapActionButton = (props) => {
92
105
  updateDisplayAndPostback(value, id);
93
106
  };
94
107
 
95
- const renderLength = (len, max) => (
96
- <CapHeading type="label1" className="rcs-render-btn-length">
97
- {formatMessage(messages.templateMessageLength, {
98
- currentLength: len,
99
- maxLength: max,
100
- })}
108
+ const renderInnerCharCount = (len, max) => (
109
+ <CapHeading type="h5" className="rcs-cta-inner-char-count">
110
+ {formatMessage(messages.ctaFieldCharCountInline, { current: len, max })}
101
111
  </CapHeading>
102
112
  );
103
113
 
104
- const onUrlChange = ({ target }) => {
105
- let { value, id } = target;
106
- let errorMessage = false;
107
- if (!isUrl(value)) {
108
- errorMessage = formatMessage(messages.ctaWebsiteUrlErrorMessage);
109
- } else if (value.match(invalidVarRegex)?.length > 0) {
110
- errorMessage = formatMessage(messages.staticUrlWithVarErrorMessage);
114
+ const validateCtaUrlValue = (value, urlSubtype) => {
115
+ const v = String(value || '').trim();
116
+ if (!v) {
117
+ return formatMessage(messages.ctaWebsiteUrlErrorMessage);
118
+ }
119
+ if (v.length > URL_MAX_LENGTH) {
120
+ return formatMessage(messages.ctaWebsiteUrlErrorMessage);
121
+ }
122
+ if (urlSubtype === RCS_CTA_URL_TYPE.DYNAMIC) {
123
+ return false;
111
124
  }
112
- setUrlError(errorMessage);
125
+ if (!isUrl(v)) {
126
+ return formatMessage(messages.ctaWebsiteUrlErrorMessage);
127
+ }
128
+ if (v.match(invalidVarRegex)?.length > 0) {
129
+ return formatMessage(messages.staticUrlWithVarErrorMessage);
130
+ }
131
+ return false;
132
+ };
133
+
134
+ const onUrlChange = ({ target }) => {
135
+ const { value, id } = target;
136
+ const row = suggestions[id] || {};
137
+ const subtype = row.urlType || RCS_CTA_URL_TYPE.STATIC;
138
+ setUrlError(validateCtaUrlValue(value, subtype));
113
139
  updateHandler(HANDLERS.URL, value, id);
114
140
  };
115
141
 
142
+ const onUrlSubtypeChange = (nextSubtype, index) => {
143
+ const cloned = cloneDeep(suggestions[index]);
144
+ cloned.urlType = nextSubtype;
145
+ cloned.isSaved = false;
146
+ setUrlError(validateCtaUrlValue(cloned.url || '', nextSubtype));
147
+ updateButtonChange(cloned, index);
148
+ };
149
+
116
150
  const onPhoneNoChange = (value, index) => {
117
151
  updateHandler(HANDLERS.PHONE_NUMBER, value, index);
118
152
  };
119
153
 
120
154
  const ctaSaveDisabled = (index) => {
121
- const { type, text, phoneNumber, url } = suggestions[index] || {};
155
+ const { type, text, phoneNumber, url, urlType } = suggestions[index] || {};
122
156
  if (text === '' || buttonError) {
123
157
  return true;
124
- } if (type === RCS_BUTTON_TYPES.PHONE_NUMBER && phoneNumber.length < 5) {
125
- return true;
126
- } if (type === RCS_BUTTON_TYPES.CTA && (url === '' || urlError)) {
158
+ } if (type === RCS_BUTTON_TYPES.PHONE_NUMBER && (phoneNumber || '').length < 5) {
127
159
  return true;
160
+ } if (type === RCS_BUTTON_TYPES.CTA) {
161
+ const subtype = urlType || RCS_CTA_URL_TYPE.STATIC;
162
+ return !!validateCtaUrlValue(url, subtype);
128
163
  }
129
164
  return false;
130
165
  };
@@ -143,64 +178,59 @@ export const CapActionButton = (props) => {
143
178
  updateButtonChange(newSuggestion, suggestions?.length);
144
179
  };
145
180
 
146
- const renderCtaOptions = (label, tooltipLabel, isDisabled) => {
147
- if (isDisabled) {
148
- return (
149
- <CapRow>
150
- <CapColumn span={23}>{label}</CapColumn>
151
- <CapColumn span={1}>
152
- <CapTooltipWithInfo
153
- // autoAdjustOverflow
154
- placement="right"
155
- title={tooltipLabel}
156
- />
157
- </CapColumn>
158
- </CapRow>
159
- );
160
- }
161
- return label;
162
- };
163
-
164
181
  const { formatMessage } = intl;
182
+
183
+ const hideDeleteForSuggestionIndex = (idx) =>
184
+ Array.isArray(hideDeleteSuggestionIndexes) && hideDeleteSuggestionIndexes.includes(idx);
185
+
186
+ const ctaTypeRadioOptions = [
187
+ { label: formatMessage(messages.ctaPhoneNo), value: RCS_BUTTON_TYPES.PHONE_NUMBER },
188
+ { label: formatMessage(messages.ctaUrlRadio), value: RCS_BUTTON_TYPES.CTA },
189
+ { label: formatMessage(messages.ctaQr), value: RCS_BUTTON_TYPES.QUICK_REPLY },
190
+ ];
191
+
192
+ const urlTypeSelectOptions = [
193
+ { value: RCS_CTA_URL_TYPE.STATIC, label: formatMessage(messages.ctaWebsiteTypeStatic) },
194
+ { value: RCS_CTA_URL_TYPE.DYNAMIC, label: formatMessage(messages.ctaWebsiteTypeDynamic) },
195
+ ];
196
+
165
197
  const renderedContent = () => {
166
198
  const renderArray = [];
167
- const addBtnDisabled = suggestions.length >= maxButtons || !suggestions[suggestions.length - 1]?.isSaved;
168
-
169
- const ctaOptions = CTA_OPTIONS.map((option) => {
170
- const { value, label } = option;
171
- const isDisabled = suggestions.length >= maxButtons && !suggestions[suggestions.length - 1];
172
- return {
173
- value,
174
- label: renderCtaOptions(label, formatMessage(messages.ctaButtonTypeDisabled), isDisabled),
175
- disabled: isDisabled,
176
- };
177
- });
199
+ const addBtnDisabled = suggestions?.length > 0 && (suggestions.length >= maxButtons || !suggestions[suggestions.length - 1]?.isSaved);
200
+ const savedSuggestionsCount = (suggestions || []).filter((s) => s && s.isSaved).length;
201
+ const cannotDeleteSavedMandatory = (idx) => {
202
+ const row = suggestions[idx];
203
+ if (!row || !row.isSaved) return false;
204
+ return minSavedSuggestions > 0 && savedSuggestionsCount <= minSavedSuggestions;
205
+ };
178
206
 
179
- suggestions.forEach((cta) => {
207
+ suggestions?.length > 0 && suggestions.forEach((cta) => {
180
208
  const {
181
209
  index, type, text, isSaved,
182
210
  } = cta || {};
183
211
 
184
212
  const url = type !== RCS_BUTTON_TYPES.CTA ? null : cta.url;
213
+ const urlSubtype = type === RCS_BUTTON_TYPES.CTA
214
+ ? (cta.urlType || RCS_CTA_URL_TYPE.STATIC)
215
+ : RCS_CTA_URL_TYPE.STATIC;
185
216
  const phoneNumber = type !== RCS_BUTTON_TYPES.PHONE_NUMBER ? null : cta.phoneNumber;
186
217
  if (isFullMode && !isEditFlow && !isSaved) {
187
218
  renderArray.push(
188
- <div className="rcs-button-cta-create-container" key={`cta-edit-${index}`}>
189
- <CapRow type='flex' justify='space-between' className="rcs-button-cta-create margin-t-16">
190
- <CapColumn span={11}>
191
- {/* Type of action */}
192
- <CapHeading type="h4" className="cta-label">
219
+ <CapRow className="rcs-button-cta-create-container" key={`cta-edit-${index}`} gutter={0}>
220
+ <CapRow className="rcs-button-cta-create" gutter={0}>
221
+ <CapColumn span={24}>
222
+ <CapHeading type="h4">
193
223
  {formatMessage(messages.ctaType)}
194
224
  </CapHeading>
195
- <CapSelect
196
- id="rcs-cta-type"
197
- options={ctaOptions || []}
198
- onChange={(value) => onCtaTypeChange(value, index)}
225
+ <CapRadioGroup
226
+ id={`rcs-cta-type-radio-${index}`}
227
+ className="cap-rcs-cta-type-radio"
228
+ options={ctaTypeRadioOptions}
199
229
  value={type}
200
- disabled={false}
230
+ onChange={(e) => onCtaTypeChange(e.target.value, index)}
201
231
  />
202
232
  </CapColumn>
203
- <CapColumn span={12}>
233
+ <CapColumn span={24}>
204
234
  <CapHeading type="h4" className="cta-label">
205
235
  {formatMessage(messages.ctaButtonText)}
206
236
  <CapTooltipWithInfo
@@ -221,28 +251,34 @@ export const CapActionButton = (props) => {
221
251
  size="large"
222
252
  maxLength={BTN_MAX_LENGTH}
223
253
  errorMessage={buttonError}
254
+ suffix={renderInnerCharCount((text || '').length, BTN_MAX_LENGTH)}
224
255
  />
225
- {renderLength(text.length, BTN_MAX_LENGTH)}
226
256
  </CapColumn>
227
257
  </CapRow>
228
258
  {type === RCS_BUTTON_TYPES.PHONE_NUMBER && (
229
259
  <>
230
260
  <CapRow>
231
- <CapColumn span={11}>
232
- {/* phone number */}
261
+ <CapColumn span={24}>
233
262
  <CapHeading type="h4" className="cta-label">
234
263
  {formatMessage(messages.ctaPhoneNo)}
235
264
  </CapHeading>
236
- <PhoneInput
237
- placeholder={formatMessage(messages.ctaPhoneNoPlaceholder)}
238
- autoFormat={false}
239
- countryCodeEditable={false}
240
- value={phoneNumber}
241
- onChange={(value) => onPhoneNoChange(value, index)}
242
- country="in"
243
- className="cta-phone-number"
244
- />
245
- {renderLength(phoneNumber.length, PHONE_NUMBER_MAX_LENGTH)}
265
+ <CapRow
266
+ className="rcs-cta-input-with-inner-count rcs-cta-input-with-inner-count--phone"
267
+ gutter={0}
268
+ >
269
+ <CapColumn span={24}>
270
+ <PhoneInput
271
+ placeholder={formatMessage(messages.ctaPhoneNoPlaceholder)}
272
+ autoFormat={false}
273
+ countryCodeEditable={false}
274
+ value={phoneNumber}
275
+ onChange={(value) => onPhoneNoChange(value, index)}
276
+ country="in"
277
+ className="cta-phone-number rcs-cta-phone-input"
278
+ />
279
+ {renderInnerCharCount((phoneNumber || '').length, PHONE_NUMBER_MAX_LENGTH)}
280
+ </CapColumn>
281
+ </CapRow>
246
282
  </CapColumn>
247
283
  </CapRow>
248
284
  <CapRow useLegacy className="rcs-cta-save-delete-btn">
@@ -250,7 +286,7 @@ export const CapActionButton = (props) => {
250
286
  title={ctaSaveDisabled(index) && formatMessage(messages.ctaSaveDisabled)}
251
287
  placement="bottom"
252
288
  >
253
- <div className="button-disabled-tooltip-wrapper">
289
+ <CapRow className="button-disabled-tooltip-wrapper">
254
290
  <CapButton
255
291
  onClick={() => saveCta(index)}
256
292
  disabled={ctaSaveDisabled(index)}
@@ -258,36 +294,49 @@ export const CapActionButton = (props) => {
258
294
  >
259
295
  {formatMessage(globalMessages.save)}
260
296
  </CapButton>
261
- </div>
297
+ </CapRow>
262
298
  </CapTooltip>
263
- <CapButton
264
- onClick={() => deleteButtonHandler(index)}
265
- className="rcs-cta-delete-btn"
266
- type="secondary"
267
- >
268
- {formatMessage(globalMessages.delete)}
269
- </CapButton>
299
+ {!hideDeleteForSuggestionIndex(index) && !cannotDeleteSavedMandatory(index) && (
300
+ <CapButton
301
+ onClick={() => deleteButtonHandler(index)}
302
+ className="rcs-cta-delete-btn"
303
+ type="secondary"
304
+ >
305
+ {formatMessage(globalMessages.delete)}
306
+ </CapButton>
307
+ )}
270
308
  </CapRow>
271
309
  </>
272
310
  )}
273
311
  {type === RCS_BUTTON_TYPES.CTA && (
274
312
  <>
275
- <CapRow>
276
- <CapColumn span={24}>
313
+ <CapRow className="rcs-cta-url-fields-row" gutter={8}>
314
+ <CapColumn span={6} className="rcs-cta-url-type-col">
277
315
  <CapHeading type="h4" className="cta-label">
278
- {formatMessage(messages.ctaWebsite)}
316
+ {formatMessage(messages.ctaWebsiteType)}
317
+ </CapHeading>
318
+ <CapSelect
319
+ id={`rcs-cta-url-type-${index}`}
320
+ options={urlTypeSelectOptions}
321
+ value={urlSubtype}
322
+ onChange={(value) => onUrlSubtypeChange(value, index)}
323
+ />
324
+ </CapColumn>
325
+ <CapColumn span={18} className="rcs-cta-url-value-col">
326
+ <CapHeading type="h4" className="cta-label">
327
+ {formatMessage(messages.ctaUrlField)}
279
328
  </CapHeading>
280
329
  <CapInput
281
330
  id={index}
282
331
  className="rcs-cta-url"
283
332
  onChange={onUrlChange}
284
- placeholder={formatMessage(messages.ctaStaticPlaceholder)}
285
- value={url}
333
+ placeholder={formatMessage(messages.ctaEnterUrlPlaceholder)}
334
+ value={url || ''}
286
335
  size="large"
287
336
  maxLength={URL_MAX_LENGTH}
288
337
  errorMessage={urlError}
338
+ suffix={renderInnerCharCount((url || '').length, URL_MAX_LENGTH)}
289
339
  />
290
- {renderLength(url.length, URL_MAX_LENGTH)}
291
340
  </CapColumn>
292
341
  </CapRow>
293
342
  <CapRow useLegacy className="rcs-cta-save-delete-btn">
@@ -297,7 +346,7 @@ export const CapActionButton = (props) => {
297
346
  }
298
347
  placement="bottom"
299
348
  >
300
- <div className="button-disabled-tooltip-wrapper">
349
+ <CapRow className="button-disabled-tooltip-wrapper">
301
350
  <CapButton
302
351
  onClick={() => saveCta(index)}
303
352
  disabled={ctaSaveDisabled(index)}
@@ -305,15 +354,17 @@ export const CapActionButton = (props) => {
305
354
  >
306
355
  {formatMessage(globalMessages.save)}
307
356
  </CapButton>
308
- </div>
357
+ </CapRow>
309
358
  </CapTooltip>
310
- <CapButton
311
- onClick={() => deleteButtonHandler(index)}
312
- className="rcs-cta-delete-btn"
313
- type="secondary"
314
- >
315
- {formatMessage(globalMessages.delete)}
316
- </CapButton>
359
+ {!hideDeleteForSuggestionIndex(index) && !cannotDeleteSavedMandatory(index) && (
360
+ <CapButton
361
+ onClick={() => deleteButtonHandler(index)}
362
+ className="rcs-cta-delete-btn"
363
+ type="secondary"
364
+ >
365
+ {formatMessage(globalMessages.delete)}
366
+ </CapButton>
367
+ )}
317
368
  </CapRow>
318
369
  </>
319
370
  )}
@@ -323,7 +374,7 @@ export const CapActionButton = (props) => {
323
374
  title={ctaSaveDisabled(index) && formatMessage(messages.ctaSaveDisabled)}
324
375
  placement="bottom"
325
376
  >
326
- <div className="button-disabled-tooltip-wrapper">
377
+ <CapRow className="button-disabled-tooltip-wrapper">
327
378
  <CapButton
328
379
  onClick={() => saveCta(index)}
329
380
  disabled={ctaSaveDisabled(index)}
@@ -331,9 +382,9 @@ export const CapActionButton = (props) => {
331
382
  >
332
383
  {formatMessage(globalMessages.save)}
333
384
  </CapButton>
334
- </div>
385
+ </CapRow>
335
386
  </CapTooltip>
336
- {index !== 0 && (
387
+ {!(isHostIcs && index === 0) && !hideDeleteForSuggestionIndex(index) && !cannotDeleteSavedMandatory(index) && (
337
388
  <CapButton
338
389
  onClick={() => deleteButtonHandler(index)}
339
390
  className="rcs-cta-delete-btn"
@@ -344,12 +395,12 @@ export const CapActionButton = (props) => {
344
395
  )}
345
396
  </CapRow>
346
397
  )}
347
- </div>
398
+ </CapRow>
348
399
  );
349
400
  } else {
350
401
  const ctaIsPhone = type === RCS_BUTTON_TYPES.PHONE_NUMBER;
351
402
  const ctaIsReply = type === RCS_BUTTON_TYPES.QUICK_REPLY;
352
- renderArray.push(
403
+ suggestions?.length > 0 && renderArray?.push(
353
404
  <CapRow
354
405
  key={`cta-saved-${index}`}
355
406
  className="cap-rcs-saved-cta margin-t-12"
@@ -379,7 +430,9 @@ export const CapActionButton = (props) => {
379
430
  <>
380
431
  <CapColumn span={3}>
381
432
  <CapLabel className="url-type" type="label2">
382
- {formatMessage(messages.ctaWebsiteTypeStatic)}
433
+ {(cta.urlType || RCS_CTA_URL_TYPE.STATIC) === RCS_CTA_URL_TYPE.DYNAMIC
434
+ ? formatMessage(messages.ctaWebsiteTypeDynamic)
435
+ : formatMessage(messages.ctaWebsiteTypeStatic)}
383
436
  </CapLabel>
384
437
  </CapColumn>
385
438
  <CapRow type='flex' className="rcs-url-preview-wrapper">
@@ -400,7 +453,7 @@ export const CapActionButton = (props) => {
400
453
  >
401
454
  <CapIcon size="s" type="edit" />
402
455
  </CapColumn>
403
- {index !== 0 && (
456
+ {!(isHostIcs && index === 0) && !hideDeleteForSuggestionIndex(index) && !cannotDeleteSavedMandatory(index) && (
404
457
  <CapColumn className="rcs-saved-cta-delete-icon" span={1} onClick={() => deleteButtonHandler(index)}>
405
458
  <CapIcon size="s" type="delete" />
406
459
  </CapColumn>
@@ -412,7 +465,7 @@ export const CapActionButton = (props) => {
412
465
  }
413
466
  });
414
467
  {
415
- suggestions.length < maxButtons &&
468
+ suggestions?.length < maxButtons &&
416
469
  (isFullMode && !isEditFlow)
417
470
  && renderArray.push(
418
471
  <CapRow useLegacy>
@@ -422,7 +475,7 @@ export const CapActionButton = (props) => {
422
475
  }
423
476
  placement={'right'}
424
477
  >
425
- <div className="button-disabled-tooltip-wrapper">
478
+ <CapRow className="button-disabled-tooltip-wrapper">
426
479
  <CapButton
427
480
  type="flat"
428
481
  id="rcs-cta-add-button"
@@ -433,7 +486,7 @@ export const CapActionButton = (props) => {
433
486
  >
434
487
  {formatMessage(messages.addButton)}
435
488
  </CapButton>
436
- </div>
489
+ </CapRow>
437
490
  </CapTooltip>
438
491
  </CapRow>,
439
492
  );
@@ -446,6 +499,8 @@ export const CapActionButton = (props) => {
446
499
  CapActionButton.propTypes = {
447
500
  intl: intlShape.isRequired,
448
501
  updateButtonChange: PropTypes.func,
502
+ minSavedSuggestions: PropTypes.number,
503
+ hideDeleteSuggestionIndexes: PropTypes.arrayOf(PropTypes.number),
449
504
  suggestions: PropTypes.array,
450
505
  tags: PropTypes.array,
451
506
  injectedTags: PropTypes.object,
@@ -453,12 +508,15 @@ CapActionButton.propTypes = {
453
508
  selectedOfferDetails: PropTypes.array,
454
509
  onTagSelect: PropTypes.func,
455
510
  onContextChange: PropTypes.func,
511
+ host: PropTypes.string,
456
512
  };
457
513
 
458
514
  CapActionButton.defaultProps = {
459
515
  buttonTextlen: 20,
460
516
  type: '',
461
517
  updateButtonChange: () => {},
518
+ minSavedSuggestions: 0,
519
+ hideDeleteSuggestionIndexes: [],
462
520
  suggestions: [],
463
521
  tags: [],
464
522
  injectedTags: {},
@@ -466,6 +524,7 @@ CapActionButton.defaultProps = {
466
524
  selectedOfferDetails: [],
467
525
  onTagSelect: () => {},
468
526
  onContextChange: () => {},
527
+ host: '',
469
528
  };
470
529
 
471
530
  export default injectIntl(CapActionButton);
@@ -1,7 +1,20 @@
1
1
  @import '~@capillarytech/cap-ui-library/styles/_variables';
2
2
 
3
- #rcs-cta-type{
4
- width: 90%;
3
+ // Horizontal RCS button type radios (Phone number | URL | Quick reply)
4
+ .cap-rcs-cta-type-radio.cap-radio-group-v2 {
5
+ display: flex;
6
+ flex-wrap: wrap;
7
+ align-items: center;
8
+ margin-top: 0.5rem;
9
+
10
+ .ant-radio-wrapper {
11
+ margin-right: $CAP_SPACE_24;
12
+ margin-bottom: 0;
13
+
14
+ &:last-child {
15
+ margin-right: 0;
16
+ }
17
+ }
5
18
  }
6
19
 
7
20
  .cap-rcs-saved-cta {
@@ -48,9 +61,139 @@
48
61
  }
49
62
  }
50
63
 
51
- .rcs-button-cta-create-container {
52
- border: solid 1px $CAP_G06;
53
- padding: 10px;
64
+ // Button text / URL: count via CapInput `suffix` (antd affix, right-aligned inside field).
65
+ // Phone: react-phone-input-2 overlay count + padding on .form-control
66
+ .rcs-cta-inner-char-count {
67
+ font-size: 0.75rem;
68
+ line-height: 1.25rem;
69
+ color: $FONT_COLOR_03;
70
+ white-space: nowrap;
71
+ }
72
+
73
+ .rcs-cta-input-with-inner-count {
74
+ position: relative;
75
+ width: 100%;
76
+
77
+ &--phone .rcs-cta-inner-char-count {
78
+ position: absolute;
79
+ right: 0.6875rem;
80
+ top: 50%;
81
+ transform: translateY(-50%);
82
+ z-index: 2;
83
+ pointer-events: none;
84
+ }
85
+ }
86
+
87
+ // RCS phone field: Figma — one light border, 4px radius, ~antd Input large height, full width, count inside right
88
+ .rcs-button-cta-create-container .rcs-cta-input-with-inner-count--phone {
89
+ .react-tel-input.rcs-cta-phone-input {
90
+ width: 100%;
91
+ }
92
+
93
+ .rcs-cta-phone-input .form-control {
94
+ width: 100% !important;
95
+ max-width: none;
96
+ height: 2.5rem;
97
+ min-height: 2.5rem;
98
+ padding-top: 0;
99
+ padding-bottom: 0;
100
+ padding-left: 3rem;
101
+ padding-right: 3.5rem;
102
+ margin: 0;
103
+ font-size: 0.875rem;
104
+ line-height: 2.5rem;
105
+ color: $CAP_G01;
106
+ background: $CAP_WHITE;
107
+ border: 1px solid $CAP_G06;
108
+ border-radius: 0.25rem;
109
+ box-shadow: none;
110
+
111
+ &::placeholder {
112
+ color: $CAP_G05;
113
+ }
114
+
115
+ &:hover {
116
+ border-color: $CAP_G11;
117
+ }
118
+
119
+ &:focus {
120
+ border-color: $CAP_G01;
121
+ box-shadow: none;
122
+ outline: none;
123
+ }
124
+ }
125
+
126
+ .rcs-cta-phone-input .flag-dropdown {
127
+ top: 0.0625rem;
128
+ bottom: 0.0625rem;
129
+ left: 0.0625rem;
130
+ padding: 0;
131
+ background: $CAP_WHITE;
132
+ border: none;
133
+ border-radius: 0.1875rem 0 0 0.1875rem; // inset from outer 4px radius
134
+ }
135
+
136
+ .rcs-cta-phone-input .flag-dropdown.open {
137
+ border-radius: 0.1875rem 0 0 0;
138
+ }
139
+
140
+ .rcs-cta-phone-input .selected-flag {
141
+ width: 2.75rem;
142
+ padding: 0 0 0 0.5rem;
143
+ background: transparent;
144
+ border-radius: 0.1875rem 0 0 0.1875rem;
145
+ }
146
+
147
+ .rcs-cta-phone-input .selected-flag:hover,
148
+ .rcs-cta-phone-input .selected-flag:focus {
149
+ background: $CAP_G09;
150
+ }
151
+
152
+ .rcs-cta-phone-input .selected-flag .arrow {
153
+ left: 1.375rem;
154
+ border-top-color: $CAP_G04;
155
+ }
156
+ }
157
+
158
+ // URL CTA: URL type (narrow) + URL field (~1:3) per Figma
159
+ .rcs-cta-url-fields-row {
160
+ .rcs-cta-url-type-col .ant-select {
161
+ width: 100%;
162
+ }
163
+ }
164
+
165
+ // RCS “create CTA” card: 0.5rem padding + gaps (Figma-tight; fixes excess space above first label)
166
+ .rcs-button-cta-create-container.cap-row-v2 {
167
+ display: flex;
168
+ flex-direction: column;
169
+ flex-wrap: nowrap;
170
+ width: 100%;
171
+ border: solid 1px $CAP_G06;
172
+ padding: 1.25rem;
173
+ border-radius: 0.25rem; // 4px — match .cap-rcs-saved-cta
174
+
175
+ // Stack “Button type” (radios) above “Button text”
176
+ .rcs-button-cta-create.cap-row-v2 {
177
+ display: flex;
178
+ flex-direction: column;
179
+ flex-wrap: nowrap;
180
+ margin: 0;
181
+ }
182
+
183
+ // Space after each field label (CapHeading margins are often zeroed by the library)
184
+ .cta-label {
185
+ margin-bottom: 0;
186
+ margin-top: 0.75rem;
187
+ }
188
+
189
+ .cta-label + * {
190
+ margin-top: 0.5rem;
191
+ }
192
+
193
+ // “Button type” heading has no .cta-label — keep same label→control gap as other fields
194
+ .rcs-button-cta-create > .ant-col:first-of-type .cap-rcs-cta-type-radio {
195
+ margin-top: 0.5rem;
196
+ }
54
197
  }
55
198
 
56
199
  .disabled {
@@ -64,4 +207,12 @@
64
207
 
65
208
  .button-disabled-tooltip-wrapper {
66
209
  display: inline-block;
210
+ margin-top: 1.25rem;
211
+ }
212
+
213
+ // Space between Save and Delete on RCS / carousel CTA rows
214
+ .rcs-cta-save-delete-btn {
215
+ .rcs-cta-delete-btn {
216
+ margin-left: 0.75rem;
217
+ }
67
218
  }