@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.
- package/package.json +1 -1
- package/v2Components/FormBuilder/Classic.js +3 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +39 -30
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +6 -2
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/index.js +26 -1
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +40 -12
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +10 -0
- package/v2Containers/CreativesContainer/tests/switchToEditAfterCreate.test.js +152 -0
- package/v2Containers/Email/index.js +41 -6
- package/v2Containers/Email/tests/index.test.js +123 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +32 -12
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +34 -0
- package/v2Containers/InApp/index.js +19 -23
- package/v2Containers/InApp/tests/index.test.js +52 -9
- package/v2Containers/InappAdvance/index.js +19 -24
- package/v2Containers/InappAdvance/tests/index.test.js +39 -15
- package/v2Containers/Line/Container/index.js +18 -8
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +129 -108
- package/v2Containers/Line/Container/tests/index.test.js +68 -0
- package/v2Containers/MobilePush/Create/index.js +24 -5
- package/v2Containers/MobilePush/Create/test/stayOpenOnSave.test.js +80 -0
- package/v2Containers/MobilePush/Edit/index.js +15 -9
- package/v2Containers/MobilePush/Edit/test/stayOpenOnSave.test.js +60 -0
- package/v2Containers/MobilePushNew/index.js +41 -7
- package/v2Containers/MobilePushNew/tests/index.test.js +61 -0
- package/v2Containers/Sms/Create/index.js +32 -14
- package/v2Containers/Sms/Create/test/stayOpenOnSave.test.js +92 -0
- package/v2Containers/Sms/Edit/index.js +22 -14
- package/v2Containers/Sms/Edit/tests/index.test.js +66 -0
- package/v2Containers/Templates/index.js +17 -4
- package/v2Containers/Viber/index.js +15 -6
- package/v2Containers/Viber/tests/index.test.js +97 -28
- package/v2Containers/WebPush/Create/components/FormActions.js +1 -1
- package/v2Containers/WebPush/Create/components/FormActions.test.js +3 -3
- package/v2Containers/WebPush/Create/index.js +32 -6
- package/v2Containers/WebPush/Create/messages.js +0 -4
- package/v2Containers/WebPush/Create/tests/stayOpenOnSave.test.js +268 -0
|
@@ -6,6 +6,7 @@ import { createStructuredSelector } from 'reselect';
|
|
|
6
6
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
7
7
|
import isEmpty from 'lodash/isEmpty';
|
|
8
8
|
import get from 'lodash/get';
|
|
9
|
+
import isPlainObject from 'lodash/isPlainObject';
|
|
9
10
|
import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
|
|
10
11
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
11
12
|
import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
|
|
@@ -133,7 +134,6 @@ export const Viber = (props) => {
|
|
|
133
134
|
metaEntities,
|
|
134
135
|
globalActions: globalActionsProps,
|
|
135
136
|
handleClose,
|
|
136
|
-
onCreateComplete,
|
|
137
137
|
params,
|
|
138
138
|
templateData = EMPTY_TEMPLATE_DATA,
|
|
139
139
|
actions,
|
|
@@ -158,6 +158,8 @@ export const Viber = (props) => {
|
|
|
158
158
|
const [errorMessageTextarea, updateErrorMessageTextArea] = useState(false);
|
|
159
159
|
const [isEditLoading, updateEditLoading] = useState(false);
|
|
160
160
|
const [isEditFlow, checkEditFlow] = useState(false);
|
|
161
|
+
// Full mode: id of the template created in this session — the form stays as is and later saves update it
|
|
162
|
+
const [savedTemplateId, setSavedTemplateId] = useState('');
|
|
161
163
|
const [messageTitle, updateTextMessageTitle] = useState("");
|
|
162
164
|
const [errorMessageTitle, updateErrorMessageTitle] = useState(false);
|
|
163
165
|
const [buttonURLErrorMessage, updateButtonURLErrorMessage] = useState(false);
|
|
@@ -1432,13 +1434,19 @@ export const Viber = (props) => {
|
|
|
1432
1434
|
}
|
|
1433
1435
|
};
|
|
1434
1436
|
|
|
1437
|
+
// Full mode stays open; a create continues in place as an edit.
|
|
1435
1438
|
const onCreateViber = () => {
|
|
1436
1439
|
actions.createTemplate(
|
|
1437
1440
|
formatSubmitPayload(),
|
|
1438
1441
|
(resp, errorMessage) => {
|
|
1439
1442
|
createCallback({resp, errorMessage});
|
|
1440
1443
|
if (!errorMessage) {
|
|
1441
|
-
|
|
1444
|
+
const savedResponse = resp?.templateId;
|
|
1445
|
+
const newTemplateId = (isPlainObject(savedResponse) ? savedResponse._id : savedResponse) || '';
|
|
1446
|
+
setSavedTemplateId(newTemplateId);
|
|
1447
|
+
getFormSubscriptionData({
|
|
1448
|
+
_id: newTemplateId, validity: true, keepSlideBoxOpen: true, continuedAsEdit: true,
|
|
1449
|
+
});
|
|
1442
1450
|
}
|
|
1443
1451
|
}
|
|
1444
1452
|
);
|
|
@@ -1448,12 +1456,12 @@ export const Viber = (props) => {
|
|
|
1448
1456
|
actions.editTemplate(
|
|
1449
1457
|
{
|
|
1450
1458
|
...formatSubmitPayload(),
|
|
1451
|
-
_id: params
|
|
1459
|
+
_id: params?.id || savedTemplateId,
|
|
1452
1460
|
},
|
|
1453
1461
|
(resp, errorMessage) => {
|
|
1454
1462
|
createCallback({resp, errorMessage}, true);
|
|
1455
1463
|
if (!errorMessage) {
|
|
1456
|
-
|
|
1464
|
+
getFormSubscriptionData({ validity: true, keepSlideBoxOpen: true });
|
|
1457
1465
|
}
|
|
1458
1466
|
}
|
|
1459
1467
|
);
|
|
@@ -1461,7 +1469,7 @@ export const Viber = (props) => {
|
|
|
1461
1469
|
|
|
1462
1470
|
const onDoneCallback = () => {
|
|
1463
1471
|
if (isFullMode) {
|
|
1464
|
-
if (isEditFlow) {
|
|
1472
|
+
if (isEditFlow || savedTemplateId) {
|
|
1465
1473
|
return onEditViber;
|
|
1466
1474
|
}
|
|
1467
1475
|
return onCreateViber;
|
|
@@ -1574,7 +1582,8 @@ export const Viber = (props) => {
|
|
|
1574
1582
|
disabled={isDisableDone()}
|
|
1575
1583
|
className="create-msg viber-create-msg"
|
|
1576
1584
|
>
|
|
1577
|
-
|
|
1585
|
+
{/* Full mode saves without closing, so the button reads "Save" for create and edit */}
|
|
1586
|
+
<FormattedMessage {...(isFullMode ? messages.save : messages.doneButtonLabel)} />
|
|
1578
1587
|
</CapButton>
|
|
1579
1588
|
<CapButton
|
|
1580
1589
|
onClick={handleTestAndPreview}
|
|
@@ -44,6 +44,21 @@ const renderComponent = (props) =>
|
|
|
44
44
|
</Provider>,
|
|
45
45
|
);
|
|
46
46
|
|
|
47
|
+
// Full mode labels the main Viber button "Save" (same text as the CTA / carousel-button "Save"),
|
|
48
|
+
// so tell them apart by the main button's class.
|
|
49
|
+
const MAIN_BUTTON_CLASS = 'viber-create-msg';
|
|
50
|
+
const isMainButton = (btn) => btn.classList.contains(MAIN_BUTTON_CLASS);
|
|
51
|
+
const getMainButton = () => screen.getAllByRole('button', { name: /^(save|done)$/i }).find(isMainButton);
|
|
52
|
+
const findMainButton = async () => {
|
|
53
|
+
await screen.findAllByRole('button', { name: /^(save|done)$/i });
|
|
54
|
+
return getMainButton();
|
|
55
|
+
};
|
|
56
|
+
const getOtherSaveButton = () => screen.getAllByRole('button', { name: /^save$/i }).find((btn) => !isMainButton(btn));
|
|
57
|
+
const findOtherSaveButton = async () => {
|
|
58
|
+
await waitFor(() => expect(getOtherSaveButton()).toBeTruthy());
|
|
59
|
+
return getOtherSaveButton();
|
|
60
|
+
};
|
|
61
|
+
|
|
47
62
|
describe('Test Viber container', () => {
|
|
48
63
|
it('test case for Viber template creation flow', async () => {
|
|
49
64
|
renderComponent({
|
|
@@ -110,18 +125,14 @@ describe('Test Viber container', () => {
|
|
|
110
125
|
fireEvent.change(ctaBtnUrl2, { target: { value: 'not url' } });
|
|
111
126
|
ctaBtnUrl2 = screen.getByPlaceholderText('Enter button url');
|
|
112
127
|
fireEvent.change(ctaBtnUrl2, { target: { value: 'https://www.test.com' } });
|
|
113
|
-
const saveBtn = await
|
|
114
|
-
name: /save/i,
|
|
115
|
-
});
|
|
128
|
+
const saveBtn = await findOtherSaveButton();
|
|
116
129
|
await waitFor(() => expect(saveBtn).toBeEnabled());
|
|
117
130
|
fireEvent.click(saveBtn);
|
|
118
131
|
const editCta = await screen.findByLabelText(/edit-cta-icon/i);
|
|
119
132
|
fireEvent.click(editCta);
|
|
120
133
|
const cancelBtn = screen.getAllByRole('button', {name: /cancel/i});
|
|
121
134
|
fireEvent.click(cancelBtn[0]);
|
|
122
|
-
const doneBtn = await
|
|
123
|
-
name: /done/i,
|
|
124
|
-
});
|
|
135
|
+
const doneBtn = await findMainButton();
|
|
125
136
|
await waitFor(() => expect(doneBtn).toBeEnabled());
|
|
126
137
|
fireEvent.click(doneBtn);
|
|
127
138
|
expect(mockActions.createTemplate).toHaveBeenCalled();
|
|
@@ -148,9 +159,7 @@ describe('Test Viber container', () => {
|
|
|
148
159
|
params: { id: 'test'},
|
|
149
160
|
handleClose: jest.fn(),
|
|
150
161
|
});
|
|
151
|
-
const doneBtn =
|
|
152
|
-
name: /done/i,
|
|
153
|
-
});
|
|
162
|
+
const doneBtn = getMainButton();
|
|
154
163
|
expect(doneBtn).toBeEnabled();
|
|
155
164
|
fireEvent.click(doneBtn);
|
|
156
165
|
expect(mockActions.editTemplate).toHaveBeenCalled();
|
|
@@ -181,9 +190,7 @@ describe('Test Viber container', () => {
|
|
|
181
190
|
name: /reupload/i,
|
|
182
191
|
});
|
|
183
192
|
fireEvent.click(reupload);
|
|
184
|
-
const doneBtn =
|
|
185
|
-
name: /done/i,
|
|
186
|
-
});
|
|
193
|
+
const doneBtn = getMainButton();
|
|
187
194
|
expect(doneBtn).toBeDisabled();
|
|
188
195
|
});
|
|
189
196
|
it('test case for Viber template creation flow for video media type', async () => {
|
|
@@ -211,9 +218,7 @@ describe('Test Viber container', () => {
|
|
|
211
218
|
getDefaultTags,
|
|
212
219
|
injectedTags,
|
|
213
220
|
});
|
|
214
|
-
const doneBtn =
|
|
215
|
-
name: /done/i,
|
|
216
|
-
});
|
|
221
|
+
const doneBtn = getMainButton();
|
|
217
222
|
expect(doneBtn).toBeEnabled();
|
|
218
223
|
fireEvent.click(doneBtn);
|
|
219
224
|
expect(mockActions.editTemplate).toHaveBeenCalled();
|
|
@@ -243,9 +248,7 @@ describe('Test Viber container', () => {
|
|
|
243
248
|
getDefaultTags,
|
|
244
249
|
injectedTags,
|
|
245
250
|
});
|
|
246
|
-
const doneBtn =
|
|
247
|
-
name: /done/i,
|
|
248
|
-
});
|
|
251
|
+
const doneBtn = getMainButton();
|
|
249
252
|
expect(doneBtn).toBeEnabled();
|
|
250
253
|
fireEvent.click(doneBtn);
|
|
251
254
|
expect(mockActions.editTemplate).toHaveBeenCalled();
|
|
@@ -278,9 +281,7 @@ describe('Test Viber container', () => {
|
|
|
278
281
|
name: /re upload/i,
|
|
279
282
|
});
|
|
280
283
|
fireEvent.click(reupload);
|
|
281
|
-
const doneBtn =
|
|
282
|
-
name: /done/i,
|
|
283
|
-
});
|
|
284
|
+
const doneBtn = getMainButton();
|
|
284
285
|
expect(doneBtn).toBeDisabled();
|
|
285
286
|
});
|
|
286
287
|
it('test case for Viber template for error cases', async () => {
|
|
@@ -304,9 +305,7 @@ describe('Test Viber container', () => {
|
|
|
304
305
|
params: { id: 'test'},
|
|
305
306
|
handleClose: jest.fn(),
|
|
306
307
|
});
|
|
307
|
-
const doneBtn =
|
|
308
|
-
name: /done/i,
|
|
309
|
-
});
|
|
308
|
+
const doneBtn = getMainButton();
|
|
310
309
|
expect(doneBtn).toBeDisabled();
|
|
311
310
|
});
|
|
312
311
|
|
|
@@ -334,7 +333,7 @@ describe('Test Viber container', () => {
|
|
|
334
333
|
getDefaultTags,
|
|
335
334
|
injectedTags,
|
|
336
335
|
});
|
|
337
|
-
const doneBtn =
|
|
336
|
+
const doneBtn = getMainButton();
|
|
338
337
|
expect(doneBtn).toBeDisabled();
|
|
339
338
|
});
|
|
340
339
|
|
|
@@ -358,7 +357,7 @@ describe('Test Viber container', () => {
|
|
|
358
357
|
params: { id: 'test' },
|
|
359
358
|
handleClose: jest.fn(),
|
|
360
359
|
});
|
|
361
|
-
const doneBtn =
|
|
360
|
+
const doneBtn = getMainButton();
|
|
362
361
|
expect(doneBtn).toBeDisabled();
|
|
363
362
|
});
|
|
364
363
|
|
|
@@ -386,7 +385,7 @@ describe('Test Viber container', () => {
|
|
|
386
385
|
getDefaultTags,
|
|
387
386
|
injectedTags,
|
|
388
387
|
});
|
|
389
|
-
const doneBtn =
|
|
388
|
+
const doneBtn = getMainButton();
|
|
390
389
|
expect(doneBtn).toBeEnabled();
|
|
391
390
|
});
|
|
392
391
|
|
|
@@ -465,7 +464,7 @@ describe('Test Viber container', () => {
|
|
|
465
464
|
|
|
466
465
|
fireEvent.click(screen.getByRole('radio', { name: /carousel/i }));
|
|
467
466
|
await screen.findByPlaceholderText('https://example.com/action');
|
|
468
|
-
fireEvent.click(
|
|
467
|
+
fireEvent.click(getOtherSaveButton());
|
|
469
468
|
|
|
470
469
|
expect(await screen.findByText("URL can't be empty")).toBeInTheDocument();
|
|
471
470
|
});
|
|
@@ -573,3 +572,73 @@ describe('Test Viber container', () => {
|
|
|
573
572
|
});
|
|
574
573
|
});
|
|
575
574
|
});
|
|
575
|
+
|
|
576
|
+
describe('Viber — full mode keeps the slidebox open after saving', () => {
|
|
577
|
+
const buildProps = (overrides = {}) => ({
|
|
578
|
+
actions: {
|
|
579
|
+
...mockActions,
|
|
580
|
+
createTemplate: jest.fn(),
|
|
581
|
+
editTemplate: jest.fn(),
|
|
582
|
+
clearCreateResponse: jest.fn(),
|
|
583
|
+
clearEditResponse: jest.fn(),
|
|
584
|
+
},
|
|
585
|
+
globalActions: mockGlobalActions,
|
|
586
|
+
templateData: { mode: 'create' },
|
|
587
|
+
viber: { uploadedAssetData: {}, createTemplateInProgress: false },
|
|
588
|
+
location: { pathname: '/viber/create', query: { type: false, module: 'default' }, search: '' },
|
|
589
|
+
isFullMode: true,
|
|
590
|
+
handleClose: jest.fn(),
|
|
591
|
+
onCreateComplete: jest.fn(),
|
|
592
|
+
getFormSubscriptionData: jest.fn(),
|
|
593
|
+
metaEntities,
|
|
594
|
+
getDefaultTags,
|
|
595
|
+
injectedTags,
|
|
596
|
+
...overrides,
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
it('labels the main button "Save" in full mode and "Done" in library mode', async () => {
|
|
600
|
+
const { unmount } = renderComponent(buildProps());
|
|
601
|
+
expect((await findMainButton()).textContent).toMatch(/^save$/i);
|
|
602
|
+
unmount();
|
|
603
|
+
renderComponent(buildProps({ isFullMode: false }));
|
|
604
|
+
expect((await findMainButton()).textContent).toMatch(/^done$/i);
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
it('create: stays open (header switches) and the next save updates the created template', async () => {
|
|
608
|
+
const props = buildProps();
|
|
609
|
+
renderComponent(props);
|
|
610
|
+
fireEvent.change((await screen.findAllByPlaceholderText('Enter template name'))[0], { target: { value: 'Promo' } });
|
|
611
|
+
fireEvent.change(screen.getAllByPlaceholderText(/Enter message/i)[0], { target: { value: 'Hello there' } });
|
|
612
|
+
|
|
613
|
+
fireEvent.click(getMainButton());
|
|
614
|
+
expect(props.actions.createTemplate).toHaveBeenCalledTimes(1);
|
|
615
|
+
props.actions.createTemplate.mock.calls[0][1]({ templateId: { _id: 'vb-1' } });
|
|
616
|
+
|
|
617
|
+
expect(props.getFormSubscriptionData).toHaveBeenCalledWith({
|
|
618
|
+
_id: 'vb-1', validity: true, keepSlideBoxOpen: true, continuedAsEdit: true,
|
|
619
|
+
});
|
|
620
|
+
expect(props.onCreateComplete).not.toHaveBeenCalled();
|
|
621
|
+
expect(props.handleClose).not.toHaveBeenCalled();
|
|
622
|
+
|
|
623
|
+
await waitFor(() => expect(getMainButton()).toBeEnabled());
|
|
624
|
+
fireEvent.click(getMainButton());
|
|
625
|
+
expect(props.actions.createTemplate).toHaveBeenCalledTimes(1);
|
|
626
|
+
expect(props.actions.editTemplate).toHaveBeenCalledTimes(1);
|
|
627
|
+
expect(props.actions.editTemplate.mock.calls[0][0]._id).toBe('vb-1');
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
it('edit: stays open after a successful update', async () => {
|
|
631
|
+
const props = buildProps({
|
|
632
|
+
params: { id: 'vb-9' },
|
|
633
|
+
viber: { uploadedAssetData: {}, createTemplateInProgress: false, templateDetails: templateDetailsText },
|
|
634
|
+
});
|
|
635
|
+
renderComponent(props);
|
|
636
|
+
|
|
637
|
+
fireEvent.click(await findMainButton());
|
|
638
|
+
expect(props.actions.editTemplate.mock.calls[0][0]._id).toBe('vb-9');
|
|
639
|
+
props.actions.editTemplate.mock.calls[0][1]({ templateId: { _id: 'vb-9' } });
|
|
640
|
+
|
|
641
|
+
expect(props.getFormSubscriptionData).toHaveBeenCalledWith({ validity: true, keepSlideBoxOpen: true });
|
|
642
|
+
expect(props.onCreateComplete).not.toHaveBeenCalled();
|
|
643
|
+
});
|
|
644
|
+
});
|
|
@@ -18,7 +18,7 @@ export const FormActions = ({
|
|
|
18
18
|
<>
|
|
19
19
|
<CapRow useLegacy className="creatives-webpush-actions">
|
|
20
20
|
<CapButton type="primary" onClick={onSave} disabled={isSaveDisabled}>
|
|
21
|
-
{formatMessage(messages.
|
|
21
|
+
{formatMessage(messages.saveButton)}
|
|
22
22
|
</CapButton>
|
|
23
23
|
</CapRow>
|
|
24
24
|
{errorText && (
|
|
@@ -10,8 +10,8 @@ describe('FormActions', () => {
|
|
|
10
10
|
const mockOnSave = jest.fn();
|
|
11
11
|
|
|
12
12
|
const mockMessages = {
|
|
13
|
-
|
|
14
|
-
defaultMessage: 'Save
|
|
13
|
+
saveButton: {
|
|
14
|
+
defaultMessage: 'Save',
|
|
15
15
|
},
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -46,7 +46,7 @@ describe('FormActions', () => {
|
|
|
46
46
|
const wrapper = mountWithIntl(<FormActions {...defaultProps} />);
|
|
47
47
|
const saveButton = wrapper.find(CapButton);
|
|
48
48
|
expect(saveButton.exists()).toBe(true);
|
|
49
|
-
expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.
|
|
49
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.saveButton);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
it('should disable save button when isSaveDisabled is true', () => {
|
|
@@ -32,6 +32,7 @@ import { useImageUpload } from './hooks/useImageUpload';
|
|
|
32
32
|
import { useTagManagement } from './hooks/useTagManagement';
|
|
33
33
|
import isEmpty from 'lodash/isEmpty';
|
|
34
34
|
import get from 'lodash/get';
|
|
35
|
+
import isPlainObject from 'lodash/isPlainObject';
|
|
35
36
|
import * as templateActions from '../../Templates/actions';
|
|
36
37
|
import { makeSelectTemplates } from '../../Templates/selectors';
|
|
37
38
|
|
|
@@ -165,8 +166,13 @@ const WebPushCreate = ({
|
|
|
165
166
|
Templates,
|
|
166
167
|
restrictPersonalization = false,
|
|
167
168
|
onContentValidityChange,
|
|
169
|
+
canStayOpenAfterCreate = false,
|
|
170
|
+
onCreateContinuedAsEdit,
|
|
168
171
|
}) => {
|
|
169
172
|
const { formatMessage } = intl;
|
|
173
|
+
// Full mode stays open after saving; creates only with edit permission.
|
|
174
|
+
const stayOpenAfterSave = !!isFullMode;
|
|
175
|
+
const stayOpenAfterCreate = !!isFullMode && !!canStayOpenAfterCreate;
|
|
170
176
|
const aiContentBotDisabled = isAiContentBotDisabled();
|
|
171
177
|
|
|
172
178
|
// Form state - kept in main component for now
|
|
@@ -189,6 +195,8 @@ const WebPushCreate = ({
|
|
|
189
195
|
const [activeUploadField, setActiveUploadField] = useState(null);
|
|
190
196
|
const [templateIdError, setTemplateIdError] = useState('');
|
|
191
197
|
const [showTestAndPreviewSlidebox, setShowTestAndPreviewSlidebox] = useState(false);
|
|
198
|
+
// Full mode: id of the template created in this session — the form stays as is and later saves update it
|
|
199
|
+
const [savedTemplateId, setSavedTemplateId] = useState('');
|
|
192
200
|
|
|
193
201
|
// Refs
|
|
194
202
|
const titleCountRef = useRef(null);
|
|
@@ -708,10 +716,10 @@ const WebPushCreate = ({
|
|
|
708
716
|
return;
|
|
709
717
|
}
|
|
710
718
|
|
|
711
|
-
// Full mode: proceed with API calls
|
|
712
|
-
if (isEditMode) {
|
|
713
|
-
// Get template ID from params or templateData
|
|
714
|
-
const templateId = params?.id || templateData?._id;
|
|
719
|
+
// Full mode: proceed with API calls. A template created earlier in this session is updated too.
|
|
720
|
+
if (isEditMode || savedTemplateId) {
|
|
721
|
+
// Get template ID from params or templateData (or the in-session created template)
|
|
722
|
+
const templateId = params?.id || templateData?._id || savedTemplateId;
|
|
715
723
|
if (templateId) {
|
|
716
724
|
// Clear any previous template ID error
|
|
717
725
|
setTemplateIdError('');
|
|
@@ -725,6 +733,10 @@ const WebPushCreate = ({
|
|
|
725
733
|
// Clear flag before calling callbacks to prevent double-invocation
|
|
726
734
|
// from the editResponse useEffect
|
|
727
735
|
saveInitiatedRef.current = false;
|
|
736
|
+
// Stays open (host shows the toast and refreshes its list from the edit response)
|
|
737
|
+
if (stayOpenAfterSave) {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
728
740
|
if (onCreateComplete) {
|
|
729
741
|
onCreateComplete(true);
|
|
730
742
|
}
|
|
@@ -769,6 +781,15 @@ const WebPushCreate = ({
|
|
|
769
781
|
) {
|
|
770
782
|
// Reset flag after handling response
|
|
771
783
|
saveInitiatedRef.current = false;
|
|
784
|
+
if (stayOpenAfterCreate) {
|
|
785
|
+
// Stay open: next save updates this template.
|
|
786
|
+
const savedResponse = response.templateId || response._id;
|
|
787
|
+
setSavedTemplateId((isPlainObject(savedResponse) ? savedResponse._id : savedResponse) || '');
|
|
788
|
+
if (onCreateContinuedAsEdit) {
|
|
789
|
+
onCreateContinuedAsEdit(); // host switches the header to the edit title
|
|
790
|
+
}
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
772
793
|
if (onCreateComplete) {
|
|
773
794
|
onCreateComplete(true);
|
|
774
795
|
}
|
|
@@ -776,7 +797,7 @@ const WebPushCreate = ({
|
|
|
776
797
|
handleClose();
|
|
777
798
|
}
|
|
778
799
|
}
|
|
779
|
-
}, [webPush?.response, onCreateComplete, handleClose, isEditMode]);
|
|
800
|
+
}, [webPush?.response, onCreateComplete, handleClose, isEditMode, stayOpenAfterCreate, onCreateContinuedAsEdit]);
|
|
780
801
|
|
|
781
802
|
// Handle edit response
|
|
782
803
|
useEffect(() => {
|
|
@@ -789,6 +810,9 @@ const WebPushCreate = ({
|
|
|
789
810
|
) {
|
|
790
811
|
// Reset flag after handling response
|
|
791
812
|
saveInitiatedRef.current = false;
|
|
813
|
+
if (stayOpenAfterSave) {
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
792
816
|
if (onCreateComplete) {
|
|
793
817
|
onCreateComplete(true);
|
|
794
818
|
}
|
|
@@ -796,7 +820,7 @@ const WebPushCreate = ({
|
|
|
796
820
|
handleClose();
|
|
797
821
|
}
|
|
798
822
|
}
|
|
799
|
-
}, [webPush?.editResponse, onCreateComplete, handleClose, isEditMode]);
|
|
823
|
+
}, [webPush?.editResponse, onCreateComplete, handleClose, isEditMode, stayOpenAfterSave]);
|
|
800
824
|
|
|
801
825
|
// Handle getFormData request from parent (library mode)
|
|
802
826
|
useEffect(() => {
|
|
@@ -1194,6 +1218,8 @@ WebPushCreate.propTypes = {
|
|
|
1194
1218
|
templateActions: PropTypes.object,
|
|
1195
1219
|
restrictPersonalization: PropTypes.bool,
|
|
1196
1220
|
onContentValidityChange: PropTypes.func,
|
|
1221
|
+
canStayOpenAfterCreate: PropTypes.bool,
|
|
1222
|
+
onCreateContinuedAsEdit: PropTypes.func,
|
|
1197
1223
|
};
|
|
1198
1224
|
|
|
1199
1225
|
WebPushCreate.defaultProps = {
|
|
@@ -43,10 +43,6 @@ export default defineMessages({
|
|
|
43
43
|
id: `${scope}.messageRequired`,
|
|
44
44
|
defaultMessage: 'Message is required',
|
|
45
45
|
},
|
|
46
|
-
saveTemplate: {
|
|
47
|
-
id: `${scope}.saveTemplate`,
|
|
48
|
-
defaultMessage: 'Save Template',
|
|
49
|
-
},
|
|
50
46
|
accountRequired: {
|
|
51
47
|
id: `${scope}.accountRequired`,
|
|
52
48
|
defaultMessage: 'Select an account to create a template',
|