@capillarytech/creatives-library 9.0.70-alpha.sprint-cap-213712.13 → 9.0.70

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 (39) hide show
  1. package/package.json +1 -1
  2. package/v2Components/FormBuilder/Classic.js +3 -0
  3. package/v2Containers/CreativesContainer/SlideBoxContent.js +39 -30
  4. package/v2Containers/CreativesContainer/SlideBoxFooter.js +6 -2
  5. package/v2Containers/CreativesContainer/constants.js +1 -0
  6. package/v2Containers/CreativesContainer/index.js +26 -1
  7. package/v2Containers/CreativesContainer/messages.js +4 -0
  8. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +40 -12
  9. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +10 -0
  10. package/v2Containers/CreativesContainer/tests/switchToEditAfterCreate.test.js +152 -0
  11. package/v2Containers/Email/index.js +41 -6
  12. package/v2Containers/Email/tests/index.test.js +123 -0
  13. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +32 -12
  14. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +34 -0
  15. package/v2Containers/InApp/index.js +19 -23
  16. package/v2Containers/InApp/tests/index.test.js +52 -9
  17. package/v2Containers/InappAdvance/index.js +19 -24
  18. package/v2Containers/InappAdvance/tests/index.test.js +39 -15
  19. package/v2Containers/Line/Container/index.js +18 -8
  20. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +129 -108
  21. package/v2Containers/Line/Container/tests/index.test.js +68 -0
  22. package/v2Containers/MobilePush/Create/index.js +24 -5
  23. package/v2Containers/MobilePush/Create/test/stayOpenOnSave.test.js +80 -0
  24. package/v2Containers/MobilePush/Edit/index.js +15 -9
  25. package/v2Containers/MobilePush/Edit/test/stayOpenOnSave.test.js +60 -0
  26. package/v2Containers/MobilePushNew/index.js +41 -7
  27. package/v2Containers/MobilePushNew/tests/index.test.js +61 -0
  28. package/v2Containers/Sms/Create/index.js +32 -14
  29. package/v2Containers/Sms/Create/test/stayOpenOnSave.test.js +92 -0
  30. package/v2Containers/Sms/Edit/index.js +22 -14
  31. package/v2Containers/Sms/Edit/tests/index.test.js +66 -0
  32. package/v2Containers/Templates/index.js +17 -4
  33. package/v2Containers/Viber/index.js +15 -6
  34. package/v2Containers/Viber/tests/index.test.js +97 -28
  35. package/v2Containers/WebPush/Create/components/FormActions.js +1 -1
  36. package/v2Containers/WebPush/Create/components/FormActions.test.js +3 -3
  37. package/v2Containers/WebPush/Create/index.js +32 -6
  38. package/v2Containers/WebPush/Create/messages.js +0 -4
  39. package/v2Containers/WebPush/Create/tests/stayOpenOnSave.test.js +268 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "9.0.70-alpha.sprint-cap-213712.13",
4
+ "version": "9.0.70",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -3327,6 +3327,9 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3327
3327
  let computedStyle = val.style ?? {};
3328
3328
  if (val.id === EXPORT_HTML_LABEL_ID && this.props?.exportHtmlLocked) {
3329
3329
  computedStyle = { ...computedStyle, opacity: 0.5, cursor: 'not-allowed', pointerEvents: 'none' };
3330
+ } else if (val.id === EXPORT_HTML_LABEL_ID && this.props?.exportHtmlEnabled) {
3331
+ // Enabled after an in-place save; prop-driven, like the lock above.
3332
+ computedStyle = { ...computedStyle, opacity: 1, cursor: 'pointer', pointerEvents: 'auto' };
3330
3333
  }
