@capillarytech/creatives-library 9.0.56-alpha.4 → 9.0.56-alpha.5

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "9.0.56-alpha.4",
4
+ "version": "9.0.56-alpha.5",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/services/api.js CHANGED
@@ -701,21 +701,23 @@ export const createCentralCommsMetaId = (payload, metaType = TRANSACTION) => {
701
701
  return request(url, getAPICallObject('POST', payload, false, false, false, true));
702
702
  };
703
703
 
704
- // CCS CommDefinition API (new Veyron /api/v1/commdefinition surface, proxied through cap-creatives-api /comm-definitions); used by CommunicationFlow's Save, while legacy messageMeta functions remain for CreativesContainer's save flow (Cap/sagas.js).
704
+ // CCS CommDefinition API, proxied through cap-creatives-api; used by CommunicationFlow's Save, while legacy messageMeta functions remain for CreativesContainer's save flow.
705
+ const COMM_DEFINITIONS_PATH = `${API_ENDPOINT}/comm-definitions`;
706
+
705
707
  export const createCommDefinition = (payload) => {
706
- const url = `${API_ENDPOINT}/comm-definitions`;
708
+ const url = COMM_DEFINITIONS_PATH;
707
709
  return request(url, getAPICallObject('POST', payload, false, false, false, true));
708
710
  };
709
711
 
710
- // Opens a new DRAFT version with the supplied content on an existing CommDefinition (same id/referenceId); used by CommunicationFlow edit-mode saves to preserve the alert's identity instead of creating a new CommDefinition. Route verified against Veyron's /commdefinition/{id}/edit endpoint.
712
+ // Opens a new DRAFT version on an existing CommDefinition, preserving its id/referenceId.
711
713
  export const editCommDefinition = (commDefinitionId, payload) => {
712
- const url = `${API_ENDPOINT}/comm-definitions/${commDefinitionId}/edit`;
714
+ const url = `${COMM_DEFINITIONS_PATH}/${commDefinitionId}/edit`;
713
715
  return request(url, getAPICallObject('POST', payload, false, false, false, true));
714
716
  };
715
717
 
716
- // Sends a real transactional comm via CCS (notify/ui's "Send test" action uses this instead of the legacy createMessageMeta/sendTestMessage flow — see CommonTestAndPreview's handleSendTestMessage).
718
+ // notify/ui's "Send test" uses this instead of the legacy createMessageMeta/sendTestMessage flow.
717
719
  export const sendTransactionalComm = (payload) => {
718
- const url = `${API_ENDPOINT}/comm-definitions/send/transaction`;
720
+ const url = `${COMM_DEFINITIONS_PATH}/send/transaction`;
719
721
  return request(url, getAPICallObject('POST', payload, false, false, false, true));
720
722
  };
721
723
 
