@capillarytech/creatives-library 8.0.158 → 8.0.159-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/config/app.js +1 -1
- package/package.json +1 -1
- package/v2Components/CustomerSearchSection/index.js +83 -79
- package/v2Components/TestAndPreviewSlidebox/PreviewSection.js +1 -1
- package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +2 -1
- package/v2Components/TestAndPreviewSlidebox/index.js +37 -3
- package/v2Components/TestAndPreviewSlidebox/tests/PreviewSection.test.js +1 -1
- package/v2Containers/Email/index.js +60 -25
- package/assets/loading_img.gif +0 -0
- package/utils/whatsappMediaUtils.js +0 -44
- package/v2Containers/Email/tests/index.test.js +0 -35
package/config/app.js
CHANGED
|
@@ -20,7 +20,7 @@ const config = {
|
|
|
20
20
|
accountConfig: (strs, accountId) => `${window.location.origin}/org/config/AccountAdd?q=a&channelId=2&accountId=${accountId}&edit=1`,
|
|
21
21
|
},
|
|
22
22
|
development: {
|
|
23
|
-
api_endpoint: '
|
|
23
|
+
api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/creatives',
|
|
24
24
|
campaigns_api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/campaigns',
|
|
25
25
|
campaigns_api_org_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/org/campaign',
|
|
26
26
|
auth_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/auth',
|
package/package.json
CHANGED
|
@@ -69,7 +69,9 @@ const CustomerSearchSection = ({
|
|
|
69
69
|
if (value?.trim()) {
|
|
70
70
|
debouncedSearch(value.trim());
|
|
71
71
|
} else {
|
|
72
|
-
onClearSearch
|
|
72
|
+
if (onClearSearch && typeof onClearSearch === 'function') {
|
|
73
|
+
onClearSearch();
|
|
74
|
+
}
|
|
73
75
|
setShowDropdown(false);
|
|
74
76
|
}
|
|
75
77
|
},
|
|
@@ -182,86 +184,88 @@ const CustomerSearchSection = ({
|
|
|
182
184
|
|
|
183
185
|
return (
|
|
184
186
|
<CapRow className="customer-search-section">
|
|
185
|
-
<
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
<CapRow
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
<
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
<
|
|
215
|
-
<
|
|
216
|
-
|
|
217
|
-
</CapCard>
|
|
218
|
-
)}
|
|
219
|
-
</CapRow>
|
|
220
|
-
<CapRow type="flex" justify="center" align="middle">
|
|
221
|
-
{processedSearchData?.length > 0 && (
|
|
222
|
-
<CapCard className="search-result-card scroll-bar">
|
|
223
|
-
{
|
|
224
|
-
<CapRow className="identifier-row">
|
|
225
|
-
{processedSearchData?.map((d) => (
|
|
226
|
-
<>
|
|
227
|
-
<CapLink
|
|
228
|
-
key={d?.customerId}
|
|
229
|
-
className="search-results-height link-result"
|
|
230
|
-
title={(
|
|
231
|
-
<>
|
|
232
|
-
<CapRow type="flex" align="middle" gutter={16}>
|
|
233
|
-
<CapColumn data-testid="namingIcon">
|
|
234
|
-
<CapRow className="customer-common-profile">{getNamingIcon(d?.name)}</CapRow>
|
|
235
|
-
</CapColumn>
|
|
236
|
-
<CapColumn>
|
|
237
|
-
<CapRow type="flex" gutter={12}>
|
|
238
|
-
<CapColumn data-testid="searchResultName">
|
|
239
|
-
<CapHeading className="search-text" type="h4">
|
|
240
|
-
{d?.name}
|
|
241
|
-
</CapHeading>
|
|
242
|
-
</CapColumn>
|
|
243
|
-
</CapRow>
|
|
244
|
-
{(
|
|
245
|
-
<CapRow type="flex">
|
|
246
|
-
{showIdentifiers(d?.identifiers)}
|
|
247
|
-
</CapRow>
|
|
248
|
-
)}
|
|
249
|
-
</CapColumn>
|
|
250
|
-
</CapRow>
|
|
251
|
-
</>
|
|
252
|
-
)}
|
|
253
|
-
onClick={() => handleCustomerSelectItem(d)}
|
|
254
|
-
/>
|
|
255
|
-
</>
|
|
256
|
-
))}
|
|
187
|
+
<div ref={searchContainerRef}>
|
|
188
|
+
<CapRow className="search-container">
|
|
189
|
+
{selectedCustomer ? (
|
|
190
|
+
<SelectedCustomerView
|
|
191
|
+
customer={selectedCustomer}
|
|
192
|
+
onClear={onClear}
|
|
193
|
+
showIdentifiers={showIdentifiers}
|
|
194
|
+
/>
|
|
195
|
+
) : (
|
|
196
|
+
<SearchInput
|
|
197
|
+
value={customerSearchValue}
|
|
198
|
+
onChange={handleSearchChange}
|
|
199
|
+
isLoading={isSearchingCustomer}
|
|
200
|
+
error={searchError}
|
|
201
|
+
disabled={disabled}
|
|
202
|
+
placeholder={formatMessage(messages.searchPlaceholder)}
|
|
203
|
+
/>
|
|
204
|
+
)}
|
|
205
|
+
{showDropdown && !selectedCustomer && (
|
|
206
|
+
<CapRow className="search-dropdown-container">
|
|
207
|
+
<CapRow type="flex" justify="center" align="middle">
|
|
208
|
+
{(processedSearchData?.length === 0 && customerSearchValue != null && !isSearchingCustomer) && (
|
|
209
|
+
<CapCard className="validation-card">
|
|
210
|
+
<CapHeading type="h6">
|
|
211
|
+
{formatMessage(messages.noCustomersFound)}
|
|
212
|
+
</CapHeading>
|
|
213
|
+
</CapCard>
|
|
214
|
+
)}
|
|
215
|
+
{(isSearchingCustomer) && (
|
|
216
|
+
<CapCard className="validation-card">
|
|
217
|
+
<CapRow className="spin-card-align">
|
|
218
|
+
<CapSpin />
|
|
257
219
|
</CapRow>
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
220
|
+
</CapCard>
|
|
221
|
+
)}
|
|
222
|
+
</CapRow>
|
|
223
|
+
<CapRow type="flex" justify="center" align="middle">
|
|
224
|
+
{processedSearchData?.length > 0 && (
|
|
225
|
+
<CapCard className="search-result-card scroll-bar">
|
|
226
|
+
{
|
|
227
|
+
<CapRow className="identifier-row">
|
|
228
|
+
{processedSearchData?.map((d) => (
|
|
229
|
+
<>
|
|
230
|
+
<CapLink
|
|
231
|
+
key={d?.customerId}
|
|
232
|
+
className="search-results-height link-result"
|
|
233
|
+
title={(
|
|
234
|
+
<>
|
|
235
|
+
<CapRow type="flex" align="middle" gutter={16}>
|
|
236
|
+
<CapColumn data-testid="namingIcon">
|
|
237
|
+
<CapRow className="customer-common-profile">{getNamingIcon(d?.name)}</CapRow>
|
|
238
|
+
</CapColumn>
|
|
239
|
+
<CapColumn>
|
|
240
|
+
<CapRow type="flex" gutter={12}>
|
|
241
|
+
<CapColumn data-testid="searchResultName">
|
|
242
|
+
<CapHeading className="search-text" type="h4">
|
|
243
|
+
{d?.name}
|
|
244
|
+
</CapHeading>
|
|
245
|
+
</CapColumn>
|
|
246
|
+
</CapRow>
|
|
247
|
+
{(
|
|
248
|
+
<CapRow type="flex">
|
|
249
|
+
{showIdentifiers(d?.identifiers)}
|
|
250
|
+
</CapRow>
|
|
251
|
+
)}
|
|
252
|
+
</CapColumn>
|
|
253
|
+
</CapRow>
|
|
254
|
+
</>
|
|
255
|
+
)}
|
|
256
|
+
onClick={() => handleCustomerSelectItem(d)}
|
|
257
|
+
/>
|
|
258
|
+
</>
|
|
259
|
+
))}
|
|
260
|
+
</CapRow>
|
|
261
|
+
}
|
|
262
|
+
</CapCard>
|
|
263
|
+
)}
|
|
264
|
+
</CapRow>
|
|
261
265
|
</CapRow>
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
</
|
|
266
|
+
)}
|
|
267
|
+
</CapRow>
|
|
268
|
+
</div>
|
|
265
269
|
</CapRow>
|
|
266
270
|
);
|
|
267
271
|
};
|
|
@@ -15,7 +15,7 @@ const PreviewSection = ({
|
|
|
15
15
|
formatMessage,
|
|
16
16
|
PreviewChrome,
|
|
17
17
|
}) => (
|
|
18
|
-
<CapRow className="preview-section panel-section">
|
|
18
|
+
<CapRow className="test-and-preview-section panel-section">
|
|
19
19
|
<PreviewChrome
|
|
20
20
|
device={previewDevice}
|
|
21
21
|
onDeviceChange={setPreviewDevice}
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
.test-preview-container {
|
|
31
|
+
margin-left: 2%;
|
|
31
32
|
height: 100%;
|
|
32
33
|
display: flex;
|
|
33
34
|
flex-direction: column;
|
|
@@ -329,7 +330,7 @@
|
|
|
329
330
|
}
|
|
330
331
|
}
|
|
331
332
|
|
|
332
|
-
.preview-section {
|
|
333
|
+
.test-and-preview-section {
|
|
333
334
|
.section-title {
|
|
334
335
|
margin-bottom: $CAP_SPACE_16;
|
|
335
336
|
color: #333;
|
|
@@ -93,10 +93,15 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
93
93
|
), [requiredTags, customValues]);
|
|
94
94
|
|
|
95
95
|
useEffect(() => {
|
|
96
|
-
if
|
|
96
|
+
// Only save BEE content if we're actually using BEE editor
|
|
97
|
+
const currentTabData = formData[formData.currentTab - 1];
|
|
98
|
+
const activeTab = currentTabData?.activeTab;
|
|
99
|
+
const isDragDrop = currentTabData?.[activeTab]?.is_drag_drop;
|
|
100
|
+
|
|
101
|
+
if (show && beeInstance && isDragDrop) {
|
|
97
102
|
beeInstance.save();
|
|
98
103
|
}
|
|
99
|
-
}, [show, beeInstance]);
|
|
104
|
+
}, [show, beeInstance, formData]);
|
|
100
105
|
|
|
101
106
|
useEffect(() => {
|
|
102
107
|
if (show) {
|
|
@@ -281,7 +286,35 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
281
286
|
};
|
|
282
287
|
|
|
283
288
|
// Handle update preview
|
|
284
|
-
const handleUpdatePreview = () => {
|
|
289
|
+
const handleUpdatePreview = async () => {
|
|
290
|
+
// For BEE editor, ensure content is saved first
|
|
291
|
+
const currentTabData = formData[formData.currentTab - 1];
|
|
292
|
+
const activeTab = currentTabData?.activeTab;
|
|
293
|
+
|
|
294
|
+
// Get latest content from BEE editor if needed
|
|
295
|
+
if (beeInstance && currentTabData?.[activeTab]?.is_drag_drop) {
|
|
296
|
+
// Trigger save to ensure latest content
|
|
297
|
+
beeInstance.save();
|
|
298
|
+
|
|
299
|
+
// Wait a bit for save to complete
|
|
300
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
301
|
+
|
|
302
|
+
// Get latest content from BEE editor
|
|
303
|
+
beeInstance.getContent((jsonFile, htmlFile) => {
|
|
304
|
+
const payload = {
|
|
305
|
+
channel: EMAIL,
|
|
306
|
+
messageTitle: formData['template-subject'],
|
|
307
|
+
messageBody: htmlFile || content,
|
|
308
|
+
resolvedTags: customValues,
|
|
309
|
+
userId: selectedCustomer?.customerId,
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
actions.updatePreviewRequested(payload);
|
|
313
|
+
});
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Use content from formData for non-BEE editor
|
|
285
318
|
const payload = {
|
|
286
319
|
channel: EMAIL,
|
|
287
320
|
messageTitle: formData['template-subject'],
|
|
@@ -289,6 +322,7 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
289
322
|
resolvedTags: customValues,
|
|
290
323
|
userId: selectedCustomer?.customerId,
|
|
291
324
|
};
|
|
325
|
+
|
|
292
326
|
actions.updatePreviewRequested(payload);
|
|
293
327
|
};
|
|
294
328
|
|
|
@@ -91,7 +91,7 @@ describe('PreviewSection', () => {
|
|
|
91
91
|
</TestWrapper>
|
|
92
92
|
);
|
|
93
93
|
|
|
94
|
-
expect(container.querySelector('.preview-section')).toBeTruthy();
|
|
94
|
+
expect(container.querySelector('.test-and-preview-section')).toBeTruthy();
|
|
95
95
|
expect(container.querySelector('.panel-section')).toBeTruthy();
|
|
96
96
|
});
|
|
97
97
|
});
|
|
@@ -592,27 +592,24 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
592
592
|
onChange = (evt) => {
|
|
593
593
|
const {isFullMode, showTemplateName} = this.props;
|
|
594
594
|
const formData = _.cloneDeep(this.state.formData);
|
|
595
|
+
const currentTabData = formData[this.state.currentTab - 1];
|
|
596
|
+
const activeTab = currentTabData?.activeTab;
|
|
595
597
|
|
|
596
|
-
//
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
// //temp.name = id;
|
|
605
|
-
//
|
|
606
|
-
// }
|
|
607
|
-
// });
|
|
608
|
-
//}
|
|
609
|
-
if (!formData[this.state.currentTab - 1][formData[`${this.state.currentTab - 1}`].activeTab].is_drag_drop) {
|
|
610
|
-
formData[`${this.state.currentTab - 1}`][formData[`${this.state.currentTab - 1}`].activeTab][`template-content`] = _.cloneDeep(evt.editor.getData());
|
|
611
|
-
if (formData[`${this.state.currentTab - 1}`].tabKey === formData.base.tabKey) {
|
|
612
|
-
formData.base[formData[`${this.state.currentTab - 1}`].activeTab][`template-content`] = _.cloneDeep(evt.editor.getData());
|
|
598
|
+
// Only handle CKEditor changes
|
|
599
|
+
if (currentTabData && activeTab && !currentTabData[activeTab]?.is_drag_drop) {
|
|
600
|
+
const newContent = evt.editor.getData();
|
|
601
|
+
|
|
602
|
+
// Update formData with new content
|
|
603
|
+
currentTabData[activeTab]['template-content'] = _.cloneDeep(newContent);
|
|
604
|
+
if (currentTabData.tabKey === formData.base.tabKey) {
|
|
605
|
+
formData.base[activeTab]['template-content'] = _.cloneDeep(newContent);
|
|
613
606
|
}
|
|
614
607
|
|
|
615
|
-
|
|
608
|
+
// Update state with new content
|
|
609
|
+
this.setState({
|
|
610
|
+
formData,
|
|
611
|
+
content: newContent // Keep latest content in state
|
|
612
|
+
}, () => {
|
|
616
613
|
if (isFullMode && showTemplateName) {
|
|
617
614
|
showTemplateName({formData, onFormDataChange: this.onFormDataChange});
|
|
618
615
|
}
|
|
@@ -827,8 +824,11 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
827
824
|
const currentTabData = formData[currentTab - 1];
|
|
828
825
|
const activeTab = currentTabData?.activeTab;
|
|
829
826
|
|
|
827
|
+
// Get content from formData
|
|
830
828
|
if (currentTabData && activeTab && currentTabData[activeTab]) {
|
|
831
|
-
|
|
829
|
+
const isDragDrop = currentTabData[activeTab].is_drag_drop;
|
|
830
|
+
const templateContent = currentTabData[activeTab]['template-content'];
|
|
831
|
+
return templateContent || '';
|
|
832
832
|
}
|
|
833
833
|
|
|
834
834
|
return '';
|
|
@@ -2471,9 +2471,39 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
2471
2471
|
const formData = _.cloneDeep(this.state.formData);
|
|
2472
2472
|
const activeLangTab = formData[`${this.state.currentTab - 1}`].activeTab;
|
|
2473
2473
|
const langIndex = formData[`${this.state.currentTab - 1}`].selectedLanguages.indexOf(activeLangTab);
|
|
2474
|
+
|
|
2475
|
+
// Store current content before switching
|
|
2476
|
+
const currentContent = formData[`${this.state.currentTab - 1}`][activeLangTab]['template-content'];
|
|
2477
|
+
|
|
2478
|
+
// Update formData to mark as not drag-drop
|
|
2479
|
+
formData[`${this.state.currentTab - 1}`][activeLangTab].is_drag_drop = false;
|
|
2480
|
+
if (formData[`${this.state.currentTab - 1}`].base) {
|
|
2481
|
+
formData.base[activeLangTab].is_drag_drop = false;
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
this.setState({
|
|
2485
|
+
mode: "switchEditor",
|
|
2486
|
+
formData
|
|
2487
|
+
}, () => {
|
|
2488
|
+
// No need to call handleEdmSave as we're switching to CKEditor
|
|
2489
|
+
let schema = _.cloneDeep(this.state.schema);
|
|
2490
|
+
_.forEach(schema.containers, (container, index) => {
|
|
2491
|
+
if (parseInt(index, 10) === (this.state.currentTab - 1)) {
|
|
2492
|
+
const temp = container;
|
|
2493
|
+
const langTab = formData[`${this.state.currentTab - 1}`].selectedLanguages.indexOf(activeLangTab);
|
|
2494
|
+
|
|
2495
|
+
temp.panes[langTab].sections[0].inputFields[0].cols[0].colStyle = {display: ""};
|
|
2496
|
+
temp.panes[langTab].sections[0].inputFields[0].cols[1].colStyle = {display: "none"};
|
|
2497
|
+
temp.tabBarExtraContent.sections[0].inputFields[0].cols[4].colStyle.display = "none";
|
|
2498
|
+
}
|
|
2499
|
+
});
|
|
2500
|
+
schema = this.showInsertImageButton(schema);
|
|
2474
2501
|
|
|
2475
|
-
|
|
2476
|
-
|
|
2502
|
+
this.setState({
|
|
2503
|
+
schema,
|
|
2504
|
+
showConfirmationModal: false,
|
|
2505
|
+
isSchemaChanged: true
|
|
2506
|
+
});
|
|
2477
2507
|
});
|
|
2478
2508
|
}
|
|
2479
2509
|
|
|
@@ -2668,22 +2698,26 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
2668
2698
|
this.beeInstance = instance;
|
|
2669
2699
|
}
|
|
2670
2700
|
saveBeeData = (json, html) => {
|
|
2701
|
+
// Update state with new content
|
|
2671
2702
|
this.setState((prevState) => {
|
|
2672
2703
|
const { currentTab, formData } = _.cloneDeep(prevState);
|
|
2673
2704
|
const activeTab = formData[currentTab - 1].activeTab;
|
|
2705
|
+
|
|
2706
|
+
// Update content in both formData and base
|
|
2674
2707
|
formData[currentTab - 1][activeTab]['template-content'] = html;
|
|
2675
2708
|
formData[currentTab - 1][activeTab]['json-content'] = json;
|
|
2676
|
-
|
|
2677
2709
|
formData.base[activeTab]['template-content'] = html;
|
|
2678
2710
|
formData.base[activeTab]['json-content'] = json;
|
|
2679
2711
|
|
|
2680
2712
|
return {
|
|
2681
2713
|
...prevState,
|
|
2682
2714
|
formData,
|
|
2715
|
+
content: html // Keep latest content in state
|
|
2683
2716
|
};
|
|
2684
2717
|
}, () => {
|
|
2685
|
-
|
|
2686
|
-
|
|
2718
|
+
// Always trigger validation to ensure content is saved
|
|
2719
|
+
this.setState({
|
|
2720
|
+
startValidation: true
|
|
2687
2721
|
});
|
|
2688
2722
|
});
|
|
2689
2723
|
}
|
|
@@ -2697,6 +2731,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
2697
2731
|
const imagePreviewHeader = (<h3>{this.props.intl.formatMessage(messages.h3imageSelection)}</h3>);
|
|
2698
2732
|
const imagePreviewContent = this.getImagePreviewContent();
|
|
2699
2733
|
const { selectedOfferDetails, getDefaultTags, Email: { CmsSettings = {} } = {}, moduleType = '', showTestAndPreviewSlidebox, handleTestAndPreview, handleCloseTestAndPreview } = this.props;
|
|
2734
|
+
const testAndPreviewContent = this.getTemplateContent();
|
|
2700
2735
|
if (!this.props.currentOrgDetails || !this.props.currentOrgDetails.basic_details) {
|
|
2701
2736
|
return (<div>Loading...</div>);
|
|
2702
2737
|
}
|
|
@@ -2796,7 +2831,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
2796
2831
|
onClose={handleCloseTestAndPreview}
|
|
2797
2832
|
formData={this.state.formData}
|
|
2798
2833
|
beeInstance={this.beeInstance}
|
|
2799
|
-
content={
|
|
2834
|
+
content={testAndPreviewContent}
|
|
2800
2835
|
currentChannel={EMAIL}
|
|
2801
2836
|
/>
|
|
2802
2837
|
</div>
|
package/assets/loading_img.gif
DELETED
|
Binary file
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for handling WhatsApp media URL transformations
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Extracts creative ID from media URL pattern
|
|
7
|
-
* @param {string} mediaUrl - URL with pattern {{media_content(<creativeId>_<mediaDetailId>)}}
|
|
8
|
-
* @returns {string|null} - Extracted creative ID or null if not found
|
|
9
|
-
*/
|
|
10
|
-
export const extractCreativeIdFromMediaUrl = (mediaUrl) => {
|
|
11
|
-
if (!mediaUrl || typeof mediaUrl !== 'string') {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Extract creativeId from pattern: {{media_content(<creativeId>_<mediaDetailId>)}}
|
|
16
|
-
const match = mediaUrl.match(/\{\{media_content\(([^_]+)_[^)]+\)\}\}/);
|
|
17
|
-
return match ? match[1] : null;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Creates URL mapping from API response format to template pattern format
|
|
22
|
-
* @param {Object} mediaDetails - API response with format {url: "mediaDetailId_creativeId"}
|
|
23
|
-
* @returns {Object} - Mapping object {creativeId_mediaDetailId: url}
|
|
24
|
-
*/
|
|
25
|
-
export const createMediaUrlMapping = (mediaDetails) => {
|
|
26
|
-
const mediaUrlMap = {};
|
|
27
|
-
|
|
28
|
-
if (!mediaDetails || typeof mediaDetails !== 'object') {
|
|
29
|
-
return mediaUrlMap;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
Object.keys(mediaDetails).forEach(url => {
|
|
33
|
-
const value = mediaDetails[url];
|
|
34
|
-
// API response format: "mediaDetailId_creativeId"
|
|
35
|
-
// We need to reverse it to match our pattern: "creativeId_mediaDetailId"
|
|
36
|
-
if (typeof value === 'string' && value.includes('_')) {
|
|
37
|
-
const [mediaDetailId, creativeId] = value.split('_');
|
|
38
|
-
const templatePattern = `${mediaDetailId}_${creativeId}`;
|
|
39
|
-
mediaUrlMap[templatePattern] = url;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
return mediaUrlMap;
|
|
44
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { injectIntl } from 'react-intl';
|
|
3
|
-
import '@testing-library/jest-dom';
|
|
4
|
-
import {
|
|
5
|
-
render,
|
|
6
|
-
} from '../../../utils/test-utils';
|
|
7
|
-
import { EMAILPreviewMockData } from '../mockdata/mockdata';
|
|
8
|
-
import { Email } from "../index";
|
|
9
|
-
|
|
10
|
-
const initializeComponent = () => {
|
|
11
|
-
const Component = injectIntl(Email);
|
|
12
|
-
const resetUploadData = jest.fn();
|
|
13
|
-
const clearStoreValues = jest.fn();
|
|
14
|
-
const clearCRUDResponse = jest.fn();
|
|
15
|
-
const fetchSchemaForEntity = jest.fn();
|
|
16
|
-
|
|
17
|
-
return render( <Component
|
|
18
|
-
{...EMAILPreviewMockData}
|
|
19
|
-
templatesActions={{resetUploadData}}
|
|
20
|
-
actions={{
|
|
21
|
-
clearStoreValues,
|
|
22
|
-
clearCRUDResponse,
|
|
23
|
-
}}
|
|
24
|
-
globalActions={{
|
|
25
|
-
fetchSchemaForEntity,
|
|
26
|
-
}}
|
|
27
|
-
/>);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
describe('renders a message', () => {
|
|
31
|
-
it("Test if Email component renders", () => {
|
|
32
|
-
initializeComponent();
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|