3331
3334
  const divElement = (
3332
3335
  <div
@@ -20,6 +20,7 @@ import { RICH_MEDIA, MAP_TEMPLATE, CREATE } from '../WeChat/Wrapper/constants';
20
20
  import CallTask from '../CallTask';
21
21
  import MobliPushEdit from '../MobilePush/Edit';
22
22
  import * as constants from './constants';
23
+ import { SMS as SMS_LOWERCASE } from '../../constants/unified';
23
24
  import LineContainer from '../Line/Container';
24
25
  import FTP from '../FTP';
25
26
  import Viber from '../Viber';
@@ -184,6 +185,8 @@ export function SlideBoxContent(props) {
184
185
  onHtmlEditorValidationStateChange,
185
186
  onEmbeddedSmsFooterValidity,
186
187
  onContentValidityChange,
188
+ canStayOpenAfterCreate,
189
+ onCreateContinuedAsEdit,
187
190
  } = props;
188
191
  const localTemplatesConfig = props.localTemplatesConfig || pick(props, constants.LOCAL_TEMPLATE_CONFIG_KEYS);
189
192
  const useLocalTemplates = !!get(localTemplatesConfig, 'useLocalTemplates');
@@ -262,6 +265,35 @@ export function SlideBoxContent(props) {
262
265
  isEditInApp = isEdit && channel === constants.INAPP;
263
266
  }
264
267
  const isDltEnabled = commonUtil.isTraiDLTEnable(isFullMode, smsRegister);
268
+
269
+ // Shared by the regular and background (create → edit) SMS Edit; each adds its own templateData.
270
+ const smsEditWrapperProps = {
271
+ showLiquidErrorInFooter,
272
+ setIsLoadingContent,
273
+ isEditSms: true,
274
+ location: creativesLocationProps,
275
+ isFullMode,
276
+ route: { name: SMS_LOWERCASE },
277
+ isGetFormData,
278
+ getFormSubscriptionData: getFormData,
279
+ getDefaultTags: type,
280
+ forwardedTags,
281
+ selectedOfferDetails,
282
+ onPreviewContentClicked,
283
+ onTestContentClicked,
284
+ handleClose,
285
+ onCreateComplete,
286
+ smsRegister,
287
+ eventContextTags,
288
+ waitEventContextTags,
289
+ getLiquidTags,
290
+ showTestAndPreviewSlidebox,
291
+ handleTestAndPreview,
292
+ handleCloseTestAndPreview,
293
+ isTestAndPreviewMode,
294
+ onValidationFail,
295
+ onEmbeddedSmsFooterValidity,
296
+ };
265
297
  const hasJPLocaleHideFeatureEnabled = commonUtil?.hasJPLocaleHideFeatureEnabled();
266
298
 
267
299
  const getChannelPreviewContent = (templateDataObject) => {
@@ -579,35 +611,7 @@ export function SlideBoxContent(props) {
579
611
  />
580
612
  }
581
613
  {isEditSms && (
582
- <SmsWrapper
583
- showLiquidErrorInFooter={showLiquidErrorInFooter}
584
- setIsLoadingContent={setIsLoadingContent}
585
- isEditSms={isEditSms}
586
- location={creativesLocationProps}
587
- isFullMode={isFullMode}
588
- route={{ name: 'sms' }}
589
- params={{id: templateData._id}}
590
- isGetFormData={isGetFormData}
591
- getFormSubscriptionData={getFormData}
592
- getDefaultTags={type}
593
- templateData={templateData}
594
- forwardedTags={forwardedTags}
595
- selectedOfferDetails={selectedOfferDetails}
596
- onPreviewContentClicked={onPreviewContentClicked}
597
- onTestContentClicked={onTestContentClicked}
598
- handleClose={handleClose}
599
- onCreateComplete={onCreateComplete}
600
- smsRegister={smsRegister}
601
- eventContextTags={eventContextTags}
602
- waitEventContextTags={waitEventContextTags}
603
- getLiquidTags={getLiquidTags}
604
- showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
605
- handleTestAndPreview={handleTestAndPreview}
606
- handleCloseTestAndPreview={handleCloseTestAndPreview}
607
- isTestAndPreviewMode={isTestAndPreviewMode}
608
- onValidationFail={onValidationFail}
609
- onEmbeddedSmsFooterValidity={onEmbeddedSmsFooterValidity}
610
- />
614
+ <SmsWrapper {...smsEditWrapperProps} templateData={templateData} />
611
615
  )}
612
616
  {isEditFTP && (
613
617
  <FTP
@@ -667,7 +671,7 @@ export function SlideBoxContent(props) {
667
671
  showLiquidErrorInFooter={showLiquidErrorInFooter}
668
672
  setIsLoadingContent={setIsLoadingContent}
669
673
  location={creativesLocationProps}
670
- route={{ name: 'sms' }}
674
+ route={{ name: SMS_LOWERCASE }}
671
675
  isCreateSms={isCreateSms}
672
676
  isComponent
673
677
  templateData={templateData}
@@ -1289,6 +1293,8 @@ export function SlideBoxContent(props) {
1289
1293
  isAnonymousType={isAnonymousType}
1290
1294
  waitEventContextTags={waitEventContextTags}
1291
1295
  onContentValidityChange={onContentValidityChange}
1296
+ canStayOpenAfterCreate={canStayOpenAfterCreate}
1297
+ onCreateContinuedAsEdit={onCreateContinuedAsEdit}
1292
1298
  />
1293
1299
  )}
1294
1300
  {isCreateRcs && (<Rcs
@@ -1349,6 +1355,9 @@ SlideBoxContent.propTypes = {
1349
1355
  onResetStep: PropTypes.func,
1350
1356
  onCallTaskSubmit: PropTypes.func,
1351
1357
  isFullMode: PropTypes.bool,
1358
+ // Full mode: host allows a create to continue in place as an edit (edit permission)
1359
+ canStayOpenAfterCreate: PropTypes.bool,
1360
+ onCreateContinuedAsEdit: PropTypes.func,
1352
1361
  setIsLoadingContent: PropTypes.func,
1353
1362
  onMobilepushModeChange: PropTypes.func,
1354
1363
  mobilePushCreateMode: PropTypes.string,
@@ -11,7 +11,11 @@ import { EMAIL_CREATE_MODES } from '../EmailWrapper/constants';
11
11
  import { hasSupportCKEditor } from '../../utils/common';
12
12
  import { getMessageForDevice, getTitleForDevice } from '../../utils/commonUtils';
13
13
 
14
- function getFullModeSaveBtn(slidBoxContent, isCreatingTemplate) {
14
+ function getFullModeSaveBtn(slidBoxContent, isCreatingTemplate, isStayOpenChannel) {
15
+ // Email / push: "Save" in both modes
16
+ if (isStayOpenChannel) {
17
+ return <FormattedMessage {...messages.creativesTemplatesSaveButton} />;
18
+ }
15
19
  if (isCreatingTemplate) {
16
20
  return <FormattedMessage {...messages.creativesTemplatesDone} />;
17
21
  }
@@ -171,7 +175,7 @@ function SlideBoxFooter(props) {
171
175
 
172
176
  function getSaveButtonLabel() {
173
177
  if (primarySaveButtonMessage) return <FormattedMessage {...primarySaveButtonMessage} />;
174
- if (isFullMode) return getFullModeSaveBtn(slidBoxContent, isCreatingTemplate);
178
+ if (isFullMode) return getFullModeSaveBtn(slidBoxContent, isCreatingTemplate, isEmailChannel || isMobilePushChannel);
175
179
  return <FormattedMessage {...messages.creativesTemplatesSave} />;
176
180
  }
177
181
 
@@ -25,6 +25,7 @@ export const INAPP = "INAPP";
25
25
  export const WEBPUSH = "WEBPUSH";
26
26
  export const WEBPUSH_BRAND_ICON = "WEBPUSH_BRAND_ICON";
27
27
  export const PREVIEW = "preview";
28
+ export const CREATE_TEMPLATE = "createTemplate";
28
29
  export const EDIT_TEMPLATE = "editTemplate";
29
30
  export const JOURNEY = "journey";
30
31
  export const HTML = "HTML";
@@ -200,6 +200,8 @@ export class Creatives extends React.Component {
200
200
  // Live content-validity signal for channels that report it (currently SMS create) —
201
201
  // false by default so unwired channels are never blocked by this flag.
202
202
  isContentInvalid: false,
203
+ // Full mode: a create continued in place as an edit (form kept) — header shows the edit title
204
+ isCreateContinuedAsEdit: false,
203
205
  };
204
206
  this.creativesTemplateSteps = {
205
207
  1: 'modeSelection',
@@ -1703,7 +1705,24 @@ export class Creatives extends React.Component {
1703
1705
  };
1704
1706
  }
1705
1707
 
1708
+ // Channel kept its form after a create and will update on the next save: show the edit header
1709
+ handleCreateContinuedAsEdit = () => {
1710
+ if (!this.state.isCreateContinuedAsEdit) {
1711
+ this.setState({ isCreateContinuedAsEdit: true });
1712
+ }
1713
+ };
1714
+
1706
1715
  getFormData = (template) => {
1716
+ // Full-mode save that stays open: host only refreshes its list (creates need edit permission).
1717
+ const canStayOpen = this.state.slidBoxContent !== constants.CREATE_TEMPLATE || this.props.switchToEditAfterCreate;
1718
+ if (this.props.isFullMode && template?.keepSlideBoxOpen && canStayOpen) {
1719
+ this.setState({ isGetFormData: false });
1720
+ if (template.continuedAsEdit) {
1721
+ this.handleCreateContinuedAsEdit(); // header switches to the edit title
1722
+ }
1723
+ this.props.getCreativesData({ channel: this.state.currentChannel?.toUpperCase(), keepSlideBoxOpen: true });
1724
+ return;
1725
+ }
1707
1726
  // Always reset isGetFormData so the child does not re-send form data on every re-render
1708
1727
  // (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
1709
1728
  this.setState(
@@ -2336,7 +2355,10 @@ export class Creatives extends React.Component {
2336
2355
  key="creatives-container-slidebox-header"
2337
2356
  channel={currentChannel}
2338
2357
  messages={this.props.messages}
2339
- slidBoxContent={this.state.slidBoxContent}
2358
+ // Edit title after an in-place create
2359
+ slidBoxContent={this.state.isCreateContinuedAsEdit && this.state.slidBoxContent === constants.CREATE_TEMPLATE
2360
+ ? constants.EDIT_TEMPLATE
2361
+ : this.state.slidBoxContent}
2340
2362
  templateData={templateData}
2341
2363
  onShowTemplates={this.onShowTemplates}
2342
2364
  creativesMode={creativesMode}
@@ -2439,6 +2461,8 @@ export class Creatives extends React.Component {
2439
2461
  onContentValidityChange={this.handleContentValidityChange}
2440
2462
  onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
2441
2463
  localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
2464
+ canStayOpenAfterCreate={!!(isFullMode && this.props.switchToEditAfterCreate)}
2465
+ onCreateContinuedAsEdit={this.handleCreateContinuedAsEdit}
2442
2466
  />
2443
2467
  )}
2444
2468
  footer={this.shouldShowFooter() ? (
@@ -2505,6 +2529,7 @@ Creatives.propTypes = {
2505
2529
  handleCloseCreatives: PropTypes.func,
2506
2530
  templateData: PropTypes.object,
2507
2531
  isFullMode: PropTypes.bool,
2532
+ switchToEditAfterCreate: PropTypes.bool,
2508
2533
  channel: PropTypes.string,
2509
2534
  templateActions: PropTypes.object,
2510
2535
  globalActions: PropTypes.object,
@@ -282,6 +282,10 @@ export default defineMessages({
282
282
  id: `${scope}.creativesTemplatesUpdate`,
283
283
  defaultMessage: `Update`,
284
284
  },
285
+ "creativesTemplatesSaveButton": {
286
+ id: `${scope}.creativesTemplatesSaveButton`,
287
+ defaultMessage: `Save`,
288
+ },
285
289
  "creativesTemplatesDone": {
286
290
  id: `${scope}.creativesTemplatesDone`,
287
291
  defaultMessage: `Done`,
@@ -61,7 +61,7 @@ describe("test for empty email empty template name", () => {
61
61
  renderComponent(props);
62
62
  const errorMessage = await screen.findByText(/template name cannot be empty/i);
63
63
  expect(errorMessage).toBeInTheDocument();
64
- const updateBtn = screen.getByRole('button', { name: /update/i });
64
+ const updateBtn = screen.getByRole('button', { name: /^save$/i });
65
65
  expect(updateBtn).toBeDisabled();
66
66
  renderComponent({
67
67
  ...props,
@@ -71,7 +71,7 @@ describe("test for empty email empty template name", () => {
71
71
  issueCounts: { html: 0, label: 0, liquid: 0, total: 0 },
72
72
  },
73
73
  });
74
- const updateBtns = screen.getAllByRole('button', { name: /update/i });
74
+ const updateBtns = screen.getAllByRole('button', { name: /^save$/i });
75
75
  expect(updateBtns[1]).toBeEnabled();
76
76
  });
77
77
  });
@@ -96,7 +96,7 @@ describe('shouldCheckValidation (line 79)', () => {
96
96
  issueCounts: { html: 1, label: 0, liquid: 0, total: 1 },
97
97
  },
98
98
  });
99
- const updateBtn = screen.getByRole('button', { name: /update/i });
99
+ const updateBtn = screen.getByRole('button', { name: /^save$/i });
100
100
  expect(updateBtn).toBeDisabled();
101
101
  });
102
102
 
@@ -115,7 +115,7 @@ describe('shouldCheckValidation (line 79)', () => {
115
115
  issueCounts: { html: 0, label: 0, liquid: 0, total: 0 },
116
116
  },
117
117
  });
118
- const updateBtn = screen.getByRole('button', { name: /update/i });
118
+ const updateBtn = screen.getByRole('button', { name: /^save$/i });
119
119
  expect(updateBtn).toBeEnabled();
120
120
  });
121
121
 
@@ -147,7 +147,7 @@ describe('shouldCheckValidation (line 79)', () => {
147
147
  slidBoxContent: 'editTemplate',
148
148
  htmlEditorValidationState: null,
149
149
  });
150
- const updateBtn = screen.getByRole('button', { name: /update/i });
150
+ const updateBtn = screen.getByRole('button', { name: /^save$/i });
151
151
  expect(updateBtn).toBeEnabled();
152
152
  });
153
153
 
@@ -166,7 +166,7 @@ describe('shouldCheckValidation (line 79)', () => {
166
166
  issueCounts: { html: 1, label: 0, liquid: 0, total: 1 },
167
167
  },
168
168
  });
169
- const updateBtn = screen.getByRole('button', { name: /update/i });
169
+ const updateBtn = screen.getByRole('button', { name: /^save$/i });
170
170
  expect(updateBtn).toBeEnabled();
171
171
  });
172
172
 
@@ -187,7 +187,7 @@ describe('shouldCheckValidation (line 79)', () => {
187
187
  issueCounts: { html: 0, label: 0, liquid: 0, total: 0 },
188
188
  },
189
189
  });
190
- const saveBtn = screen.getByRole('button', { name: /create/i });
190
+ const saveBtn = screen.getByRole('button', { name: /^save$/i });
191
191
  expect(saveBtn).toBeDisabled();
192
192
  });
193
193
 
@@ -555,7 +555,7 @@ describe('SlideBoxFooter — isHtmlEditorValidationStateActive via issueCounts',
555
555
  // isHtmlEditorValidationStateActive = true (via issueCounts.total > 0)
556
556
  // isHTMLEditorModeInEdit = true, shouldCheckValidation = true
557
557
  // hasValidationErrors = false, shouldDisableButtons = false (no hasErrors)
558
- const updateBtn = screen.getByRole('button', { name: /update/i });
558
+ const updateBtn = screen.getByRole('button', { name: /^save$/i });
559
559
  expect(updateBtn).toBeEnabled();
560
560
  });
561
561
 
@@ -578,7 +578,7 @@ describe('SlideBoxFooter — isHtmlEditorValidationStateActive via issueCounts',
578
578
  // isHtmlEditorValidationStateActive = false → isHTMLEditorModeInEdit = false
579
579
  // isBEEEditor = true (isEditMode && !isHtmlEditorValidationStateActive)
580
580
  // shouldCheckValidation = false → button enabled
581
- const updateBtn = screen.getByRole('button', { name: /update/i });
581
+ const updateBtn = screen.getByRole('button', { name: /^save$/i });
582
582
  expect(updateBtn).toBeEnabled();
583
583
  });
