@capillarytech/creatives-library 8.0.125-alpha.6 → 8.0.126

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 (105) hide show
  1. package/config/app.js +6 -0
  2. package/containers/App/constants.js +0 -1
  3. package/containers/Email/index.js +5 -5
  4. package/containers/WeChat/RichmediaTemplates/Create/index.js +1 -1
  5. package/initialReducer.js +2 -0
  6. package/package.json +1 -1
  7. package/services/api.js +94 -1
  8. package/services/tests/api.test.js +191 -0
  9. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +3 -8
  10. package/tests/integration/TemplateCreation/api-response.js +0 -5
  11. package/tests/integration/TemplateCreation/msw-handler.js +63 -42
  12. package/utils/common.js +0 -7
  13. package/utils/commonUtils.js +6 -2
  14. package/v2Components/CapImageUpload/index.js +45 -51
  15. package/v2Components/CapInAppCTA/index.js +0 -1
  16. package/v2Components/CapTagList/index.js +120 -177
  17. package/v2Components/CapVideoUpload/constants.js +0 -3
  18. package/v2Components/CapVideoUpload/index.js +110 -167
  19. package/v2Components/CapVideoUpload/messages.js +0 -16
  20. package/v2Components/Carousel/index.js +13 -15
  21. package/v2Components/CustomerSearchSection/_customerSearch.scss +309 -0
  22. package/v2Components/CustomerSearchSection/constants.js +5 -0
  23. package/v2Components/CustomerSearchSection/index.js +362 -0
  24. package/v2Components/CustomerSearchSection/messages.js +20 -0
  25. package/v2Components/CustomerSearchSection/tests/utils.test.js +334 -0
  26. package/v2Components/CustomerSearchSection/utils.js +49 -0
  27. package/v2Components/ErrorInfoNote/style.scss +0 -1
  28. package/v2Components/MobilePushPreviewV2/index.js +5 -37
  29. package/v2Components/TemplatePreview/_templatePreview.scss +72 -114
  30. package/v2Components/TemplatePreview/index.js +50 -178
  31. package/v2Components/TemplatePreview/messages.js +0 -4
  32. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +543 -0
  33. package/v2Components/TestAndPreviewSlidebox/actions.js +67 -0
  34. package/v2Components/TestAndPreviewSlidebox/constants.js +67 -0
  35. package/v2Components/TestAndPreviewSlidebox/index.js +771 -0
  36. package/v2Components/TestAndPreviewSlidebox/messages.js +147 -0
  37. package/v2Components/TestAndPreviewSlidebox/reducer.js +233 -0
  38. package/v2Components/TestAndPreviewSlidebox/sagas.js +258 -0
  39. package/v2Components/TestAndPreviewSlidebox/selectors.js +142 -0
  40. package/v2Components/TestAndPreviewSlidebox/tests/actions.test.js +80 -0
  41. package/v2Components/TestAndPreviewSlidebox/tests/reducer.test.js +367 -0
  42. package/v2Components/TestAndPreviewSlidebox/tests/saga.rtl.test.js +192 -0
  43. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +652 -0
  44. package/v2Components/TestAndPreviewSlidebox/tests/selector.test.js +182 -0
  45. package/v2Containers/CreativesContainer/SlideBoxContent.js +21 -9
  46. package/v2Containers/CreativesContainer/SlideBoxFooter.js +23 -2
  47. package/v2Containers/CreativesContainer/index.js +160 -195
  48. package/v2Containers/CreativesContainer/messages.js +4 -0
  49. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +21 -0
  50. package/v2Containers/Email/index.js +18 -6
  51. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +10 -0
  52. package/v2Containers/EmailWrapper/index.js +6 -0
  53. package/v2Containers/InApp/constants.js +0 -1
  54. package/v2Containers/InApp/index.js +13 -13
  55. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
  56. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
  57. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -0
  58. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
  59. package/v2Containers/MobilePush/Create/index.js +0 -1
  60. package/v2Containers/MobilePush/commonMethods.js +14 -7
  61. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +23 -5
  62. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
  63. package/v2Containers/TagList/index.js +10 -56
  64. package/v2Containers/Templates/_templates.scss +1 -101
  65. package/v2Containers/Templates/index.js +35 -147
  66. package/v2Containers/Templates/messages.js +0 -8
  67. package/v2Containers/Templates/sagas.js +0 -2
  68. package/v2Containers/WeChat/RichmediaTemplates/Create/index.js +1 -1
  69. package/v2Containers/Whatsapp/constants.js +0 -1
  70. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +35 -0
  71. package/utils/createPayload.js +0 -270
  72. package/utils/tests/createPayload.test.js +0 -761
  73. package/v2Components/CapMpushCTA/constants.js +0 -25
  74. package/v2Components/CapMpushCTA/index.js +0 -332
  75. package/v2Components/CapMpushCTA/index.scss +0 -95
  76. package/v2Components/CapMpushCTA/messages.js +0 -89
  77. package/v2Components/TemplatePreview/assets/images/Android _ With date and time.svg +0 -29
  78. package/v2Components/TemplatePreview/assets/images/android.svg +0 -9
  79. package/v2Components/TemplatePreview/assets/images/iOS _ With date and time.svg +0 -26
  80. package/v2Components/TemplatePreview/assets/images/ios.svg +0 -9
  81. package/v2Containers/Email/tests/index.test.js +0 -35
  82. package/v2Containers/MobilePushNew/actions.js +0 -116
  83. package/v2Containers/MobilePushNew/components/CtaButtons.js +0 -170
  84. package/v2Containers/MobilePushNew/components/MediaUploaders.js +0 -686
  85. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +0 -279
  86. package/v2Containers/MobilePushNew/components/index.js +0 -5
  87. package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +0 -779
  88. package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +0 -2114
  89. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +0 -343
  90. package/v2Containers/MobilePushNew/constants.js +0 -115
  91. package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +0 -1299
  92. package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +0 -1223
  93. package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +0 -246
  94. package/v2Containers/MobilePushNew/hooks/useUpload.js +0 -709
  95. package/v2Containers/MobilePushNew/index.js +0 -2170
  96. package/v2Containers/MobilePushNew/index.scss +0 -308
  97. package/v2Containers/MobilePushNew/messages.js +0 -226
  98. package/v2Containers/MobilePushNew/reducer.js +0 -160
  99. package/v2Containers/MobilePushNew/sagas.js +0 -198
  100. package/v2Containers/MobilePushNew/selectors.js +0 -55
  101. package/v2Containers/MobilePushNew/tests/reducer.test.js +0 -741
  102. package/v2Containers/MobilePushNew/tests/sagas.test.js +0 -863
  103. package/v2Containers/MobilePushNew/tests/selectors.test.js +0 -425
  104. package/v2Containers/MobilePushNew/tests/utils.test.js +0 -322
  105. package/v2Containers/MobilePushNew/utils.js +0 -33
