@capillarytech/creatives-library 8.0.316-alpha.4 → 8.0.317-alpha.0
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/constants/unified.js +1 -0
- package/package.json +1 -1
- package/services/api.js +6 -0
- package/services/tests/api.test.js +7 -0
- package/utils/common.js +6 -1
- package/utils/tests/tagValidations.test.js +34 -0
- package/v2Components/CapTagList/index.js +15 -22
- package/v2Components/CapTagList/style.scss +48 -0
- package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
- package/v2Components/CapTagListWithInput/index.js +4 -0
- package/v2Components/CapWhatsappCTA/index.js +2 -0
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +180 -0
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +96 -0
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +99 -0
- package/v2Components/CommonTestAndPreview/tests/index.test.js +113 -3
- package/v2Components/FormBuilder/index.js +7 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +95 -0
- package/v2Containers/BeeEditor/index.js +3 -0
- package/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
- package/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
- package/v2Containers/CommunicationFlow/constants.js +200 -0
- package/v2Containers/CommunicationFlow/index.js +102 -0
- package/v2Containers/CommunicationFlow/messages.js +346 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +28 -1
- package/v2Containers/CreativesContainer/constants.js +3 -0
- package/v2Containers/CreativesContainer/index.js +3 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +104 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/Email/index.js +1 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +7 -1
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -0
- package/v2Containers/EmailWrapper/index.js +4 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
- package/v2Containers/InAppWrapper/index.js +3 -0
- package/v2Containers/MobilePush/Create/index.js +2 -0
- package/v2Containers/MobilePush/Edit/index.js +2 -0
- package/v2Containers/MobilepushWrapper/index.js +3 -1
- package/v2Containers/Rcs/index.js +1 -0
- package/v2Containers/Sms/Create/index.js +2 -0
- package/v2Containers/Sms/Edit/index.js +2 -0
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/v2Containers/SmsTrai/Edit/index.js +2 -0
- package/v2Containers/SmsWrapper/index.js +2 -0
- package/v2Containers/TagList/index.js +41 -2
- package/v2Containers/TagList/messages.js +4 -0
- package/v2Containers/TagList/tests/TagList.test.js +122 -20
- package/v2Containers/TagList/tests/mockdata.js +17 -0
- package/v2Containers/Templates/tests/sagas.test.js +83 -0
- package/v2Containers/Viber/index.js +5 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
- package/v2Containers/WebPush/Create/index.js +9 -1
- package/v2Containers/Whatsapp/index.js +5 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +20 -0
- package/v2Containers/Zalo/index.js +2 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeliverySettingsStep - Entry point
|
|
3
|
+
* Exports: DeliverySettingsSection (integrated in ChannelSelectionStep), SenderDetails
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { default as SenderDetails, parseSenderDetailsFromEntity } from './SenderDetails';
|
|
7
|
+
export { default as DeliverySettingsSection } from './DeliverySettingsSection';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DynamicControlsStep Component
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import PropTypes from 'prop-types';
|
|
7
|
+
import { injectIntl } from 'react-intl';
|
|
8
|
+
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
9
|
+
import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
|
|
10
|
+
import CapSwitch from '@capillarytech/cap-ui-library/CapSwitch';
|
|
11
|
+
import messages from '../../messages';
|
|
12
|
+
import './DynamicControlsStep.scss';
|
|
13
|
+
|
|
14
|
+
const DynamicControlsStep = ({
|
|
15
|
+
value,
|
|
16
|
+
onChange,
|
|
17
|
+
controls,
|
|
18
|
+
error,
|
|
19
|
+
intl,
|
|
20
|
+
}) => {
|
|
21
|
+
const { formatMessage } = intl || {};
|
|
22
|
+
// formatMessage used for section title only
|
|
23
|
+
const dynamicControls = value?.dynamicControls || {};
|
|
24
|
+
|
|
25
|
+
const handleToggle = (key, checked) => {
|
|
26
|
+
onChange({
|
|
27
|
+
...value,
|
|
28
|
+
dynamicControls: { ...dynamicControls, [key]: checked },
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
if (!controls?.length) return null;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<CapRow className="dynamic-controls-step">
|
|
36
|
+
<CapHeading type="h3" className="heading-style">
|
|
37
|
+
{formatMessage(messages.dynamicControlsTitle)}
|
|
38
|
+
</CapHeading>
|
|
39
|
+
|
|
40
|
+
{controls.map(({ key, label, description }) => {
|
|
41
|
+
const checked = !!dynamicControls[key];
|
|
42
|
+
const displayLabel = label || key;
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<CapRow
|
|
46
|
+
key={key}
|
|
47
|
+
type="flex"
|
|
48
|
+
align="top"
|
|
49
|
+
justify="space-between"
|
|
50
|
+
className="dynamic-controls-step__row"
|
|
51
|
+
>
|
|
52
|
+
<CapRow className="dynamic-controls-step__label-wrap">
|
|
53
|
+
<CapHeading type="h4" className="dynamic-controls-step__label">
|
|
54
|
+
{displayLabel}
|
|
55
|
+
</CapHeading>
|
|
56
|
+
{description && (
|
|
57
|
+
<CapHeading type="label4" className="dynamic-controls-step__desc">
|
|
58
|
+
{description}
|
|
59
|
+
</CapHeading>
|
|
60
|
+
)}
|
|
61
|
+
</CapRow>
|
|
62
|
+
<CapSwitch
|
|
63
|
+
checked={checked}
|
|
64
|
+
onChange={(val) => handleToggle(key, val)}
|
|
65
|
+
className="dynamic-controls-step__switch"
|
|
66
|
+
/>
|
|
67
|
+
</CapRow>
|
|
68
|
+
);
|
|
69
|
+
})}
|
|
70
|
+
|
|
71
|
+
{error && (
|
|
72
|
+
<CapRow className="validation-error dynamic-controls-step__error">
|
|
73
|
+
{error}
|
|
74
|
+
</CapRow>
|
|
75
|
+
)}
|
|
76
|
+
</CapRow>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
DynamicControlsStep.propTypes = {
|
|
81
|
+
value: PropTypes.shape({
|
|
82
|
+
dynamicControls: PropTypes.object,
|
|
83
|
+
}),
|
|
84
|
+
onChange: PropTypes.func.isRequired,
|
|
85
|
+
controls: PropTypes.arrayOf(
|
|
86
|
+
PropTypes.shape({
|
|
87
|
+
key: PropTypes.string.isRequired,
|
|
88
|
+
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
89
|
+
description: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
90
|
+
}),
|
|
91
|
+
),
|
|
92
|
+
error: PropTypes.string,
|
|
93
|
+
intl: PropTypes.object.isRequired,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
DynamicControlsStep.defaultProps = {
|
|
97
|
+
value: {},
|
|
98
|
+
controls: [],
|
|
99
|
+
error: null,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export default injectIntl(DynamicControlsStep);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@import '~@capillarytech/cap-ui-library/styles/_variables.scss';
|
|
2
|
+
|
|
3
|
+
.dynamic-controls-step {
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
|
|
6
|
+
&__row {
|
|
7
|
+
padding: $CAP_SPACE_16 0;
|
|
8
|
+
align-items: flex-start;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&__label-wrap {
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
align-items: flex-start;
|
|
14
|
+
flex: 1;
|
|
15
|
+
padding-right: $CAP_SPACE_24;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&__label {
|
|
19
|
+
line-height: $CAP_SPACE_20;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&__desc {
|
|
23
|
+
margin-top: $CAP_SPACE_04;
|
|
24
|
+
color: $FONT_COLOR_03;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&__switch {
|
|
28
|
+
flex-shrink: 0;
|
|
29
|
+
margin-top: 0.125rem;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&__error {
|
|
33
|
+
margin-top: $CAP_SPACE_08;
|
|
34
|
+
color: $CAP_RED;
|
|
35
|
+
}
|
|
36
|
+
}
|
package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
render, screen,
|
|
4
|
+
} from '@testing-library/react';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
7
|
+
import { IntlProvider } from 'react-intl';
|
|
8
|
+
import DynamicControlsStep from '../DynamicControlsStep';
|
|
9
|
+
|
|
10
|
+
const SAMPLE_CONTROLS = [
|
|
11
|
+
{ key: 'alpha', label: 'Alpha', description: 'Alpha help' },
|
|
12
|
+
{ key: 'beta', label: 'Beta', description: 'Beta help' },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
function renderWithIntl(ui) {
|
|
16
|
+
return render(
|
|
17
|
+
<IntlProvider locale="en" messages={{}} defaultLocale="en">
|
|
18
|
+
{ui}
|
|
19
|
+
</IntlProvider>,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function DynamicControlsHarness({ initialDynamicControls = {} }) {
|
|
24
|
+
const [value, setValue] = useState({ dynamicControls: initialDynamicControls });
|
|
25
|
+
return (
|
|
26
|
+
<DynamicControlsStep
|
|
27
|
+
value={value}
|
|
28
|
+
onChange={setValue}
|
|
29
|
+
controls={SAMPLE_CONTROLS}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('DynamicControlsStep', () => {
|
|
35
|
+
it('renders nothing when there are no controls', () => {
|
|
36
|
+
const { container } = renderWithIntl(
|
|
37
|
+
<DynamicControlsStep
|
|
38
|
+
value={{}}
|
|
39
|
+
onChange={jest.fn()}
|
|
40
|
+
controls={[]}
|
|
41
|
+
/>,
|
|
42
|
+
);
|
|
43
|
+
expect(container.firstChild).toBeNull();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('shows each switch on (true) or off (false) from dynamicControls for every field', () => {
|
|
47
|
+
renderWithIntl(
|
|
48
|
+
<DynamicControlsHarness initialDynamicControls={{ alpha: true, beta: false }} />,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(screen.getByText('Other controls')).toBeInTheDocument();
|
|
52
|
+
expect(screen.getByText('Alpha')).toBeInTheDocument();
|
|
53
|
+
expect(screen.getByText('Beta')).toBeInTheDocument();
|
|
54
|
+
|
|
55
|
+
const switches = screen.getAllByRole('switch');
|
|
56
|
+
expect(switches).toHaveLength(2);
|
|
57
|
+
expect(switches[0]).toBeChecked();
|
|
58
|
+
expect(switches[1]).not.toBeChecked();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('toggles every control through false and true via onChange', async () => {
|
|
62
|
+
renderWithIntl(
|
|
63
|
+
<DynamicControlsHarness initialDynamicControls={{ alpha: true, beta: false }} />,
|
|
64
|
+
);
|
|
65
|
+
const switches = screen.getAllByRole('switch');
|
|
66
|
+
|
|
67
|
+
await userEvent.click(switches[0]);
|
|
68
|
+
expect(switches[0]).not.toBeChecked();
|
|
69
|
+
|
|
70
|
+
await userEvent.click(switches[1]);
|
|
71
|
+
expect(switches[1]).toBeChecked();
|
|
72
|
+
|
|
73
|
+
await userEvent.click(switches[0]);
|
|
74
|
+
expect(switches[0]).toBeChecked();
|
|
75
|
+
|
|
76
|
+
await userEvent.click(switches[1]);
|
|
77
|
+
expect(switches[1]).not.toBeChecked();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('renders validation error when error is set', () => {
|
|
81
|
+
renderWithIntl(
|
|
82
|
+
<DynamicControlsStep
|
|
83
|
+
value={{ dynamicControls: { alpha: false } }}
|
|
84
|
+
onChange={jest.fn()}
|
|
85
|
+
controls={[SAMPLE_CONTROLS[0]]}
|
|
86
|
+
error="Dynamic controls validation failed"
|
|
87
|
+
/>,
|
|
88
|
+
);
|
|
89
|
+
expect(screen.getByText('Dynamic controls validation failed')).toBeInTheDocument();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MessageTypeStep Component
|
|
3
|
+
*
|
|
4
|
+
* Radio group for selecting Message Type: Promotional | Transactional
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { injectIntl } from 'react-intl';
|
|
10
|
+
import CapRadio from '@capillarytech/cap-ui-library/CapRadio';
|
|
11
|
+
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
12
|
+
import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
|
|
13
|
+
import { CAP_SPACE_24 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
14
|
+
import { MESSAGE_TYPES_OPTIONS } from '../../constants';
|
|
15
|
+
import messages from '../../messages';
|
|
16
|
+
import '../../CommunicationFlow.scss';
|
|
17
|
+
|
|
18
|
+
const MessageTypeStep = ({
|
|
19
|
+
value,
|
|
20
|
+
defaultOption,
|
|
21
|
+
options: optionsProp,
|
|
22
|
+
onChange,
|
|
23
|
+
error,
|
|
24
|
+
intl,
|
|
25
|
+
}) => {
|
|
26
|
+
const { formatMessage } = intl || {};
|
|
27
|
+
const options = optionsProp || MESSAGE_TYPES_OPTIONS;
|
|
28
|
+
|
|
29
|
+
// Use defaultOption value if value is null/undefined
|
|
30
|
+
const selectedValue = value || defaultOption?.value;
|
|
31
|
+
|
|
32
|
+
const handleChange = (messageType) => {
|
|
33
|
+
onChange(messageType);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<CapRow className="message-type-step">
|
|
38
|
+
<CapHeading type="h3" className="heading-style">
|
|
39
|
+
{formatMessage(messages.messageTypeHeading)}
|
|
40
|
+
</CapHeading>
|
|
41
|
+
|
|
42
|
+
<CapRow align="middle" type="flex" gap={CAP_SPACE_24}>
|
|
43
|
+
{options?.map((option) => (
|
|
44
|
+
<CapRadio
|
|
45
|
+
key={option?.value}
|
|
46
|
+
checked={selectedValue === option?.value}
|
|
47
|
+
onChange={() => handleChange(option?.value)}
|
|
48
|
+
disabled={option?.disabled}
|
|
49
|
+
>
|
|
50
|
+
{option?.label}
|
|
51
|
+
</CapRadio>
|
|
52
|
+
))}
|
|
53
|
+
</CapRow>
|
|
54
|
+
|
|
55
|
+
{error && (
|
|
56
|
+
<CapRow className="validation-error">
|
|
57
|
+
{error}
|
|
58
|
+
</CapRow>
|
|
59
|
+
)}
|
|
60
|
+
</CapRow>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
MessageTypeStep.propTypes = {
|
|
65
|
+
value: PropTypes.oneOf(['promotional', 'transactional']),
|
|
66
|
+
defaultOption: PropTypes.shape({
|
|
67
|
+
value: PropTypes.string.isRequired,
|
|
68
|
+
label: PropTypes.node.isRequired,
|
|
69
|
+
}),
|
|
70
|
+
options: PropTypes.arrayOf(PropTypes.shape({
|
|
71
|
+
value: PropTypes.string.isRequired,
|
|
72
|
+
label: PropTypes.node.isRequired,
|
|
73
|
+
})),
|
|
74
|
+
onChange: PropTypes.func.isRequired,
|
|
75
|
+
error: PropTypes.string,
|
|
76
|
+
intl: PropTypes.object.isRequired,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
MessageTypeStep.defaultProps = {
|
|
80
|
+
value: null,
|
|
81
|
+
defaultOption: null,
|
|
82
|
+
options: null,
|
|
83
|
+
error: null,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export default injectIntl(MessageTypeStep);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
5
|
+
import { IntlProvider } from 'react-intl';
|
|
6
|
+
import MessageTypeStep from '../MessageTypeStep';
|
|
7
|
+
|
|
8
|
+
const OPTIONS = [
|
|
9
|
+
{ value: 'promotional', label: 'Promotional', disabled: false },
|
|
10
|
+
{ value: 'transactional', label: 'Transactional', disabled: false },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
function renderWithIntl(ui) {
|
|
14
|
+
return render(
|
|
15
|
+
<IntlProvider locale="en" messages={{}} defaultLocale="en">
|
|
16
|
+
{ui}
|
|
17
|
+
</IntlProvider>,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('MessageTypeStep', () => {
|
|
22
|
+
it('shows the step heading and one radio per option', () => {
|
|
23
|
+
const onChange = jest.fn();
|
|
24
|
+
renderWithIntl(
|
|
25
|
+
<MessageTypeStep
|
|
26
|
+
value="promotional"
|
|
27
|
+
options={OPTIONS}
|
|
28
|
+
defaultOption={{ value: 'promotional', label: 'Promotional' }}
|
|
29
|
+
onChange={onChange}
|
|
30
|
+
/>,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(screen.getByText(/message type/i)).toBeInTheDocument();
|
|
34
|
+
expect(screen.getByRole('radio', { name: /promotional/i })).toBeInTheDocument();
|
|
35
|
+
expect(screen.getByRole('radio', { name: /transactional/i })).toBeInTheDocument();
|
|
36
|
+
expect(screen.getByRole('radio', { name: /promotional/i })).toBeChecked();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('uses defaultOption when value is null so the default appears selected', () => {
|
|
40
|
+
const onChange = jest.fn();
|
|
41
|
+
renderWithIntl(
|
|
42
|
+
<MessageTypeStep
|
|
43
|
+
value={null}
|
|
44
|
+
options={OPTIONS}
|
|
45
|
+
defaultOption={{ value: 'transactional', label: 'Transactional' }}
|
|
46
|
+
onChange={onChange}
|
|
47
|
+
/>,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(screen.getByRole('radio', { name: /transactional/i })).toBeChecked();
|
|
51
|
+
expect(screen.getByRole('radio', { name: /promotional/i })).not.toBeChecked();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('calls onChange with the chosen message type when the user switches radios', async () => {
|
|
55
|
+
const onChange = jest.fn();
|
|
56
|
+
renderWithIntl(
|
|
57
|
+
<MessageTypeStep
|
|
58
|
+
value="promotional"
|
|
59
|
+
options={OPTIONS}
|
|
60
|
+
defaultOption={{ value: 'promotional', label: 'Promotional' }}
|
|
61
|
+
onChange={onChange}
|
|
62
|
+
/>,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
await userEvent.click(screen.getByRole('radio', { name: /transactional/i }));
|
|
66
|
+
expect(onChange).toHaveBeenCalledWith('transactional');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('disables individual options when configured', () => {
|
|
70
|
+
const onChange = jest.fn();
|
|
71
|
+
const withDisabled = [
|
|
72
|
+
{ value: 'promotional', label: 'Promotional', disabled: true },
|
|
73
|
+
{ value: 'transactional', label: 'Transactional', disabled: false },
|
|
74
|
+
];
|
|
75
|
+
renderWithIntl(
|
|
76
|
+
<MessageTypeStep
|
|
77
|
+
value="transactional"
|
|
78
|
+
options={withDisabled}
|
|
79
|
+
onChange={onChange}
|
|
80
|
+
/>,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect(screen.getByRole('radio', { name: /promotional/i })).toBeDisabled();
|
|
84
|
+
expect(screen.getByRole('radio', { name: /transactional/i })).not.toBeDisabled();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('shows validation error text below the radios', () => {
|
|
88
|
+
const onChange = jest.fn();
|
|
89
|
+
renderWithIntl(
|
|
90
|
+
<MessageTypeStep
|
|
91
|
+
value="promotional"
|
|
92
|
+
options={OPTIONS}
|
|
93
|
+
onChange={onChange}
|
|
94
|
+
error="Please choose a message type"
|
|
95
|
+
/>,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(screen.getByText('Please choose a message type')).toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { STEPS } from '../constants';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Enabled steps in order from config.features.*.required flags.
|
|
5
|
+
* Channel selection, incentives, delivery, and dynamic controls are toggled independently.
|
|
6
|
+
*/
|
|
7
|
+
export const getEnabledSteps = (config) => {
|
|
8
|
+
const { features = {} } = config;
|
|
9
|
+
const steps = [];
|
|
10
|
+
|
|
11
|
+
if (features.messageTypeData?.required) {
|
|
12
|
+
steps.push(STEPS.MESSAGE_TYPE);
|
|
13
|
+
}
|
|
14
|
+
if (features.communicationStrategyData?.required) {
|
|
15
|
+
steps.push(STEPS.COMMUNICATION_STRATEGY);
|
|
16
|
+
}
|
|
17
|
+
if (features.contentTemplateData?.required) {
|
|
18
|
+
steps.push(STEPS.CHANNEL_SELECTION);
|
|
19
|
+
}
|
|
20
|
+
if (features.incentivesData?.required) {
|
|
21
|
+
steps.push(STEPS.INCENTIVES);
|
|
22
|
+
}
|
|
23
|
+
if (features.deliverySettingsData?.required) {
|
|
24
|
+
steps.push(STEPS.DELIVERY_SETTINGS);
|
|
25
|
+
}
|
|
26
|
+
if (features.dynamicControlsData?.required) {
|
|
27
|
+
steps.push(STEPS.DYNAMIC_CONTROLS);
|
|
28
|
+
}
|
|
29
|
+
return steps;
|
|
30
|
+
};
|
|
@@ -170,6 +170,7 @@ export function SlideBoxContent(props) {
|
|
|
170
170
|
creativesMode,
|
|
171
171
|
hostName = '',
|
|
172
172
|
eventContextTags,
|
|
173
|
+
waitEventContextTags,
|
|
173
174
|
isLoyaltyModule,
|
|
174
175
|
loyaltyMetaData = {},
|
|
175
176
|
showTestAndPreviewSlidebox,
|
|
@@ -453,6 +454,7 @@ export function SlideBoxContent(props) {
|
|
|
453
454
|
selectedOfferDetails,
|
|
454
455
|
getFormData,
|
|
455
456
|
eventContextTags,
|
|
457
|
+
waitEventContextTags,
|
|
456
458
|
};
|
|
457
459
|
|
|
458
460
|
return (
|
|
@@ -487,6 +489,7 @@ export function SlideBoxContent(props) {
|
|
|
487
489
|
enableNewChannels={enableNewChannels}
|
|
488
490
|
hideTestAndPreviewBtn={hideTestAndPreviewBtn}
|
|
489
491
|
eventContextTags={eventContextTags}
|
|
492
|
+
waitEventContextTags={waitEventContextTags}
|
|
490
493
|
loyaltyMetaData={loyaltyMetaData}
|
|
491
494
|
isLoyaltyModule={isLoyaltyModule}
|
|
492
495
|
localTemplatesConfig={localTemplatesConfig}
|
|
@@ -591,6 +594,7 @@ export function SlideBoxContent(props) {
|
|
|
591
594
|
onCreateComplete={onCreateComplete}
|
|
592
595
|
smsRegister={smsRegister}
|
|
593
596
|
eventContextTags={eventContextTags}
|
|
597
|
+
waitEventContextTags={waitEventContextTags}
|
|
594
598
|
getLiquidTags={getLiquidTags}
|
|
595
599
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
596
600
|
handleTestAndPreview={handleTestAndPreview}
|
|
@@ -634,6 +638,7 @@ export function SlideBoxContent(props) {
|
|
|
634
638
|
}}
|
|
635
639
|
hostName={hostName}
|
|
636
640
|
eventContextTags={eventContextTags}
|
|
641
|
+
waitEventContextTags={waitEventContextTags}
|
|
637
642
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
638
643
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
639
644
|
handleTestAndPreview={handleTestAndPreview}
|
|
@@ -675,6 +680,7 @@ export function SlideBoxContent(props) {
|
|
|
675
680
|
eventContextTags={eventContextTags}
|
|
676
681
|
restrictPersonalization={restrictPersonalization}
|
|
677
682
|
isAnonymousType={isAnonymousType}
|
|
683
|
+
waitEventContextTags={waitEventContextTags}
|
|
678
684
|
/>
|
|
679
685
|
)}
|
|
680
686
|
|
|
@@ -708,6 +714,7 @@ export function SlideBoxContent(props) {
|
|
|
708
714
|
moduleType={moduleType}
|
|
709
715
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
710
716
|
eventContextTags={eventContextTags}
|
|
717
|
+
waitEventContextTags={waitEventContextTags}
|
|
711
718
|
isLoyaltyModule={isLoyaltyModule}
|
|
712
719
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
713
720
|
handleTestAndPreview={handleTestAndPreview}
|
|
@@ -752,6 +759,7 @@ export function SlideBoxContent(props) {
|
|
|
752
759
|
moduleType={moduleType}
|
|
753
760
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
754
761
|
eventContextTags={eventContextTags}
|
|
762
|
+
waitEventContextTags={waitEventContextTags}
|
|
755
763
|
isLoyaltyModule={isLoyaltyModule}
|
|
756
764
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
757
765
|
handleTestAndPreview={handleTestAndPreview}
|
|
@@ -791,6 +799,7 @@ export function SlideBoxContent(props) {
|
|
|
791
799
|
moduleType={moduleType}
|
|
792
800
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
793
801
|
eventContextTags={eventContextTags}
|
|
802
|
+
waitEventContextTags={waitEventContextTags}
|
|
794
803
|
isLoyaltyModule={isLoyaltyModule}
|
|
795
804
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
796
805
|
handleTestAndPreview={handleTestAndPreview}
|
|
@@ -834,6 +843,7 @@ export function SlideBoxContent(props) {
|
|
|
834
843
|
hideTestAndPreviewBtn={hideTestAndPreviewBtn}
|
|
835
844
|
creativesMode={creativesMode}
|
|
836
845
|
eventContextTags={eventContextTags}
|
|
846
|
+
waitEventContextTags={waitEventContextTags}
|
|
837
847
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
838
848
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
839
849
|
handleTestAndPreview={handleTestAndPreview}
|
|
@@ -866,6 +876,7 @@ export function SlideBoxContent(props) {
|
|
|
866
876
|
hideTestAndPreviewBtn={hideTestAndPreviewBtn}
|
|
867
877
|
creativesMode={creativesMode}
|
|
868
878
|
eventContextTags={eventContextTags}
|
|
879
|
+
waitEventContextTags={waitEventContextTags}
|
|
869
880
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
870
881
|
handleClose={handleClose}
|
|
871
882
|
restrictPersonalization={restrictPersonalization}
|
|
@@ -905,6 +916,7 @@ export function SlideBoxContent(props) {
|
|
|
905
916
|
hideTestAndPreviewBtn={hideTestAndPreviewBtn}
|
|
906
917
|
onTestContentClicked={onTestContentClicked}
|
|
907
918
|
eventContextTags={eventContextTags}
|
|
919
|
+
waitEventContextTags={waitEventContextTags}
|
|
908
920
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
909
921
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
910
922
|
handleTestAndPreview={handleTestAndPreview}
|
|
@@ -943,6 +955,7 @@ export function SlideBoxContent(props) {
|
|
|
943
955
|
hideTestAndPreviewBtn={hideTestAndPreviewBtn}
|
|
944
956
|
onTestContentClicked={onTestContentClicked}
|
|
945
957
|
eventContextTags={eventContextTags}
|
|
958
|
+
waitEventContextTags={waitEventContextTags}
|
|
946
959
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
947
960
|
onCreateComplete={onCreateComplete}
|
|
948
961
|
creativesMode={creativesMode}
|
|
@@ -968,6 +981,7 @@ export function SlideBoxContent(props) {
|
|
|
968
981
|
onSelectTemplate={onSelectTemplate}
|
|
969
982
|
orgUnitId={orgUnitId}
|
|
970
983
|
eventContextTags={eventContextTags}
|
|
984
|
+
waitEventContextTags={waitEventContextTags}
|
|
971
985
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
972
986
|
/>
|
|
973
987
|
)
|
|
@@ -989,6 +1003,7 @@ export function SlideBoxContent(props) {
|
|
|
989
1003
|
fbAdManager={fbAdManager}
|
|
990
1004
|
onSelectTemplate={onSelectTemplate}
|
|
991
1005
|
eventContextTags={eventContextTags}
|
|
1006
|
+
waitEventContextTags={waitEventContextTags}
|
|
992
1007
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
993
1008
|
/>
|
|
994
1009
|
)
|
|
@@ -1012,6 +1027,7 @@ export function SlideBoxContent(props) {
|
|
|
1012
1027
|
handleClose={handleClose}
|
|
1013
1028
|
selectedOfferDetails={selectedOfferDetails}
|
|
1014
1029
|
eventContextTags={eventContextTags}
|
|
1030
|
+
waitEventContextTags={waitEventContextTags}
|
|
1015
1031
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
1016
1032
|
/>
|
|
1017
1033
|
)
|
|
@@ -1032,6 +1048,7 @@ export function SlideBoxContent(props) {
|
|
|
1032
1048
|
handleClose={handleClose}
|
|
1033
1049
|
selectedOfferDetails={selectedOfferDetails}
|
|
1034
1050
|
eventContextTags={eventContextTags}
|
|
1051
|
+
waitEventContextTags={waitEventContextTags}
|
|
1035
1052
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
1036
1053
|
/>
|
|
1037
1054
|
)
|
|
@@ -1048,6 +1065,7 @@ export function SlideBoxContent(props) {
|
|
|
1048
1065
|
templateData={templateData}
|
|
1049
1066
|
selectedOfferDetails={selectedOfferDetails}
|
|
1050
1067
|
eventContextTags={eventContextTags}
|
|
1068
|
+
waitEventContextTags={waitEventContextTags}
|
|
1051
1069
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
1052
1070
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
1053
1071
|
handleTestAndPreview={handleTestAndPreview}
|
|
@@ -1072,6 +1090,7 @@ export function SlideBoxContent(props) {
|
|
|
1072
1090
|
handleTestAndPreview={handleTestAndPreview}
|
|
1073
1091
|
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
1074
1092
|
eventContextTags={eventContextTags}
|
|
1093
|
+
waitEventContextTags={waitEventContextTags}
|
|
1075
1094
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
1076
1095
|
createNew/> }
|
|
1077
1096
|
|
|
@@ -1079,6 +1098,7 @@ export function SlideBoxContent(props) {
|
|
|
1079
1098
|
isFullMode={isFullMode}
|
|
1080
1099
|
onCreateComplete={onCreateComplete}
|
|
1081
1100
|
eventContextTags={eventContextTags}
|
|
1101
|
+
waitEventContextTags={waitEventContextTags}
|
|
1082
1102
|
handleClose={handleClose}
|
|
1083
1103
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
1084
1104
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -1096,6 +1116,7 @@ export function SlideBoxContent(props) {
|
|
|
1096
1116
|
forwardedTags={forwardedTags}
|
|
1097
1117
|
selectedOfferDetails={selectedOfferDetails}
|
|
1098
1118
|
eventContextTags={eventContextTags}
|
|
1119
|
+
waitEventContextTags={waitEventContextTags}
|
|
1099
1120
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
1100
1121
|
handleTestAndPreview={handleTestAndPreview}
|
|
1101
1122
|
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
@@ -1134,6 +1155,7 @@ export function SlideBoxContent(props) {
|
|
|
1134
1155
|
onPreviewContentClicked={onPreviewContentClicked}
|
|
1135
1156
|
onTestContentClicked={onTestContentClicked}
|
|
1136
1157
|
eventContextTags={eventContextTags}
|
|
1158
|
+
waitEventContextTags={waitEventContextTags}
|
|
1137
1159
|
onCreateComplete={onCreateComplete}
|
|
1138
1160
|
handleClose={handleClose}
|
|
1139
1161
|
moduleType={moduleType}
|
|
@@ -1169,6 +1191,7 @@ export function SlideBoxContent(props) {
|
|
|
1169
1191
|
moduleType={moduleType}
|
|
1170
1192
|
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
1171
1193
|
eventContextTags={eventContextTags}
|
|
1194
|
+
waitEventContextTags={waitEventContextTags}
|
|
1172
1195
|
onCreateComplete={onCreateComplete}
|
|
1173
1196
|
handleClose={handleClose}
|
|
1174
1197
|
getDefaultTags={type}
|
|
@@ -1192,6 +1215,7 @@ export function SlideBoxContent(props) {
|
|
|
1192
1215
|
onCreateComplete={onCreateComplete}
|
|
1193
1216
|
selectedOfferDetails={selectedOfferDetails}
|
|
1194
1217
|
eventContextTags={eventContextTags}
|
|
1218
|
+
waitEventContextTags={waitEventContextTags}
|
|
1195
1219
|
params={{
|
|
1196
1220
|
id: templateData._id,
|
|
1197
1221
|
}}
|
|
@@ -1230,6 +1254,7 @@ export function SlideBoxContent(props) {
|
|
|
1230
1254
|
eventContextTags={eventContextTags}
|
|
1231
1255
|
restrictPersonalization={restrictPersonalization}
|
|
1232
1256
|
isAnonymousType={isAnonymousType}
|
|
1257
|
+
waitEventContextTags={waitEventContextTags}
|
|
1233
1258
|
/>
|
|
1234
1259
|
)}
|
|
1235
1260
|
{isCreateRcs && (<Rcs
|
|
@@ -1324,6 +1349,8 @@ SlideBoxContent.propTypes = {
|
|
|
1324
1349
|
showTestAndPreviewSlidebox: PropTypes.bool,
|
|
1325
1350
|
handleTestAndPreview: PropTypes.func,
|
|
1326
1351
|
handleCloseTestAndPreview: PropTypes.func,
|
|
1327
|
-
isTestAndPreviewMode: PropTypes.bool
|
|
1352
|
+
isTestAndPreviewMode: PropTypes.bool,
|
|
1353
|
+
waitEventContextTags: PropTypes.object,
|
|
1354
|
+
eventContextTags: PropTypes.array,
|
|
1328
1355
|
};
|
|
1329
1356
|
export default SlideBoxContent;
|
|
@@ -11,6 +11,7 @@ export const EBILL = "EBILL";
|
|
|
11
11
|
export const LINE = "LINE";
|
|
12
12
|
export const CALL_TASK = "CALL_TASK";
|
|
13
13
|
export const MOBILE_PUSH = "MOBILEPUSH";
|
|
14
|
+
export const MPUSH = "MPUSH";
|
|
14
15
|
export const WECHAT = "WECHAT";
|
|
15
16
|
export const FACEBOOK = "FACEBOOK";
|
|
16
17
|
export const FTP = "FTP";
|
|
@@ -57,6 +58,8 @@ export const COMMON_CHANNELS = ['sms', 'email', 'wechat', 'mobilepush', 'webpush
|
|
|
57
58
|
export const NORMALIZED_CHANNEL_ALIASES = {
|
|
58
59
|
we_chat: WECHAT.toLowerCase(),
|
|
59
60
|
m_push: MOBILE_PUSH.toLowerCase(),
|
|
61
|
+
// paneKey `inApp` → `in_app`; TemplatesV2 pane uses key INAPP → `inapp` — both must match for channelsToHide
|
|
62
|
+
in_app: INAPP.toLowerCase(),
|
|
60
63
|
};
|
|
61
64
|
export const MIXED = "MIXED";
|
|
62
65
|
export const VISITOR = "VISITOR";
|