584
584
  });
@@ -607,7 +607,7 @@ describe('SlideBoxFooter — isBEEEditor detection in create mode via emailCreat
607
607
  });
608
608
  // selectedEmailCreateMode=drag_drop → isBEEEditor = true (DRAG_DROP branch)
609
609
  // shouldCheckValidation = false → button not disabled by validation
610
- const createBtn = screen.getByRole('button', { name: /create/i });
610
+ const createBtn = screen.getByRole('button', { name: /^save$/i });
611
611
  expect(createBtn).toBeInTheDocument();
612
612
  });
613
613
 
@@ -630,7 +630,7 @@ describe('SlideBoxFooter — isBEEEditor detection in create mode via emailCreat
630
630
  });
631
631
  // isHTMLEditorModeInCreate = false (selectedEmailCreateMode is undefined, not html_editor)
632
632
  // emailCreateMode === 'editor' && !isHTMLEditorMode → isBEEEditor = true
633
- const createBtn = screen.getByRole('button', { name: /create/i });
633
+ const createBtn = screen.getByRole('button', { name: /^save$/i });
634
634
  expect(createBtn).toBeInTheDocument();
635
635
  expect(createBtn).not.toBeDisabled();
636
636
  });
@@ -687,4 +687,32 @@ describe('SlideBoxFooter — isContentInvalid (live content-validity signal, e.g
687
687
  });