@@ -0,0 +1,309 @@
1
+ @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
2
+
3
+ .customer-search-section {
4
+ margin-top: $CAP_SPACE_08;
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: $CAP_SPACE_04;
8
+ padding: 0;
9
+ position: relative;
10
+
11
+ .customer-search-label {
12
+ font-weight: bold;
13
+ margin-bottom: $CAP_SPACE_04;
14
+ font-size: $CAP_SPACE_16;
15
+ }
16
+
17
+ .search-container {
18
+ position: relative;
19
+ }
20
+
21
+ .search-dropdown-container {
22
+ position: absolute;
23
+ width: 100%;
24
+ z-index: 1000;
25
+ }
26
+
27
+ .search-result-card {
28
+ width: 100%;
29
+ margin: 0;
30
+ box-shadow: 0 $CAP_SPACE_04 $CAP_SPACE_12 rgba(0, 0, 0, 0.15);
31
+ border-radius: $CAP_SPACE_08;
32
+ border: 1px solid #d9d9d9;
33
+
34
+ .ant-card-body {
35
+ padding: $CAP_SPACE_08;
36
+ }
37
+ }
38
+
39
+ .link-result {
40
+ .ant-row.ant-row-flex {
41
+ padding: $CAP_SPACE_08 $CAP_SPACE_12;
42
+ border-radius: $CAP_SPACE_06;
43
+
44
+ &:hover {
45
+ background-color: #f0f0f0;
46
+ }
47
+ }
48
+ }
49
+
50
+ .customer-common-profile {
51
+ width: $CAP_SPACE_40;
52
+ height: $CAP_SPACE_40;
53
+ border-radius: 50%;
54
+ background-color: #E7D0FB;
55
+ color: $CAP_PURPLE;
56
+ display: flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ font-weight: bold;
60
+ font-size: $CAP_SPACE_16;
61
+ }
62
+
63
+ .search-text {
64
+ &.ant-typography {
65
+ font-weight: bold;
66
+ color: #262626;
67
+ margin-bottom: 0;
68
+ }
69
+ }
70
+
71
+
72
+ .identifiers-text {
73
+ margin-top: -0.6rem;
74
+ color: #8c8c8c;
75
+ .highlight-background-color {
76
+ background-color: transparent;
77
+ font-weight: bold;
78
+ }
79
+ }
80
+ .identifier-desc {
81
+ margin-top: 0.6rem;
82
+ }
83
+
84
+ .link-result-divider {
85
+ margin: 0 $CAP_SPACE_12;
86
+ }
87
+
88
+ .selected-customer-view {
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: space-between;
92
+ padding: $CAP_SPACE_04 $CAP_SPACE_12;
93
+ border: 1px solid #d9d9d9;
94
+ border-radius: $CAP_SPACE_06;
95
+ background-color: $CAP_WHITE;
96
+ height: $CAP_SPACE_40;
97
+ cursor: default;
98
+
99
+ .customer-common-profile {
100
+ width: $CAP_SPACE_24;
101
+ height: $CAP_SPACE_24;
102
+ font-size: $CAP_SPACE_12;
103
+ }
104
+
105
+ .search-text, .identifiers-text {
106
+ margin-bottom: 0;
107
+ }
108
+ .multiple-identifiers {
109
+ margin: 0.25rem 0;
110
+ }
111
+
112
+ .clear-icon {
113
+ cursor: pointer;
114
+ color: #8c8c8c;
115
+ }
116
+ }
117
+
118
+ .search-input-container {
119
+ position: relative;
120
+ .search-error {
121
+ margin-top: $CAP_SPACE_08;
122
+ }
123
+ }
124
+
125
+ .validation-card {
126
+ min-width: 100%;
127
+ max-width: 100%;
128
+ margin: 0;
129
+ box-shadow: 0 $CAP_SPACE_04 $CAP_SPACE_08 -2px rgba(9, 30, 66, 0.25),
130
+ 0 0 1px 0 rgba(9, 30, 66, 0.31);
131
+ border-top-left-radius: unset;
132
+ border-top-right-radius: unset;
133
+ border-top-color: transparent;
134
+ .ant-card-body {
135
+ padding: $CAP_SPACE_12 $CAP_SPACE_20;
136
+ }
137
+ }
138
+
139
+ .search-dropdown {
140
+ position: absolute;
141
+ top: 100%;
142
+ left: 0;
143
+ right: 0;
144
+ background: #fff;
145
+ border: 1px solid #d9d9d9;
146
+ border-top: none;
147
+ border-radius: 0 0 $CAP_SPACE_06 $CAP_SPACE_06;
148
+ box-shadow: 0 $CAP_SPACE_02 $CAP_SPACE_08 rgba(0, 0, 0, 0.1);
149
+ max-height: 200px;
150
+ overflow-y: auto;
151
+ z-index: 1050;
152
+
153
+ &.no-results {
154
+ .no-results-message {
155
+ display: flex;
156
+ align-items: center;
157
+ gap: $CAP_SPACE_08;
158
+ padding: $CAP_SPACE_16;
159
+ color: #8c8c8c;
160
+ font-size: 1rem;
161
+
162
+ .cap-icon {
163
+ color: #d9d9d9;
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ .customer-result-item {
170
+ display: flex;
171
+ align-items: center;
172
+ gap: $CAP_SPACE_12;
173
+ padding: $CAP_SPACE_12 $CAP_SPACE_16;
174
+ cursor: pointer;
175
+ border-bottom: 1px solid #f0f0f0;
176
+ transition: background-color 0.2s ease;
177
+
178
+ &:hover {
179
+ background-color: #f5f5f5;
180
+ }
181
+
182
+ &:last-child {
183
+ border-bottom: none;
184
+ }
185
+
186
+ .customer-avatar {
187
+ flex-shrink: 0;
188
+ }
189
+
190
+ .customer-details {
191
+ flex: 1;
192
+ min-width: 0;
193
+
194
+ .customer-name {
195
+ font-weight: 500;
196
+ font-size: 1rem;
197
+ color: #262626;
198
+ margin-bottom: 2px;
199
+ }
200
+
201
+ .customer-email {
202
+ font-size: $CAP_SPACE_12;
203
+ color: #8c8c8c;
204
+ margin-bottom: 2px;
205
+ }
206
+
207
+ .customer-phone {
208
+ font-size: $CAP_SPACE_12;
209
+ color: #8c8c8c;
210
+ }
211
+ }
212
+
213
+ .customer-id {
214
+ flex-shrink: 0;
215
+ font-size: $CAP_SPACE_12;
216
+ color: #8c8c8c;
217
+ font-weight: 500;
218
+ }
219
+ }
220
+
221
+ .selected-customer {
222
+ display: flex;
223
+ flex-direction: column;
224
+ gap: $CAP_SPACE_16;
225
+ padding: $CAP_SPACE_16;
226
+ background: #f8f9fa;
227
+ border: 1px solid #e8e8e8;
228
+ border-radius: $CAP_SPACE_06;
229
+
230
+ .selected-customer-info {
231
+ display: flex;
232
+ align-items: center;
233
+ gap: $CAP_SPACE_12;
234
+
235
+ .customer-details {
236
+ flex: 1;
237
+
238
+ .customer-name {
239
+ font-weight: 500;
240
+ font-size: 1rem;
241
+ color: #262626;
242
+ margin-bottom: $CAP_SPACE_04;
243
+ }
244
+
245
+ .customer-email {
246
+ font-size: $CAP_SPACE_12;
247
+ color: #8c8c8c;
248
+ margin-bottom: $CAP_SPACE_04;
249
+ }
250
+
251
+ .customer-id {
252
+ font-size: $CAP_SPACE_12;
253
+ color: #8c8c8c;
254
+ font-weight: 500;
255
+ }
256
+ }
257
+ }
258
+
259
+ .selected-customer-actions {
260
+ display: flex;
261
+ justify-content: flex-end;
262
+ align-items: center;
263
+ }
264
+
265
+ .tag-extraction-success {
266
+ .extraction-summary {
267
+ display: flex;
268
+ align-items: center;
269
+ gap: $CAP_SPACE_08;
270
+ margin-bottom: $CAP_SPACE_12;
271
+ font-size: 1rem;
272
+ font-weight: 500;
273
+ color: #52c41a;
274
+ }
275
+
276
+ .required-tags,
277
+ .optional-tags {
278
+ margin-bottom: $CAP_SPACE_12;
279
+
280
+ .tag-category {
281
+ display: flex;
282
+ align-items: center;
283
+ gap: $CAP_SPACE_08;
284
+ margin-bottom: $CAP_SPACE_08;
285
+ font-size: 13px;
286
+ font-weight: 500;
287
+ }
288
+
289
+ .tag-list {
290
+ display: flex;
291
+ flex-wrap: wrap;
292
+ gap: $CAP_SPACE_06;
293
+ }
294
+ }
295
+
296
+ .required-tags .tag-category {
297
+ color: #fa8c16;
298
+ }
299
+
300
+ .optional-tags .tag-category {
301
+ color: #52c41a;
302
+ }
303
+
304
+ .api-warnings {
305
+ margin-top: $CAP_SPACE_08;
306
+ }
307
+ }
308
+ }
309
+ }
@@ -0,0 +1,5 @@
1
+ export const FIRSTNAME = 'firstname';
2
+ export const LASTNAME = 'lastname';
3
+ export const INSTORE = 'instore';
4
+ export const NA = 'N/A';
5
+ export const MINIMUM_IDENTIFIER_LENGTH = 1;
@@ -0,0 +1,362 @@
1
+ /**
2
+ *
3
+ * CustomerSearchSection
4
+ *
5
+ */
6
+ import React, {
7
+ useState, useCallback, useRef, useEffect,
8
+ } from 'react';
9
+ import PropTypes from 'prop-types';
10
+ import { injectIntl } from 'react-intl';
11
+ import CapInput from '@capillarytech/cap-ui-library/CapInput';
12
+ import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
13
+ import CapAlert from '@capillarytech/cap-ui-library/CapAlert';
14
+ import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
15
+ import CapRow from '@capillarytech/cap-ui-library/CapRow';
16
+ import CapCard from '@capillarytech/cap-ui-library/CapCard';
17
+ import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
18
+ import CapLink from '@capillarytech/cap-ui-library/CapLink';
19
+ import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
20
+ import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
21
+ import { debounce } from 'lodash';
22
+ import './_customerSearch.scss';
23
+ import {
24
+ FIRSTNAME,
25
+ LASTNAME,
26
+ INSTORE,
27
+ NA,
28
+ MINIMUM_IDENTIFIER_LENGTH,
29
+ } from './constants';
30
+ import {
31
+ checkForData,
32
+ removeExtraIdentifiers,
33
+ identifiersHighlight,
34
+ getNamingIcon,
35
+ } from './utils';
36
+ import messages from './messages';
37
+
38
+
39
+ const CustomerSearchSection = ({
40
+ intl: { formatMessage },
41
+ onCustomerSelect,
42
+ onSearch,
43
+ onClearSearch,
44
+ onClearSelection,
45
+ customers,
46
+ isSearchingCustomer,
47
+ searchError,
48
+ selectedCustomer,
49
+ hasSearched,
50
+ disabled,
51
+ }) => {
52
+ const [showDropdown, setShowDropdown] = useState(false);
53
+ const [customerSearchValue, setCustomerSearchValue] = useState('');
54
+
55
+ const searchContainerRef = useRef(null);
56
+
57
+ const debouncedSearch = useCallback(
58
+ debounce((query) => {
59
+ onSearch(query);
60
+ }, 300),
61
+ [onSearch],
62
+ );
63
+
64
+ const handleSearchChange = useCallback(
65
+ (e) => {
66
+ const { value } = e.target;
67
+ setCustomerSearchValue(value);
68
+ if (value?.trim()) {
69
+ debouncedSearch(value.trim());
70
+ } else {
71
+ onClearSearch();
72
+ setShowDropdown(false);
73
+ }
74
+ },
75
+ [debouncedSearch, onClearSearch],
76
+ );
77
+
78
+ const handleCustomerSelectItem = useCallback(
79
+ (customer) => {
80
+ setShowDropdown(false);
81
+ onCustomerSelect(customer);
82
+ },
83
+ [onCustomerSelect],
84
+ );
85
+
86
+ const handleClickOutside = useCallback((event) => {
87
+ if (
88
+ searchContainerRef.current
89
+ && !searchContainerRef.current.contains(event.target)
90
+ ) {
91
+ setShowDropdown(false);
92
+ }
93
+ }, []);
94
+
95
+ useEffect(() => {
96
+ document.addEventListener('mousedown', handleClickOutside);
97
+ return () => {
98
+ document.removeEventListener('mousedown', handleClickOutside);
99
+ };
100
+ }, [handleClickOutside]);
101
+
102
+ useEffect(
103
+ () => () => {
104
+ debouncedSearch.cancel();
105
+ },
106
+ [debouncedSearch],
107
+ );
108
+
109
+ useEffect(() => {
110
+ if (customerSearchValue.trim() === '') {
111
+ setShowDropdown(false);
112
+ } else if (isSearchingCustomer || hasSearched) {
113
+ setShowDropdown(true);
114
+ }
115
+ }, [customerSearchValue, isSearchingCustomer, hasSearched]);
116
+
117
+ const getCompleteName = (data) => {
118
+ const { firstName = '', lastName = '' } = data?.[0] || {};
119
+ return `${firstName} ${lastName}`.trim() || NA;
120
+ };
121
+
122
+ const searchData = () => {
123
+ let finalSearchData;
124
+ if (!isSearchingCustomer && customers?.length > 0) {
125
+ finalSearchData = customers?.map((dataToFetch) => {
126
+ const checkForInstoreData = checkForData(dataToFetch?.profiles, INSTORE);
127
+ const identifiers = removeExtraIdentifiers(
128
+ dataToFetch?.matchedIdentifiers,
129
+ FIRSTNAME,
130
+ LASTNAME,
131
+ );
132
+ const fullName = getCompleteName( checkForInstoreData?.length ? checkForInstoreData : dataToFetch?.profiles);
133
+ return {
134
+ customerId: dataToFetch?.userId,
135
+ name: fullName,
136
+ identifiers: identifiersHighlight(customerSearchValue, identifiers),
137
+ };
138
+ });
139
+ }
140
+ return finalSearchData || [];
141
+ };
142
+
143
+ const getSearchData = searchData();
144
+
145
+ const showIdentifiers = (data) => {
146
+ if (!Array.isArray(data) || data.length === 0) return null;
147
+
148
+ const renderLabel = (item, index, isLast) => (
149
+ <CapLabel
150
+ type="label1"
151
+ key={`${item?.firstString || ''}-${item?.secondString || ''}-${item?.thirdString || ''}-${index}`}
152
+ className={`identifiers-text ${data.length > MINIMUM_IDENTIFIER_LENGTH ? 'multiple-identifiers' : ''}`}
153
+ >
154
+ {item?.firstString}
155
+ <span className="highlight-background-color">{item?.secondString}</span>
156
+ {item?.thirdString}
157
+ {!isLast && (
158
+ <>
159
+ ,
160
+ <span className="comma-separated-align"> </span>
161
+ </>
162
+ )}
163
+ </CapLabel>
164
+ );
165
+
166
+ if (data.length > MINIMUM_IDENTIFIER_LENGTH) {
167
+ return data.map((item, index) => renderLabel(item, index, index === data.length - 1));
168
+ }
169
+
170
+ return renderLabel(data[0], 0, true);
171
+ };
172
+
173
+ const onClear = () => {
174
+ setCustomerSearchValue('');
175
+ onClearSelection();
176
+ };
177
+
178
+ return (
179
+ <CapRow className="customer-search-section">
180
+ <CapRow className="search-container" ref={searchContainerRef}>
181
+ {selectedCustomer ? (
182
+ <SelectedCustomerView
183
+ customer={selectedCustomer}
184
+ onClear={onClear}
185
+ showIdentifiers={showIdentifiers}
186
+ />
187
+ ) : (
188
+ <SearchInput
189
+ value={customerSearchValue}
190
+ onChange={handleSearchChange}
191
+ isLoading={isSearchingCustomer}
192
+ error={searchError}
193
+ disabled={disabled}
194
+ placeholder={formatMessage(messages.searchPlaceholder)}
195
+ />
196
+ )}
197
+ {showDropdown && !selectedCustomer && (
198
+ <CapRow className="search-dropdown-container">
199
+ <CapRow type="flex" justify="center" align="middle">
200
+ {(getSearchData?.length === 0 && customerSearchValue != null && !isSearchingCustomer) && (
201
+ <CapCard className="validation-card">
202
+ <CapHeading type="h6">
203
+ {formatMessage(messages.noCustomersFound)}
204
+ </CapHeading>
205
+ </CapCard>
206
+ )}
207
+ {(isSearchingCustomer) && (
208
+ <CapCard className="validation-card">
209
+ <CapRow className="spin-card-align">
210
+ <CapSpin />
211
+ </CapRow>
212
+ </CapCard>
213
+ )}
214
+ </CapRow>
215
+ <CapRow type="flex" justify="center" align="middle">
216
+ {getSearchData?.length > 0 && (
217
+ <CapCard className="search-result-card scroll-bar">
218
+ {
219
+ <CapRow className="identifier-row">
220
+ {getSearchData?.map((d) => (
221
+ <>
222
+ <CapLink
223
+ key={d?.customerId}
224
+ className="search-results-height link-result"
225
+ title={(
226
+ <>
227
+ <CapRow type="flex" align="middle" gutter={16}>
228
+ <CapColumn data-testid="namingIcon">
229
+ <CapRow className="customer-common-profile">{getNamingIcon(d?.name)}</CapRow>
230
+ </CapColumn>
231
+ <CapColumn>
232
+ <CapRow type="flex" gutter={12}>
233
+ <CapColumn data-testid="searchResultName">
234
+ <CapHeading className="search-text" type="h4">
235
+ {d?.name}
236
+ </CapHeading>
237
+ </CapColumn>
238
+ </CapRow>
239
+ {(
240
+ <CapRow type="flex">
241
+ {showIdentifiers(d?.identifiers)}
242
+ </CapRow>
243
+ )}
244
+ </CapColumn>
245
+ </CapRow>
246
+ </>
247
+ )}
248
+ onClick={() => handleCustomerSelectItem(d)}
249
+ />
250
+ </>
251
+ ))}
252
+ </CapRow>
253
+ }
254
+ </CapCard>
255
+ )}
256
+ </CapRow>
257
+ </CapRow>
258
+ )}
259
+ </CapRow>
260
+ </CapRow>
261
+ );
262
+ };
263
+
264
+ // Search Input Component
265
+ const SearchInput = ({
266
+ value,
267
+ onChange,
268
+ isLoading,
269
+ error,
270
+ disabled,
271
+ placeholder,
272
+ }) => (
273
+ <CapRow className="search-input-container">
274
+ <CapInput
275
+ value={value}
276
+ onChange={onChange}
277
+ placeholder={placeholder}
278
+ disabled={disabled || isLoading}
279
+ status={error ? 'error' : undefined}
280
+ allowClear
281
+ autoComplete="off"
282
+ />
283
+ {error && (
284
+ <CapRow className="search-error">
285
+ <CapAlert
286
+ message={error}
287
+ type="error"
288
+ size="small"
289
+ showIcon
290
+ />
291
+ </CapRow>
292
+ )}
293
+ </CapRow>
294
+ );
295
+
296
+ const SelectedCustomerView = ({ customer, onClear, showIdentifiers }) => (
297
+ <CapRow className="selected-customer-view">
298
+ <CapRow type="flex" align="middle" gutter={8}>
299
+ <CapColumn>
300
+ <CapRow className="customer-common-profile">{getNamingIcon(customer?.name)}</CapRow>
301
+ </CapColumn>
302
+ <CapColumn>
303
+ <CapHeading className="search-text" type="h4">
304
+ {customer.name}
305
+ </CapHeading>
306
+ </CapColumn>
307
+ <CapColumn>
308
+ <CapLabel type="label1" className="identifier-desc">
309
+ {showIdentifiers(customer?.identifiers)}
310
+ </CapLabel>
311
+ </CapColumn>
312
+ </CapRow>
313
+ <CapIcon size="s" type="close" className="clear-icon" onClick={onClear} />
314
+ </CapRow>
315
+ );
316
+
317
+ SelectedCustomerView.propTypes = {
318
+ customer: PropTypes.object.isRequired,
319
+ onClear: PropTypes.func.isRequired,
320
+ showIdentifiers: PropTypes.func.isRequired,
321
+ };
322
+
323
+ SearchInput.propTypes = {
324
+ value: PropTypes.string,
325
+ onChange: PropTypes.func,
326
+ isLoading: PropTypes.bool,
327
+ error: PropTypes.string,
328
+ disabled: PropTypes.bool,
329
+ placeholder: PropTypes.string.isRequired,
330
+ };
331
+ SearchInput.defaultProps = {
332
+ value: '',
333
+ onChange: () => {},
334
+ isLoading: false,
335
+ error: null,
336
+ disabled: false,
337
+ };
338
+
339
+ CustomerSearchSection.propTypes = {
340
+ onCustomerSelect: PropTypes.func.isRequired,
341
+ onSearch: PropTypes.func.isRequired,
342
+ onClearSearch: PropTypes.func.isRequired,
343
+ onClearSelection: PropTypes.func.isRequired,
344
+ customers: PropTypes.array,
345
+ isSearchingCustomer: PropTypes.bool,
346
+ searchError: PropTypes.string,
347
+ selectedCustomer: PropTypes.object,
348
+ hasSearched: PropTypes.bool,
349
+ disabled: PropTypes.bool,
350
+ intl: PropTypes.object.isRequired,
351
+ };
352
+
353
+ CustomerSearchSection.defaultProps = {
354
+ customers: [],
355
+ isSearchingCustomer: false,
356
+ searchError: null,
357
+ selectedCustomer: null,
358
+ hasSearched: false,
359
+ disabled: false,
360
+ };
361
+
362
+ export default injectIntl(CustomerSearchSection);
@@ -0,0 +1,20 @@
1
+ /*
2
+ * CustomerSearchSection Messages
3
+ *
4
+ * This contains all the text for the CustomerSearchSection component.
5
+ */
6
+
7
+ import { defineMessages } from 'react-intl';
8
+
9
+ export const scope = 'app.v2Components.CustomerSearchSection';
10
+
11
+ export default defineMessages({
12
+ searchPlaceholder: {
13
+ id: `${scope}.searchPlaceholder`,
14
+ defaultMessage: 'Search customers by their identifiers',
15
+ },
16
+ noCustomersFound: {
17
+ id: `${scope}.noCustomersFound`,
18
+ defaultMessage: 'No customers found',
19
+ },
20
+ });