@capillarytech/creatives-library 8.0.330-alpha.0 → 8.0.330
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 +0 -18
- package/package.json +1 -1
- package/services/api.js +0 -17
- package/services/tests/api.test.js +0 -85
- package/utils/commonUtils.js +0 -28
- package/utils/tests/commonUtil.test.js +0 -169
- package/v2Components/CapTagList/index.js +0 -10
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -70
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -207
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +53 -87
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +1 -20
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +34 -145
- package/v2Components/CommonTestAndPreview/actions.js +0 -10
- package/v2Components/CommonTestAndPreview/constants.js +1 -53
- package/v2Components/CommonTestAndPreview/index.js +168 -998
- package/v2Components/CommonTestAndPreview/messages.js +3 -147
- package/v2Components/CommonTestAndPreview/reducer.js +0 -10
- package/v2Components/CommonTestAndPreview/sagas.js +6 -15
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +286 -328
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +24 -65
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -31
- package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -168
- package/v2Components/CommonTestAndPreview/tests/reducer.test.js +0 -71
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
- package/v2Components/CommonTestAndPreview/tests/selectors.test.js +0 -17
- package/v2Components/FormBuilder/index.js +1 -7
- package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
- package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
- package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
- package/v2Containers/CreativesContainer/constants.js +0 -9
- package/v2Containers/CreativesContainer/index.js +93 -292
- package/v2Containers/CreativesContainer/index.scss +1 -51
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +10 -20
- package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
- package/v2Containers/Rcs/constants.js +3 -40
- package/v2Containers/Rcs/index.js +895 -1145
- package/v2Containers/Rcs/index.scss +6 -85
- package/v2Containers/Rcs/messages.js +2 -12
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +2236 -41719
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
- package/v2Containers/Rcs/tests/index.test.js +38 -41
- package/v2Containers/Rcs/tests/mockData.js +0 -38
- package/v2Containers/Rcs/tests/utils.test.js +1 -435
- package/v2Containers/Rcs/utils.js +10 -405
- package/v2Containers/Sms/Create/index.js +38 -100
- package/v2Containers/SmsTrai/Create/index.js +4 -9
- package/v2Containers/SmsTrai/Edit/constants.js +0 -2
- package/v2Containers/SmsTrai/Edit/index.js +128 -636
- package/v2Containers/SmsTrai/Edit/messages.js +4 -14
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2604 -4590
- package/v2Containers/SmsWrapper/index.js +8 -37
- package/v2Containers/TagList/index.js +0 -6
- package/v2Containers/Templates/_templates.scss +2 -63
- package/v2Containers/Templates/actions.js +0 -11
- package/v2Containers/Templates/constants.js +0 -2
- package/v2Containers/Templates/index.js +40 -90
- package/v2Containers/Templates/sagas.js +12 -57
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1079 -1043
- package/v2Containers/Templates/tests/sagas.test.js +123 -193
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
- package/v2Containers/TemplatesV2/index.js +23 -86
- package/v2Containers/Whatsapp/index.js +20 -3
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +4872 -5790
- package/utils/templateVarUtils.js +0 -201
- package/utils/tests/templateVarUtils.test.js +0 -204
- package/v2Components/CommonTestAndPreview/AddTestCustomer.js +0 -42
- package/v2Components/CommonTestAndPreview/CustomerCreationModal.js +0 -155
- package/v2Components/CommonTestAndPreview/ExistingCustomerModal.js +0 -93
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
- package/v2Components/CommonTestAndPreview/tests/AddTestCustomer.test.js +0 -66
- package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -648
- package/v2Components/CommonTestAndPreview/tests/CustomerCreationModal.test.js +0 -174
- package/v2Components/CommonTestAndPreview/tests/ExistingCustomerModal.test.js +0 -114
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -87
- package/v2Components/SmsFallback/constants.js +0 -73
- package/v2Components/SmsFallback/index.js +0 -955
- package/v2Components/SmsFallback/index.scss +0 -265
- package/v2Components/SmsFallback/messages.js +0 -78
- package/v2Components/SmsFallback/smsFallbackUtils.js +0 -118
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -197
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -277
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
- package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
- package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/index.js +0 -125
- package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -67
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
- package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
- package/v2Containers/SmsTrai/Edit/index.scss +0 -121
- package/v2Containers/Templates/TemplatesActionBar.js +0 -101
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
@import '~@capillarytech/cap-ui-library/styles/_variables';
|
|
2
|
-
|
|
3
|
-
.sms-trai-segmented-editor {
|
|
4
|
-
.ant-input {
|
|
5
|
-
margin-bottom: 0.125rem;
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/*
|
|
10
|
-
* DLT SMS fallback edit only: mirror RCS rich-card message box (`.cap-rcs-creatives` + default
|
|
11
|
-
* VarSegment `rcs-edit-template-message-input` / `rcs-edit-template-message-split`).
|
|
12
|
-
*/
|
|
13
|
-
.sms-trai-edit-rcs-fallback {
|
|
14
|
-
width: 100%;
|
|
15
|
-
|
|
16
|
-
.rcs_text_area_wrapper {
|
|
17
|
-
position: relative;
|
|
18
|
-
width: 100%;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-input {
|
|
22
|
-
background-color: $CAP_G10;
|
|
23
|
-
padding: $CAP_SPACE_12 $CAP_SPACE_16;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-split {
|
|
27
|
-
margin-bottom: $CAP_SPACE_08;
|
|
28
|
-
overflow: hidden;
|
|
29
|
-
text-overflow: ellipsis;
|
|
30
|
-
color: $FONT_COLOR_03;
|
|
31
|
-
font-weight: 500;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-input .ant-input,
|
|
35
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-input textarea.ant-input {
|
|
36
|
-
width: 100%;
|
|
37
|
-
box-sizing: border-box;
|
|
38
|
-
min-height: 2.5rem;
|
|
39
|
-
padding-top: $CAP_SPACE_08;
|
|
40
|
-
padding-bottom: $CAP_SPACE_08;
|
|
41
|
-
border-color: $CAP_G07;
|
|
42
|
-
box-shadow: none;
|
|
43
|
-
overflow: hidden;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-input .ant-input:focus,
|
|
47
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-input .ant-input:active,
|
|
48
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-input textarea.ant-input:focus,
|
|
49
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-input textarea.ant-input:active {
|
|
50
|
-
border-color: $CAP_G07;
|
|
51
|
-
box-shadow: none;
|
|
52
|
-
outline: none;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/*
|
|
56
|
-
* DLT per-slot hint: long selector (under CapSpin + message row) for specificity without !important.
|
|
57
|
-
*/
|
|
58
|
-
.rcs_text_area_wrapper .rcs-edit-template-message-input .var-segment-message-editor__var-slot {
|
|
59
|
-
display: flex;
|
|
60
|
-
flex-direction: column;
|
|
61
|
-
align-items: stretch;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.rcs_text_area_wrapper
|
|
65
|
-
.rcs-edit-template-message-input
|
|
66
|
-
.var-segment-message-editor__var-slot
|
|
67
|
-
span.sms-trai-rcs-fallback-var-hint {
|
|
68
|
-
display: block;
|
|
69
|
-
box-sizing: border-box;
|
|
70
|
-
flex-shrink: 0;
|
|
71
|
-
margin-top: $CAP_SPACE_04;
|
|
72
|
-
margin-left: auto;
|
|
73
|
-
margin-right: 0;
|
|
74
|
-
width: fit-content;
|
|
75
|
-
max-width: 100%;
|
|
76
|
-
text-align: right;
|
|
77
|
-
color: $FONT_COLOR_02;
|
|
78
|
-
font-weight: 400;
|
|
79
|
-
font-size: 0.75rem;
|
|
80
|
-
line-height: 1rem;
|
|
81
|
-
opacity: 0.92;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/* Footer “1 SMS (n characters)” — match RCS message typography, not muted gray */
|
|
85
|
-
.rcs-character-count,
|
|
86
|
-
.rcs-character-count--compact {
|
|
87
|
-
color: $FONT_COLOR_03;
|
|
88
|
-
font-weight: 500;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.rcs-character-count {
|
|
93
|
-
display: block;
|
|
94
|
-
margin-top: $CAP_SPACE_16;
|
|
95
|
-
margin-bottom: $CAP_SPACE_04;
|
|
96
|
-
text-align: right;
|
|
97
|
-
color: $FONT_COLOR_02;
|
|
98
|
-
width: 100%;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.rcs-character-count--compact {
|
|
102
|
-
font-size: 0.75rem;
|
|
103
|
-
line-height: 1rem;
|
|
104
|
-
font-weight: 400;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/* Non–RCS fallback: segmented editor shell + character count row (was inline styles on CapRow) */
|
|
108
|
-
.sms-trai-editor-segment-row {
|
|
109
|
-
background-color: $CAP_G10;
|
|
110
|
-
padding: $CAP_SPACE_16;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.sms-trai-length-row {
|
|
114
|
-
display: flex;
|
|
115
|
-
justify-content: flex-end;
|
|
116
|
-
margin-top: $CAP_SPACE_04;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.sms-trai-edit-bottom-spacer {
|
|
120
|
-
margin-bottom: 6.25rem;
|
|
121
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import CapInput from '@capillarytech/cap-ui-library/CapInput';
|
|
4
|
-
import CapButton from '@capillarytech/cap-ui-library/CapButton';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Reusable action bar for template pickers.
|
|
8
|
-
* Layout and spacing live in `_templates.scss` (`.action-container`, `.action-container__toolbar-row`).
|
|
9
|
-
* Default search field width: `.action-container__toolbar-row .search-text` (13.125rem).
|
|
10
|
-
* Pass `searchInputClassName` / `searchInputStyle` to override (defaults match Templates list: 210px per master).
|
|
11
|
-
*/
|
|
12
|
-
const TemplatesActionBar = ({
|
|
13
|
-
searchValue,
|
|
14
|
-
onSearchChange,
|
|
15
|
-
onSearch,
|
|
16
|
-
onClear,
|
|
17
|
-
searchPlaceholder,
|
|
18
|
-
searchInputClassName,
|
|
19
|
-
searchInputStyle,
|
|
20
|
-
ctaLabel,
|
|
21
|
-
onCtaClick,
|
|
22
|
-
ctaDisabled,
|
|
23
|
-
ctaClassName,
|
|
24
|
-
ctaNode,
|
|
25
|
-
children,
|
|
26
|
-
showCta = true,
|
|
27
|
-
}) => (
|
|
28
|
-
<div className="action-container">
|
|
29
|
-
<div className="action-container__toolbar-row">
|
|
30
|
-
{searchPlaceholder && (
|
|
31
|
-
<CapInput.Search
|
|
32
|
-
className={['search-text', searchInputClassName].filter(Boolean).join(' ')}
|
|
33
|
-
placeholder={searchPlaceholder}
|
|
34
|
-
value={searchValue}
|
|
35
|
-
onChange={onSearchChange}
|
|
36
|
-
/* antd `Input` (used by CapInput.Search) has no `onSearch`; only `Input.Search` does. */
|
|
37
|
-
onPressEnter={(e) => {
|
|
38
|
-
if (onSearch) {
|
|
39
|
-
const v = e?.target && 'value' in e.target ? e.target.value : searchValue;
|
|
40
|
-
onSearch(v);
|
|
41
|
-
}
|
|
42
|
-
}}
|
|
43
|
-
onSearch={onSearch}
|
|
44
|
-
onClear={onClear}
|
|
45
|
-
onScroll={(e) => e.stopPropagation()}
|
|
46
|
-
/>
|
|
47
|
-
)}
|
|
48
|
-
{children}
|
|
49
|
-
</div>
|
|
50
|
-
{showCta && (
|
|
51
|
-
<div>
|
|
52
|
-
{ctaNode || (
|
|
53
|
-
<CapButton
|
|
54
|
-
className={ctaClassName}
|
|
55
|
-
type="primary"
|
|
56
|
-
disabled={ctaDisabled}
|
|
57
|
-
onClick={onCtaClick}
|
|
58
|
-
>
|
|
59
|
-
{ctaLabel}
|
|
60
|
-
</CapButton>
|
|
61
|
-
)}
|
|
62
|
-
</div>
|
|
63
|
-
)}
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
TemplatesActionBar.propTypes = {
|
|
68
|
-
searchValue: PropTypes.string,
|
|
69
|
-
onSearchChange: PropTypes.func,
|
|
70
|
-
onSearch: PropTypes.func,
|
|
71
|
-
onClear: PropTypes.func,
|
|
72
|
-
searchPlaceholder: PropTypes.string,
|
|
73
|
-
searchInputClassName: PropTypes.string,
|
|
74
|
-
searchInputStyle: PropTypes.object,
|
|
75
|
-
ctaLabel: PropTypes.node,
|
|
76
|
-
onCtaClick: PropTypes.func,
|
|
77
|
-
ctaDisabled: PropTypes.bool,
|
|
78
|
-
ctaClassName: PropTypes.string,
|
|
79
|
-
ctaNode: PropTypes.node,
|
|
80
|
-
children: PropTypes.node,
|
|
81
|
-
showCta: PropTypes.bool,
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
TemplatesActionBar.defaultProps = {
|
|
85
|
-
searchValue: '',
|
|
86
|
-
onSearchChange: () => {},
|
|
87
|
-
onSearch: () => {},
|
|
88
|
-
onClear: () => {},
|
|
89
|
-
searchPlaceholder: '',
|
|
90
|
-
searchInputClassName: '',
|
|
91
|
-
searchInputStyle: { width: '210px' },
|
|
92
|
-
ctaLabel: null,
|
|
93
|
-
onCtaClick: () => {},
|
|
94
|
-
ctaDisabled: false,
|
|
95
|
-
ctaClassName: '',
|
|
96
|
-
ctaNode: null,
|
|
97
|
-
children: null,
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export default TemplatesActionBar;
|
|
101
|
-
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @jest-environment jsdom
|
|
3
|
-
*/
|
|
4
|
-
import React from 'react';
|
|
5
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
6
|
-
import '@testing-library/jest-dom';
|
|
7
|
-
import TemplatesActionBar from '../TemplatesActionBar';
|
|
8
|
-
|
|
9
|
-
jest.mock('@capillarytech/cap-ui-library/CapInput', () => {
|
|
10
|
-
const React = require('react');
|
|
11
|
-
function Search(props) {
|
|
12
|
-
return React.createElement('input', {
|
|
13
|
-
'data-testid': 'cap-input-search',
|
|
14
|
-
value: props?.value,
|
|
15
|
-
placeholder: props?.placeholder,
|
|
16
|
-
onChange: props?.onChange,
|
|
17
|
-
onKeyDown: (e) => {
|
|
18
|
-
if (e.key === 'Enter' && props.onPressEnter) {
|
|
19
|
-
props.onPressEnter(e);
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
function CapInput() {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
CapInput.Search = Search;
|
|
28
|
-
return { __esModule: true, default: CapInput };
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
jest.mock('@capillarytech/cap-ui-library/CapButton', () => {
|
|
32
|
-
const React = require('react');
|
|
33
|
-
return function CapButton(props) {
|
|
34
|
-
return React.createElement('button', {
|
|
35
|
-
type: 'button',
|
|
36
|
-
'data-testid': 'cta',
|
|
37
|
-
onClick: props?.onClick,
|
|
38
|
-
disabled: props?.disabled,
|
|
39
|
-
}, props?.children);
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('TemplatesActionBar', () => {
|
|
44
|
-
it('renders search when searchPlaceholder is set', () => {
|
|
45
|
-
render(
|
|
46
|
-
<TemplatesActionBar
|
|
47
|
-
searchPlaceholder="Find templates"
|
|
48
|
-
searchValue="hi"
|
|
49
|
-
ctaLabel="Create"
|
|
50
|
-
/>,
|
|
51
|
-
);
|
|
52
|
-
expect(screen.getByTestId('cap-input-search')).toHaveAttribute('placeholder', 'Find templates');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('omits search when searchPlaceholder is empty', () => {
|
|
56
|
-
const { container } = render(
|
|
57
|
-
<TemplatesActionBar searchPlaceholder="" ctaLabel="Go" />,
|
|
58
|
-
);
|
|
59
|
-
expect(container.querySelector('[data-testid="cap-input-search"]')).toBeNull();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('fires onSearchChange and onCtaClick', () => {
|
|
63
|
-
const onSearchChange = jest.fn();
|
|
64
|
-
const onCtaClick = jest.fn();
|
|
65
|
-
render(
|
|
66
|
-
<TemplatesActionBar
|
|
67
|
-
searchPlaceholder="S"
|
|
68
|
-
onSearchChange={onSearchChange}
|
|
69
|
-
ctaLabel="New"
|
|
70
|
-
onCtaClick={onCtaClick}
|
|
71
|
-
/>,
|
|
72
|
-
);
|
|
73
|
-
fireEvent.change(screen.getByTestId('cap-input-search'), { target: { value: 'x' } });
|
|
74
|
-
fireEvent.click(screen.getByTestId('cta'));
|
|
75
|
-
expect(onSearchChange).toHaveBeenCalled();
|
|
76
|
-
expect(onCtaClick).toHaveBeenCalled();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('fires onSearch when Enter is pressed (antd Input has no native onSearch)', () => {
|
|
80
|
-
const onSearch = jest.fn();
|
|
81
|
-
render(
|
|
82
|
-
<TemplatesActionBar
|
|
83
|
-
searchPlaceholder="S"
|
|
84
|
-
searchValue="query"
|
|
85
|
-
onSearch={onSearch}
|
|
86
|
-
ctaLabel="New"
|
|
87
|
-
/>,
|
|
88
|
-
);
|
|
89
|
-
const input = screen.getByTestId('cap-input-search');
|
|
90
|
-
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
|
|
91
|
-
expect(onSearch).toHaveBeenCalledWith('query');
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('renders ctaNode instead of default button when provided', () => {
|
|
95
|
-
render(
|
|
96
|
-
<TemplatesActionBar
|
|
97
|
-
searchPlaceholder="S"
|
|
98
|
-
ctaNode={<span data-testid="custom-cta">Custom</span>}
|
|
99
|
-
/>,
|
|
100
|
-
);
|
|
101
|
-
expect(screen.getByTestId('custom-cta')).toBeInTheDocument();
|
|
102
|
-
expect(screen.queryByTestId('cta')).toBeNull();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('hides CTA area when showCta is false', () => {
|
|
106
|
-
const { container } = render(
|
|
107
|
-
<TemplatesActionBar searchPlaceholder="S" showCta={false} ctaLabel="X" />,
|
|
108
|
-
);
|
|
109
|
-
expect(container.querySelector('[data-testid="cta"]')).toBeNull();
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('renders children in toolbar row', () => {
|
|
113
|
-
render(
|
|
114
|
-
<TemplatesActionBar searchPlaceholder="S" ctaLabel="C">
|
|
115
|
-
<span data-testid="child">extra</span>
|
|
116
|
-
</TemplatesActionBar>,
|
|
117
|
-
);
|
|
118
|
-
expect(screen.getByTestId('child')).toBeInTheDocument();
|
|
119
|
-
});
|
|
120
|
-
});
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import * as Api from '../../../services/api';
|
|
2
|
-
import { isTraiDLTEnable } from '../../../utils/common';
|
|
3
|
-
|
|
4
|
-
jest.mock('../../../services/api', () => ({
|
|
5
|
-
getAllTemplates: jest.fn(),
|
|
6
|
-
}));
|
|
7
|
-
|
|
8
|
-
jest.mock('../../../utils/common', () => ({
|
|
9
|
-
isTraiDLTEnable: jest.fn(),
|
|
10
|
-
}));
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
buildSmsTemplatesListQueryParams,
|
|
14
|
-
fetchSmsTemplatesFromQuery,
|
|
15
|
-
fetchSmsTemplatesListPage,
|
|
16
|
-
SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
17
|
-
} from '../utils/smsTemplatesListApi';
|
|
18
|
-
|
|
19
|
-
describe('smsTemplatesListApi', () => {
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
jest.clearAllMocks();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe('buildSmsTemplatesListQueryParams', () => {
|
|
25
|
-
it('includes traiEnable when TRAI DLT is enabled', () => {
|
|
26
|
-
isTraiDLTEnable.mockReturnValue(true);
|
|
27
|
-
const q = buildSmsTemplatesListQueryParams({
|
|
28
|
-
page: 1,
|
|
29
|
-
perPage: 25,
|
|
30
|
-
name: 'x',
|
|
31
|
-
sortBy: SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
32
|
-
isFullMode: true,
|
|
33
|
-
smsRegister: {},
|
|
34
|
-
});
|
|
35
|
-
expect(q).toEqual({
|
|
36
|
-
page: 1,
|
|
37
|
-
perPage: 25,
|
|
38
|
-
sortBy: SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
39
|
-
name: 'x',
|
|
40
|
-
traiEnable: true,
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('omits traiEnable when TRAI DLT is disabled', () => {
|
|
45
|
-
isTraiDLTEnable.mockReturnValue(false);
|
|
46
|
-
const q = buildSmsTemplatesListQueryParams({
|
|
47
|
-
page: 2,
|
|
48
|
-
perPage: 10,
|
|
49
|
-
isFullMode: false,
|
|
50
|
-
smsRegister: null,
|
|
51
|
-
});
|
|
52
|
-
expect(q.traiEnable).toBeUndefined();
|
|
53
|
-
expect(q.name).toBe('');
|
|
54
|
-
expect(q.sortBy).toBe(SMS_TEMPLATES_LIST_SORT_MOST_RECENT);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe('fetchSmsTemplatesFromQuery', () => {
|
|
59
|
-
it('returns channelTemplates, weCRMTemplate, and raw; maps intl copy on names', async () => {
|
|
60
|
-
Api.getAllTemplates.mockResolvedValue({
|
|
61
|
-
response: {
|
|
62
|
-
templates: [{ name: 'Copy of A', _id: '1' }],
|
|
63
|
-
unMapped: { u: 1 },
|
|
64
|
-
totalCount: 5,
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const out = await fetchSmsTemplatesFromQuery(
|
|
69
|
-
{ page: 1, perPage: 25 },
|
|
70
|
-
'Kopie',
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
expect(Api.getAllTemplates).toHaveBeenCalledWith({
|
|
74
|
-
channel: 'Sms',
|
|
75
|
-
queryParams: { page: 1, perPage: 25 },
|
|
76
|
-
});
|
|
77
|
-
expect(out.weCRMTemplate).toEqual({ u: 1 });
|
|
78
|
-
expect(out.raw.response.templates[0].name).toBe('Copy of A');
|
|
79
|
-
expect(out.channelTemplates.templates[0].name).toBe('Kopie A');
|
|
80
|
-
expect(out.channelTemplates.totalCount).toBe(5);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('skips name mapping when intlCopyOf is empty', async () => {
|
|
84
|
-
Api.getAllTemplates.mockResolvedValue({
|
|
85
|
-
response: {
|
|
86
|
-
templates: [{ name: 'Copy of A' }],
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
const out = await fetchSmsTemplatesFromQuery({ page: 1 }, '');
|
|
90
|
-
expect(out.channelTemplates.templates[0].name).toBe('Copy of A');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('handles missing response.templates', async () => {
|
|
94
|
-
Api.getAllTemplates.mockResolvedValue({ response: {} });
|
|
95
|
-
const out = await fetchSmsTemplatesFromQuery({}, '');
|
|
96
|
-
expect(out.channelTemplates.templates).toEqual([]);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('uses empty response when raw.response is missing', async () => {
|
|
100
|
-
Api.getAllTemplates.mockResolvedValue({});
|
|
101
|
-
const out = await fetchSmsTemplatesFromQuery({}, '');
|
|
102
|
-
expect(out.channelTemplates.templates).toEqual([]);
|
|
103
|
-
expect(out.weCRMTemplate).toBeUndefined();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('does not map names when intlCopyOf is set but templates list is empty', async () => {
|
|
107
|
-
Api.getAllTemplates.mockResolvedValue({
|
|
108
|
-
response: { templates: [] },
|
|
109
|
-
});
|
|
110
|
-
const out = await fetchSmsTemplatesFromQuery({ page: 1 }, 'X');
|
|
111
|
-
expect(out.channelTemplates.templates).toEqual([]);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('uses empty string when template name is missing during intl mapping', async () => {
|
|
115
|
-
Api.getAllTemplates.mockResolvedValue({
|
|
116
|
-
response: {
|
|
117
|
-
templates: [{ _id: 'n', name: undefined }],
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
const out = await fetchSmsTemplatesFromQuery({ page: 1 }, 'Lbl');
|
|
121
|
-
expect(out.channelTemplates.templates[0].name).toBe('');
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
describe('fetchSmsTemplatesListPage', () => {
|
|
126
|
-
it('falls back to total when totalCount is absent', async () => {
|
|
127
|
-
isTraiDLTEnable.mockReturnValue(false);
|
|
128
|
-
Api.getAllTemplates.mockResolvedValue({
|
|
129
|
-
response: {
|
|
130
|
-
templates: [{ _id: 'a' }],
|
|
131
|
-
total: 7,
|
|
132
|
-
},
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
const page = await fetchSmsTemplatesListPage({
|
|
136
|
-
page: 1,
|
|
137
|
-
perPage: 25,
|
|
138
|
-
name: '',
|
|
139
|
-
sortBy: SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
140
|
-
isFullMode: true,
|
|
141
|
-
smsRegister: {},
|
|
142
|
-
intlCopyOf: '',
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
expect(page.templates).toEqual([{ _id: 'a' }]);
|
|
146
|
-
expect(page.totalCount).toBe(7);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('uses totalCount when set', async () => {
|
|
150
|
-
isTraiDLTEnable.mockReturnValue(false);
|
|
151
|
-
Api.getAllTemplates.mockResolvedValue({
|
|
152
|
-
response: {
|
|
153
|
-
templates: [],
|
|
154
|
-
totalCount: 12,
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
const page = await fetchSmsTemplatesListPage({
|
|
158
|
-
page: 1,
|
|
159
|
-
perPage: 25,
|
|
160
|
-
isFullMode: false,
|
|
161
|
-
smsRegister: {},
|
|
162
|
-
});
|
|
163
|
-
expect(page.totalCount).toBe(12);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('normalizes total to 0 when missing counts', async () => {
|
|
167
|
-
isTraiDLTEnable.mockReturnValue(false);
|
|
168
|
-
Api.getAllTemplates.mockResolvedValue({
|
|
169
|
-
response: { templates: [] },
|
|
170
|
-
});
|
|
171
|
-
const page = await fetchSmsTemplatesListPage({
|
|
172
|
-
page: 1,
|
|
173
|
-
perPage: 25,
|
|
174
|
-
isFullMode: false,
|
|
175
|
-
smsRegister: {},
|
|
176
|
-
});
|
|
177
|
-
expect(page.totalCount).toBe(0);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
});
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import get from 'lodash/get';
|
|
2
|
-
import * as Api from '../../../services/api';
|
|
3
|
-
import { COPY_OF } from '../../../constants/unified';
|
|
4
|
-
import { isTraiDLTEnable } from '../../../utils/common';
|
|
5
|
-
|
|
6
|
-
/** Matches Templates `getAllTemplates` default for SMS. */
|
|
7
|
-
export const SMS_TEMPLATES_LIST_SORT_MOST_RECENT = 'Most Recent';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Same query shape as Redux `GET_ALL_TEMPLATES` for channel Sms (DLT vs non-DLT via traiEnable).
|
|
11
|
-
*/
|
|
12
|
-
export function buildSmsTemplatesListQueryParams({
|
|
13
|
-
page,
|
|
14
|
-
perPage,
|
|
15
|
-
name = '',
|
|
16
|
-
sortBy = SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
17
|
-
isFullMode,
|
|
18
|
-
smsRegister,
|
|
19
|
-
}) {
|
|
20
|
-
const traiDlt = isTraiDLTEnable(isFullMode, smsRegister);
|
|
21
|
-
return {
|
|
22
|
-
page,
|
|
23
|
-
perPage,
|
|
24
|
-
sortBy,
|
|
25
|
-
name: name || '',
|
|
26
|
-
...(traiDlt ? { traiEnable: true } : {}),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* SMS list for Redux saga: uses queryParams already built by Templates (incl. traiEnable).
|
|
32
|
-
* Applies the same "Copy of" → intl label as the former inline saga logic.
|
|
33
|
-
*/
|
|
34
|
-
export async function fetchSmsTemplatesFromQuery(queryParams, intlCopyOf = '') {
|
|
35
|
-
const raw = await Api.getAllTemplates({ channel: 'Sms', queryParams });
|
|
36
|
-
const response = raw.response || {};
|
|
37
|
-
let templates = get(response, 'templates', []) || [];
|
|
38
|
-
if (intlCopyOf && templates.length) {
|
|
39
|
-
templates = templates.map((template) => ({
|
|
40
|
-
...template,
|
|
41
|
-
name: (template.name || '').replace(new RegExp(COPY_OF, 'g'), intlCopyOf),
|
|
42
|
-
}));
|
|
43
|
-
}
|
|
44
|
-
const channelTemplates = { ...response, templates };
|
|
45
|
-
return {
|
|
46
|
-
channelTemplates,
|
|
47
|
-
weCRMTemplate: response.unMapped,
|
|
48
|
-
raw,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* SMS list for the RCS SMS fallback picker only.
|
|
54
|
-
* Called from `useLocalTemplateList` in SmsFallback — keeps data in component state and pairs with
|
|
55
|
-
* `localTemplatesConfig` / `useLocalTemplates` in TemplatesV2. Does **not** use GET_ALL_TEMPLATES saga.
|
|
56
|
-
* Same HTTP call shape as `fetchSmsTemplatesFromQuery` (used by the main SMS GET_ALL_TEMPLATES saga).
|
|
57
|
-
*/
|
|
58
|
-
export async function fetchSmsTemplatesListPage({
|
|
59
|
-
page,
|
|
60
|
-
perPage,
|
|
61
|
-
name,
|
|
62
|
-
sortBy,
|
|
63
|
-
isFullMode,
|
|
64
|
-
smsRegister,
|
|
65
|
-
intlCopyOf = '',
|
|
66
|
-
}) {
|
|
67
|
-
const queryParams = buildSmsTemplatesListQueryParams({
|
|
68
|
-
page,
|
|
69
|
-
perPage,
|
|
70
|
-
name,
|
|
71
|
-
sortBy,
|
|
72
|
-
isFullMode,
|
|
73
|
-
smsRegister,
|
|
74
|
-
});
|
|
75
|
-
const { channelTemplates } = await fetchSmsTemplatesFromQuery(queryParams, intlCopyOf);
|
|
76
|
-
const templates = channelTemplates.templates || [];
|
|
77
|
-
const totalCount = get(channelTemplates, 'totalCount', get(channelTemplates, 'total', 0)) || 0;
|
|
78
|
-
return { templates, totalCount };
|
|
79
|
-
}
|