688
688
  expect(screen.getByRole('button', { name: /update/i })).not.toBeDisabled();
689
689
  });
690
- });
690
+ });
691
+
692
+ describe('SlideBoxFooter — full-mode email button label', () => {
693
+ it.each([
694
+ ['create', 'createTemplate', true],
695
+ ['edit', 'editTemplate', false],
696
+ ])('reads "Save" in %s mode', (_mode, slidBoxContent, isCreatingTemplate) => {
697
+ renderComponent({
698
+ ...baseFooterProps,
699
+ currentChannel: 'EMAIL',
700
+ slidBoxContent,
701
+ isCreatingTemplate,
702
+ });
703
+ expect(screen.getByRole('button', { name: /^save$/i })).toBeInTheDocument();
704
+ });
705
+ });
706
+ describe('SlideBoxFooter — full-mode push notification button label', () => {
707
+ it.each([
708
+ ['create', 'createTemplate'],
709
+ ['edit', 'editTemplate'],
710
+ ])('reads "Save" in %s mode', (_mode, slidBoxContent) => {
711
+ renderComponent({
712
+ ...baseFooterProps,
713
+ currentChannel: 'MOBILEPUSH',
714
+ slidBoxContent,
715
+ });
716
+ expect(screen.getByRole('button', { name: /^save$/i })).toBeInTheDocument();
717
+ });
718
+ });
@@ -9,6 +9,7 @@ exports[`Test SlideBoxContent container campaign message, add creative click rcs
9
9
  <CapSlideBox
10
10
  content={
11
11
  <SlideBoxContent
12
+ canStayOpenAfterCreate={false}
12
13
  channelsToHide={Array []}
13
14
  currentChannel="RCS"
14
15
  customerType=""
@@ -30,6 +31,7 @@ exports[`Test SlideBoxContent container campaign message, add creative click rcs
30
31
  onChannelChange={[Function]}
31
32
  onContentValidityChange={[Function]}
32
33
  onCreateComplete={[MockFunction]}
34
+ onCreateContinuedAsEdit={[Function]}
33
35
  onCreateNew={[Function]}
34
36
  onCreateNextStep={[Function]}
35
37
  onEmailModeChange={[Function]}
@@ -105,6 +107,7 @@ exports[`Test SlideBoxContent container campaign message, add creative click wha
105
107
  <CapSlideBox
106
108
  content={
107
109
  <SlideBoxContent
110
+ canStayOpenAfterCreate={false}
108
111
  channelsToHide={Array []}
109
112
  currentChannel="WHATSAPP"
110
113
  customerType=""
@@ -126,6 +129,7 @@ exports[`Test SlideBoxContent container campaign message, add creative click wha
126
129
  onChannelChange={[Function]}
127
130
  onContentValidityChange={[Function]}
128
131
  onCreateComplete={[MockFunction]}
132
+ onCreateContinuedAsEdit={[Function]}
129
133
  onCreateNew={[Function]}
130
134
  onCreateNextStep={[Function]}
131
135
  onEmailModeChange={[Function]}
@@ -201,6 +205,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit all data
201
205
  <CapSlideBox
202
206
  content={
203
207
  <SlideBoxContent
208
+ canStayOpenAfterCreate={false}
204
209
  channelsToHide={Array []}
205
210
  currentChannel="WHATSAPP"
206
211
  customerType=""
@@ -222,6 +227,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit all data
222
227
  onChannelChange={[Function]}
223
228
  onContentValidityChange={[Function]}
224
229
  onCreateComplete={[MockFunction]}
230
+ onCreateContinuedAsEdit={[Function]}
225
231
  onCreateNew={[Function]}
226
232
  onCreateNextStep={[Function]}
227
233
  onEmailModeChange={[Function]}
@@ -341,6 +347,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit min data
341
347
  <CapSlideBox
342
348
  content={
343
349
  <SlideBoxContent
350
+ canStayOpenAfterCreate={false}
344
351
  channelsToHide={Array []}
345
352
  currentChannel="WHATSAPP"
346
353
  customerType=""
@@ -362,6 +369,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit min data
362
369
  onChannelChange={[Function]}
363
370
  onContentValidityChange={[Function]}
364
371
  onCreateComplete={[MockFunction]}
372
+ onCreateContinuedAsEdit={[Function]}
365
373
  onCreateNew={[Function]}
366
374
  onCreateNextStep={[Function]}
367
375
  onEmailModeChange={[Function]}
@@ -481,6 +489,7 @@ exports[`Test SlideBoxContent container it should clear the url, on channel chan
481
489
  <CapSlideBox
482
490
  content={
483
491
  <SlideBoxContent
492
+ canStayOpenAfterCreate={false}
484
493
  channelsToHide={Array []}
485
494
  currentChannel="WHATSAPP"
486
495
  customerType=""
@@ -502,6 +511,7 @@ exports[`Test SlideBoxContent container it should clear the url, on channel chan
502
511
  onChannelChange={[Function]}
503
512
  onContentValidityChange={[Function]}
504
513
  onCreateComplete={[MockFunction]}
514
+ onCreateContinuedAsEdit={[Function]}
505
515
  onCreateNew={[Function]}
506
516
  onCreateNextStep={[Function]}
507
517
  onEmailModeChange={[Function]}
@@ -0,0 +1,152 @@
1
+ import React from 'react';
2
+ import { shallowWithIntl } from '../../../helpers/intl-enzym-test-helpers';
3
+
4
+ import { Creatives } from '../index';
5
+ import { SMS } from '../constants';
6
+
7
+ jest.mock('../../../v2Components/FormBuilder', () => ({
8
+ __esModule: true,
9
+ default: () => <div className="FormBuilder-mock">FormBuilder</div>,
10
+ }));
11
+
12
+ describe('CreativesContainer: full-mode SMS create continues in place', () => {
13
+ const getCreativesData = jest.fn();
14
+ const handleCloseCreatives = jest.fn();
15
+
16
+ const render = (props = {}) => shallowWithIntl(
17
+ <Creatives
18
+ isFullMode
19
+ creativesMode="create"
20
+ channel="SMS"
21
+ templateData={{ mode: 'create' }}
22
+ Templates={{}}
23
+ getCreativesData={getCreativesData}
24
+ handleCloseCreatives={handleCloseCreatives}
25
+ switchToEditAfterCreate
26
+ {...props}
27
+ />,
28
+ );
29
+
30
+ beforeEach(() => jest.clearAllMocks());
31
+
32
+ it('create save: stays open, refreshes the host list and switches the header (content stays as is)', () => {
33
+ const wrapper = render();
34
+ wrapper.instance().getFormData({ _id: 'tpl-1', validity: true, keepSlideBoxOpen: true, continuedAsEdit: true });
35
+ wrapper.update();
36
+
37
+ expect(getCreativesData).toHaveBeenCalledWith({ channel: SMS, keepSlideBoxOpen: true });
38
+ expect(handleCloseCreatives).not.toHaveBeenCalled();
39
+ expect(wrapper.state('slidBoxContent')).toBe('createTemplate');
40
+ expect(wrapper.find('CapSlideBox').prop('header').props.slidBoxContent).toBe('editTemplate');
41
+ });
42
+
43
+ it('on an edit save in full mode, keeps the slidebox open and only lets the host refresh', () => {
44
+ const instance = render({ creativesMode: 'edit', templateData: { _id: 'tpl-1', type: SMS } }).instance();
45
+ expect(instance.state.slidBoxContent).toBe('editTemplate');
46
+ instance.setState({ isGetFormData: true });
47
+ instance.getFormData({ value: { base: {} }, _id: 'tpl-1', validity: true, keepSlideBoxOpen: true });
48
+
49
+ expect(instance.state.slidBoxContent).toBe('editTemplate');
50
+ expect(instance.state.showSlideBox).toBe(true);
51
+ expect(instance.state.isGetFormData).toBe(false);
52
+ expect(getCreativesData).toHaveBeenCalledTimes(1);
53
+ expect(getCreativesData).toHaveBeenCalledWith({ channel: SMS, keepSlideBoxOpen: true });
54
+ expect(handleCloseCreatives).not.toHaveBeenCalled();
55
+ });
56
+
57
+ it('create save without edit permission closes as before (no header switch)', () => {
58
+ const wrapper = render({ switchToEditAfterCreate: false });
59
+ wrapper.instance().getFormData({ _id: 'tpl-1', validity: true, keepSlideBoxOpen: true, continuedAsEdit: true });
60
+
61
+ expect(getCreativesData).not.toHaveBeenCalledWith({ channel: SMS, keepSlideBoxOpen: true });
62
+ expect(wrapper.state('isCreateContinuedAsEdit')).toBe(false);
63
+ });
64
+ });
65
+
66
+ describe('CreativesContainer: full-mode email create continues in place', () => {
67
+ const getCreativesData = jest.fn();
68
+ const render = (props = {}) => shallowWithIntl(
69
+ <Creatives
70
+ isFullMode
71
+ creativesMode="create"
72
+ channel="EMAIL"
73
+ templateData={{ mode: 'create' }}
74
+ Templates={{}}
75
+ getCreativesData={getCreativesData}
76
+ handleCloseCreatives={jest.fn()}
77
+ switchToEditAfterCreate
78
+ {...props}
79
+ />,
80
+ );
81
+
82
+ beforeEach(() => jest.clearAllMocks());
83
+
84
+ it('stays open after a create save and only lets the host refresh its list', () => {
85
+ const instance = render().instance();
86
+ instance.setState({ isGetFormData: true });
87
+ instance.getFormData({ _id: 'email-1', validity: true, keepSlideBoxOpen: true });
88
+
89
+ expect(instance.state.slidBoxContent).toBe('createTemplate');
90
+ expect(instance.state.isGetFormData).toBe(false);
91
+ expect(getCreativesData).toHaveBeenCalledWith({ channel: 'EMAIL', keepSlideBoxOpen: true });
92
+ });
93
+
94
+ it('closes as before after a create save when the user cannot edit', () => {
95
+ const instance = render({ switchToEditAfterCreate: false }).instance();
96
+ instance.getFormData({ _id: 'email-1', validity: true, keepSlideBoxOpen: true });
97
+
98
+ expect(getCreativesData).not.toHaveBeenCalledWith({ channel: 'EMAIL', keepSlideBoxOpen: true });
99
+ });
100
+ });
101
+
102
+ describe('CreativesContainer: header after a create continued in place (web push)', () => {
103
+ it('shows the edit title in the header while the content stays mounted in create mode', () => {
104
+ const wrapper = shallowWithIntl(
105
+ <Creatives
106
+ isFullMode
107
+ creativesMode="create"
108
+ channel="WEBPUSH"
109
+ templateData={{ mode: 'create' }}
110
+ Templates={{}}
111
+ getCreativesData={jest.fn()}
112
+ handleCloseCreatives={jest.fn()}
113
+ switchToEditAfterCreate
114
+ />,
115
+ );
116
+ const headerContent = () => wrapper.find('CapSlideBox').prop('header').props.slidBoxContent;
117
+ expect(headerContent()).toBe('createTemplate');
118
+
119
+ wrapper.instance().handleCreateContinuedAsEdit();
120
+ wrapper.update();
121
+
122
+ expect(headerContent()).toBe('editTemplate');
123
+ expect(wrapper.state('slidBoxContent')).toBe('createTemplate');
124
+ expect(wrapper.find('CapSlideBox').prop('content').props.slidBoxContent).toBe('createTemplate');
125
+ });
126
+ });
127
+
128
+ describe('CreativesContainer: a stay-open create marked continuedAsEdit (Viber)', () => {
129
+ it('stays open, refreshes the host list and switches the header to the edit title', () => {
130
+ const getCreativesData = jest.fn();
131
+ const wrapper = shallowWithIntl(
132
+ <Creatives
133
+ isFullMode
134
+ creativesMode="create"
135
+ channel="VIBER"
136
+ templateData={{ mode: 'create' }}
137
+ Templates={{}}
138
+ getCreativesData={getCreativesData}
139
+ handleCloseCreatives={jest.fn()}
140
+ switchToEditAfterCreate
141
+ />,
142
+ );
143
+
144
+ wrapper.instance().getFormData({ _id: 'vb-1', validity: true, keepSlideBoxOpen: true, continuedAsEdit: true });
145
+ wrapper.update();
146
+
147
+ expect(getCreativesData).toHaveBeenCalledWith({ channel: 'VIBER', keepSlideBoxOpen: true });
148
+ expect(wrapper.state('isCreateContinuedAsEdit')).toBe(true);
149
+ expect(wrapper.find('CapSlideBox').prop('header').props.slidBoxContent).toBe('editTemplate');
150
+ expect(wrapper.state('slidBoxContent')).toBe('createTemplate');
151
+ });
152
+ });