@capillarytech/creatives-library 9.0.54-alpha.3 → 9.0.54-alpha.4

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.54-alpha.3",
4
+ "version": "9.0.54-alpha.4",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/services/api.js CHANGED
@@ -710,6 +710,17 @@ export const createCommDefinition = (payload) => {
710
710
  return request(url, getAPICallObject('POST', payload, false, false, false, true));
711
711
  };
712
712
 
713
+ // Opens a new DRAFT version with the given content on an EXISTING
714
+ // CommDefinition (same id/referenceId) — used by CommunicationFlow's edit-mode
715
+ // save (re-editing a rejected alert) instead of createCommDefinition, so the
716
+ // alert keeps its identity rather than becoming a brand-new CommDefinition.
717
+ // Route verified against a real Postman sample against Veyron's own
718
+ // /commdefinition/{id}/edit endpoint.
719
+ export const editCommDefinition = (commDefinitionId, payload) => {
720
+ const url = `${API_ENDPOINT}/comm-definitions/${commDefinitionId}/edit`;
721
+ return request(url, getAPICallObject('POST', payload, false, false, false, true));
722
+ };
723
+
713
724
  export const getCentralCommsMetaIds = (metaIds, metaType = TRANSACTION) => {
714
725
  const url = `${API_ENDPOINT}/common/central-comms/meta-id/${metaType}?metaIds=${metaIds}`;
715
726
  return request(url, getAPICallObject('GET', null, false, false, false, true));
@@ -21,7 +21,7 @@ import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
21
21
  // import injectSaga from '../../utils/injectSaga'; // cap-coupons flows disabled
22
22
  // import injectReducer from '../../utils/injectReducer';
23
23
  import { makeSelectAuthenticated } from '../Cap/selectors';
24
- import { createCommDefinition } from '../../services/api';
24
+ import { createCommDefinition, editCommDefinition } from '../../services/api';
25
25
  import DynamicControlsStep from './steps/DynamicControlsStep';
26
26
  import MessageTypeStep from './steps/MessageTypeStep';
27
27
  import CommunicationStrategyStep from './steps/CommunicationStrategyStep';
@@ -225,8 +225,19 @@ const CommunicationFlow = ({
225
225
  },
226
226
  };
227
227
 
228
+ // Editing an existing (e.g. rejected) alert: config.context.existingCommDefinitionId
229
+ // opens a new DRAFT version on that SAME CommDefinition instead of creating a
230
+ // brand-new one, so the alert keeps its id/referenceId across the edit.
231
+ const { existingCommDefinitionId } = config?.context || {};
232
+
228
233
  try {
229
- const res = await createCommDefinition(payload);
234
+ const res = existingCommDefinitionId
235
+ ? await editCommDefinition(existingCommDefinitionId, {
236
+ strategyType: payload.strategyType,
237
+ settings: payload.settings,
238
+ singleChannelStrategy: payload.singleChannelStrategy,
239
+ })
240
+ : await createCommDefinition(payload);
230
241
  if (isDuplicateReferenceIdError(res)) {
231
242
  // Duplicate referenceId in this org — block the save so the user can
232
243
  // change it, rather than silently proceeding without a CCS comm.
@@ -234,7 +245,16 @@ const CommunicationFlow = ({
234
245
  return;
235
246
  }
236
247
  const data = res?.response?.data;
237
- if (data?.id) {
248
+ if (existingCommDefinitionId) {
249
+ if (data) {
250
+ ccsCommDefinition = {
251
+ id: existingCommDefinitionId,
252
+ referenceId: referenceId || data.referenceId,
253
+ version: data.version?.version ?? data.version ?? 1,
254
+ status: data.status,
255
+ };
256
+ }
257
+ } else if (data?.id) {
238
258
  ccsCommDefinition = {
239
259
  id: data.id,
240
260
  referenceId: data.referenceId,
@@ -2,6 +2,7 @@ import React from 'react';
2
2
 
3
3
  jest.mock('../../../services/api', () => ({
4
4
  createCommDefinition: jest.fn(),
5
+ editCommDefinition: jest.fn(),
5
6
  }));
6
7
 
7
8
  jest.mock('../../CreativesContainer', () => function MockCreativesContainer({
@@ -37,7 +38,7 @@ import { IntlProvider } from 'react-intl';
37
38
  import history from '../../../utils/history';
38
39
  import { initialReducer } from '../../../initialReducer';
39
40
  import CommunicationFlow from '../CommunicationFlow';
40
- import { createCommDefinition } from '../../../services/api';
41
+ import { createCommDefinition, editCommDefinition } from '../../../services/api';
41
42
  import { getEnabledSteps } from '../utils/getEnabledSteps';
42
43
  import {
43
44
  CHANNELS,
@@ -738,6 +739,86 @@ describe('handleSave — CCS flow', () => {
738
739
  gsmSenderId: 'BRAND1',
739
740
  });
740
741
  });
742
+
743
+ it('does not call editCommDefinition when config.context.existingCommDefinitionId is absent', async () => {
744
+ const onSave = jest.fn();
745
+ renderWithFlow({
746
+ features: {},
747
+ config: ccsConfig,
748
+ initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
749
+ onSave,
750
+ });
751
+
752
+ await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
753
+
754
+ await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
755
+ expect(editCommDefinition).not.toHaveBeenCalled();
756
+ });
757
+
758
+ it('calls editCommDefinition (not createCommDefinition) and merges the existing id into ccsCommDefinition when config.context.existingCommDefinitionId is set', async () => {
759
+ editCommDefinition.mockResolvedValue({
760
+ response: { data: { version: { version: 2 }, status: 'DRAFT' } },
761
+ });
762
+ const onSave = jest.fn();
763
+ renderWithFlow({
764
+ features: {},
765
+ config: {
766
+ ...ccsConfig,
767
+ context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', existingCommDefinitionId: 'cd_existing_1' },
768
+ },
769
+ initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
770
+ onSave,
771
+ });
772
+
773
+ await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
774
+
775
+ await waitFor(() => expect(editCommDefinition).toHaveBeenCalledTimes(1));
776
+ expect(editCommDefinition).toHaveBeenCalledWith(
777
+ 'cd_existing_1',
778
+ expect.objectContaining({
779
+ strategyType: 'SINGLE',
780
+ settings: expect.anything(),
781
+ singleChannelStrategy: expect.anything(),
782
+ }),
783
+ );
784
+ expect(createCommDefinition).not.toHaveBeenCalled();
785
+
786
+ await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
787
+ expect(onSave).toHaveBeenCalledWith(
788
+ expect.objectContaining({
789
+ ccsCommDefinition: {
790
+ id: 'cd_existing_1',
791
+ referenceId: 'ORDER_PLACED',
792
+ version: 2,
793
+ status: 'DRAFT',
794
+ },
795
+ }),
796
+ );
797
+ });
798
+
799
+ it('blocks save and shows an error when editCommDefinition resolves with a duplicate REFERENCE_ID_EXISTS conflict', async () => {
800
+ editCommDefinition.mockResolvedValue({
801
+ success: false,
802
+ status: { isError: true, code: 409, message: 'REFERENCE_ID_EXISTS' },
803
+ message: 'REFERENCE_ID_EXISTS',
804
+ });
805
+ const onSave = jest.fn();
806
+ renderWithFlow({
807
+ features: {},
808
+ config: {
809
+ ...ccsConfig,
810
+ context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', existingCommDefinitionId: 'cd_existing_1' },
811
+ },
812
+ initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
813
+ onSave,
814
+ });
815
+
816
+ await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
817
+
818
+ await waitFor(() => expect(editCommDefinition).toHaveBeenCalledTimes(1));
819
+ expect(await screen.findByText(/already in use in your organization/i)).toBeInTheDocument();
820
+ expect(onSave).not.toHaveBeenCalled();
821
+ });
741
822
  });
742
823
 
743
824
  describe('renderSteps — null returns and edge cases', () => {