@@ -140,7 +140,8 @@ const UnifiedPreview = ({
140
140
  }
141
141
 
142
142
  case CHANNELS.LINE:
143
- // LINE currently carries a single text message; CCS stores lineMessageContent.messageBody as JSON for LINE's native messages[] (see testAndPreviewDataTransform.js), already reduced to plain text before this point, so reuse the SMS chat-bubble preview. Rich LINE types (image/video/sticker/imageMap/carousel/flex) are not specially rendered yet.
143
+ // LINE carries a single plain-text message today, so it reuses the SMS chat-bubble
144
+ // preview. Rich types (image/video/sticker/imageMap/carousel/flex) aren't rendered yet.
144
145
  return (
145
146
  <SmsPreviewContent
146
147
  content={typeof content === 'string' ? content : (content?.resolvedBody || '')}
@@ -209,7 +209,7 @@ const CommonTestAndPreview = (props) => {
209
209
  wecrmAccounts = [],
210
210
  isLoadingSenderDetails = false,
211
211
  orgUnitId = -1,
212
- // notify/ui only: { commDefinitionId, referenceId } — when present, "Send test" calls CCS's send/transaction endpoint directly instead of the legacy createMessageMeta/sendTestMessage flow.
212
+ // notify/ui only: { commDefinitionId, referenceId } — routes "Send test" to CCS's send/transaction endpoint.
213
213
  ccsSendTransaction,
214
214
  // Email-specific props
215
215
  beeInstance,
@@ -46,11 +46,8 @@ import { getEnabledSteps } from './utils/getEnabledSteps';
46
46
  import messages from './messages';
47
47
  import './CommunicationFlow.scss';
48
48
 
49
- // Self-injects the same 'cap' reducer CreativesContainer already injects under this key
50
- // (see CreativesContainer/index.js's withCapReducer) — idempotent, so it's a no-op if the
51
- // consumer's own store already provides it. Guarantees makeSelectAuthenticated() below never
52
- // reads an undefined domain, regardless of whether a given consumer (e.g. coupons,
53
- // cartPromotions) wires up its own 'cap' slice.
49
+ // Self-injects the same 'cap' reducer CreativesContainer already injects under this key;
50
+ // idempotent, so it's a no-op if the consumer's own store already provides it.
54
51
  const withCapReducer = injectReducer({ key: 'cap', reducer: capReducer });
55
52
 
56
53
  const getDeliveryChannels = (contentItems) => {
@@ -64,7 +61,7 @@ const hasDeliverySettingForChannel = (channelSetting, channel) => {
64
61
  return !!settings && Object.values(settings).some((v) => v !== null && v !== '' && v !== undefined);
65
62
  };
66
63
 
67
- // createCommDefinition resolves with the CCS error envelope for 4xx/5xx responses (see api.js request()/checkStatus); duplicate referenceId within the org returns a 409.
64
+ // Duplicate referenceId within the org returns a 409 CCS error envelope.
68
65
  const isDuplicateReferenceIdError = (res) => res?.success === false && res?.status?.message === REFERENCE_ID_EXISTS;
69
66
 
70
67
  const CommunicationFlow = ({
@@ -162,12 +159,10 @@ const CommunicationFlow = ({
162
159
  if (shouldUseCCS) {
163
160
  const isMultiChannel = [CHANNEL_PRIORITY, AB_TEST].includes(aggregatedData.communicationStrategy);
164
161
  const contentItem = (aggregatedData.contentItems || [])[0];
165
- // Consumer-supplied name (e.g. CapNotify's Alert Name field) — CommunicationFlow
166
- // has no name input of its own, so this is mandatory input from config.context.
162
+ // Consumer-supplied (e.g. CapNotify's Alert Name field) — CommunicationFlow has no name input of its own.
167
163
  const name = config?.context?.name;
168
164
 
169
- // CCS create is SINGLE-strategy only this phase (D1); CHANNEL_PRIORITY/AB_TEST
170
- // carry multiple content items with no CCS equivalent yet.
165
+ // CCS create only supports SINGLE strategy; CHANNEL_PRIORITY/AB_TEST have no CCS equivalent yet.
171
166
  if (!isMultiChannel && contentItem && name) {
172
167
  const rawChannel = (contentItem.channel || '').toUpperCase();
173
168
  const channel = CCS_CHANNEL_NAME_MAP[rawChannel] || rawChannel;
@@ -177,8 +172,7 @@ const CommunicationFlow = ({
177
172
  const contentPayload = contentTransform ? contentTransform(contentItem.templateData) : contentItem.templateData;
178
173
  const { dynamicControls = {} } = aggregatedData;
179
174
  const channelSettings = aggregatedData.deliverySetting?.channelSetting?.[channel] || {};
180
- // referenceId/description are user-editable, optional fields (up until Send for
181
- // approval) — sent as '' rather than auto-generated/omitted when left blank.
175
+ // Optional fields sent as '' rather than omitted when left blank.
182
176
  const referenceId = config?.context?.referenceId || '';
183
177
  const description = config?.context?.description || '';
184
178
 
@@ -199,29 +193,35 @@ const CommunicationFlow = ({
199
193
  singleChannelStrategy: {
200
194
  variant: {
201
195
  channel,
202
- // `channel` must be spread last in both objects so CCS's normalized enum (e.g. `PUSH`) overrides the UI's internal identifier (e.g. `MOBILEPUSH`) from templateData.
196
+ // `channel` spread last so CCS's normalized enum overrides the UI's internal identifier.
203
197
  ...(contentKey && { [contentKey]: { ...contentPayload, channel } }),
204
198
  ...(deliveryKey && { [deliveryKey]: { channelSettings: { ...channelSettings, channel } } }),
205
199
  },
206
200
  },
207
201
  };
208
202
 
209
- // Editing an existing alert (e.g. rejected) uses config.context.existingCommDefinitionId to create a new DRAFT version on the same CommDefinition, preserving its id/referenceId instead of creating a new alert.
203
+ // existingCommDefinitionId (set when editing, e.g. a rejected alert) creates a new
204
+ // DRAFT version on the same CommDefinition instead of a new one.
210
205
  const { existingCommDefinitionId } = config?.context || {};
206
+ const {
207
+ referenceId: payloadReferenceId,
208
+ description: payloadDescription,
209
+ strategyType,
210
+ settings,
211
+ singleChannelStrategy,
212
+ } = payload;
211
213
 
212
214
  try {
213
215
  const res = existingCommDefinitionId
214
216
  ? await editCommDefinition(existingCommDefinitionId, {
215
- referenceId: payload.referenceId,
216
- description: payload.description,
217
- strategyType: payload.strategyType,
218
- settings: payload.settings,
219
- singleChannelStrategy: payload.singleChannelStrategy,
217
+ referenceId: payloadReferenceId,
218
+ description: payloadDescription,
219
+ strategyType,
220
+ settings,
221
+ singleChannelStrategy,
220
222
  })
221
223
  : await createCommDefinition(payload);
222
224
  if (isDuplicateReferenceIdError(res)) {
223
- // Duplicate referenceId in this org — block the save so the user can
224
- // change it, rather than silently proceeding without a CCS comm.
225
225
  setSaveError(formatMessage(messages.duplicateReferenceIdError));
226
226
  return;
227
227
  }
@@ -291,10 +291,8 @@ const CommunicationFlow = ({
291
291
  </CapRow>
292
292
  );
293
293
  case STEPS.COMMUNICATION_STRATEGY: {
294
- // No visible divider line when there's no content yet (matches the empty-state
295
- // design), but the vertical gap above the Channel card must stay either way —
296
- // see the `.communication-strategy-row` spacing rule in CommunicationFlow.scss,
297
- // which is not tied to whether the divider itself renders.
294
+ // No divider when there's no content yet, but the spacing above the Channel
295
+ // card must stay either way — see .communication-strategy-row in the scss.
298
296
  const templateStepFollows = enabledSteps.includes(STEPS.CHANNEL_SELECTION);
299
297
  const hasContent = stepData.contentItems?.length > 0;
300
298
  return (
@@ -111,10 +111,8 @@ const CommunicationFlowCard = ({
111
111
  const senderIdValue = getSenderIdValue(firstItem, savedData);
112
112
  const controls = config?.features?.dynamicControlsData?.controls || DYNAMIC_CONTROLS_CONFIG;
113
113
  const dynamicControlKeys = Object.keys(savedData?.dynamicControls || {});
114
- // Mirrors getEnabledSteps.js's own gate on this flag (which skips the in-slidebox
115
- // DynamicControlsStep) consumers like CapNotify that set showDynamicControls:
116
- // false render their own "Advanced controls" section elsewhere, so this summary
117
- // card's right column would otherwise show a redundant, always-empty control list.
114
+ // Consumers that set showDynamicControls: false render their own "Advanced
115
+ // controls" section elsewhere, so skip this card's redundant control list.
118
116
  const showDynamicControls = config?.features?.showDynamicControls !== false;
119
117
  const channel = firstItem.channel?.toUpperCase();
120
118
  const senderLabel = [WHATSAPP, RCS].includes(channel)
@@ -38,15 +38,16 @@ export const CHANNEL_PRIORITY = 'CHANNEL_PRIORITY';
38
38
  export const AB_TEST = 'AB_TEST';
39
39
  export const SINGLE_TEMPLATE = 'SINGLE_TEMPLATE';
40
40
 
41
- // CCS CommDefinition strategyType — distinct from SINGLE_TEMPLATE above, which is this UI's own communicationStrategy value. Only SINGLE is supported this phase; CCS create is skipped entirely for CHANNEL_PRIORITY/AB_TEST.
41
+ // CCS create is only supported for SINGLE (CHANNEL_PRIORITY/AB_TEST skip CCS entirely).
42
42
  export const CCS_STRATEGY_TYPE_SINGLE = 'SINGLE';
43
43
 
44
- // Mirrors CCS SingleChannelStrategy field names exactly (per Cap Notify API design samples and real create responses); kept separate from the legacy messageMeta CHANNEL_CONTENT_KEY_MAP/CHANNEL_DELIVERY_KEY_MAP.
44
+ // Mirrors CCS SingleChannelStrategy field names; kept separate from the legacy
45
+ // messageMeta CHANNEL_CONTENT_KEY_MAP/CHANNEL_DELIVERY_KEY_MAP.
45
46
  export const CCS_CHANNEL_CONTENT_KEY_MAP = {
46
47
  SMS: 'smsMessageContent',
47
48
  EMAIL: 'emailMessageContent',
48
49
  WHATSAPP: 'whatsappMessageContent',
49
- // CCS's channel enum value for mobile push is 'PUSH' (verified against real create responses), even though the content/delivery keys stay 'mpush*'.
50
+ // CCS's channel enum for mobile push is 'PUSH', but content/delivery keys stay 'mpush*'.
50
51
  PUSH: 'mpushMessageContent',
51
52
  INAPP: 'inAppMessageContent',
52
53
  ANDROID: 'androidMessageContent',
@@ -58,17 +59,16 @@ export const CCS_CHANNEL_CONTENT_KEY_MAP = {
58
59
  RCS: 'rcsMessageContent',
59
60
  };
60
61
 
61
- // contentItem.templateData uses legacy messageMeta field names, so transform mismatched channel fields before sending to CCS; for EMAIL, map legacy `emailSubject`/`emailBody` to CCS's `messageSubject`/`messageBody`.
62
+ // Transforms legacy messageMeta field names to CCS's before sending, for channels
63
+ // where the two shapes don't already match.
62
64
  export const CCS_CONTENT_TRANSFORMS = {
63
65
  EMAIL: (templateData = {}) => ({
64
66
  messageSubject: templateData.emailSubject,
65
67
  messageBody: templateData.emailBody || templateData.emailHtml,
66
68
  }),
67
- // SMS: legacy stores text as `messageBody`, while CCS expects `message`; map the field explicitly to avoid CCS returning smsMessageContent.message as null.
68
69
  SMS: (templateData = {}) => ({
69
70
  message: templateData.messageBody || '',
70
71
  }),
71
- // WEBPUSH: the legacy editor nests data under messageContent.content; flatten it to CCS's { messageSubject, accountId, content } shape and drop the legacy-only `offers` field.
72
72
  WEBPUSH: (templateData = {}) => {
73
73
  const inner = templateData.messageContent?.content || templateData;
74
74
  return {
@@ -94,12 +94,14 @@ export const CCS_CHANNEL_DELIVERY_KEY_MAP = {
94
94
  RCS: 'rcsDeliverySettings',
95
95
  };
96
96
 
97
- // The UI uses `MOBILEPUSH`, while CCS uses `PUSH` for the channel enum (verified against real create responses); normalize this value before building the CCS payload, while retaining the `mpush*` content/delivery keys. All other channel identifiers pass through unchanged.
97
+ // UI uses `MOBILEPUSH`; CCS uses `PUSH` for the channel enum. Other channels pass through.
98
98
  export const CCS_CHANNEL_NAME_MAP = {
99
99
  MOBILEPUSH: 'PUSH',
100
100
  };
101
101
 
102
- // Channel config — single source of truth for CreativesContainer and TemplatesV2; paneKey is the TemplatesV2 defaultPanes key used by channelsToHide, and channelProp is the CreativesContainer channel prop that must match pane.key for the tab to be active.
102
+ // Channel config — single source of truth for CreativesContainer and TemplatesV2.
103
+ // paneKey: TemplatesV2 defaultPanes key used by channelsToHide.
104
+ // channelProp: CreativesContainer channel prop that must match pane.key for the tab to be active.
103
105
  export const CHANNELS = [
104
106
  {
105
107
  value: 'SMS',
@@ -80,15 +80,13 @@ CommunicationFlowContainer.propTypes = {
80
80
  controls: PropTypes.array,
81
81
  }),
82
82
  }),
83
- context: PropTypes.object, // ouId, campaignId, programId; name (required for CCS create),
84
- // referenceId (optional, auto-generated from name if absent), description (optional).
85
- useCCS: PropTypes.bool, // If false, skips the CCS createCommDefinition call on save. Defaults to true.
83
+ context: PropTypes.object, // ouId, campaignId, programId, name, referenceId, description
84
+ useCCS: PropTypes.bool, // skips the CCS createCommDefinition call on save when false; defaults to true
86
85
  }).isRequired,
87
86
  initialData: PropTypes.object, // for edit/preview mode
88
- onSave: PropTypes.func.isRequired, // (data) => void - called when user saves; data.ccsCommDefinition
89
- // ({id, referenceId, version, status}) is present when the CCS create succeeded
90
- onCancel: PropTypes.func.isRequired, // () => void - called when user cancels
91
- onChange: PropTypes.func, // (data) => void - optional, called on data changes
87
+ onSave: PropTypes.func.isRequired, // (data) => void, data.ccsCommDefinition set when CCS create succeeded
88
+ onCancel: PropTypes.func.isRequired, // () => void
89
+ onChange: PropTypes.func, // (data) => void
92
90
  };
93
91
 
94
92
  CommunicationFlowContainer.defaultProps = {