@capillarytech/creatives-library 8.0.339 → 8.0.340-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.
Files changed (52) hide show
  1. package/.npmrc copy +2 -0
  2. package/package.json +1 -1
  3. package/utils/tests/tagValidations.test.js +20 -0
  4. package/v2Components/CapTagList/index.js +28 -23
  5. package/v2Components/CapTagList/style.scss +29 -0
  6. package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
  7. package/v2Components/CapTagListWithInput/index.js +4 -0
  8. package/v2Components/CapWhatsappCTA/index.js +2 -0
  9. package/v2Components/FormBuilder/index.js +7 -0
  10. package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
  11. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
  12. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
  13. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
  14. package/v2Containers/BeeEditor/index.js +3 -0
  15. package/v2Containers/CreativesContainer/SlideBoxContent.js +28 -1
  16. package/v2Containers/CreativesContainer/index.js +3 -0
  17. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +47 -0
  18. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +5 -0
  19. package/v2Containers/Email/index.js +1 -0
  20. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +6 -1
  21. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
  22. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
  23. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
  24. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -0
  25. package/v2Containers/EmailWrapper/index.js +4 -0
  26. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
  27. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
  28. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +1 -0
  29. package/v2Containers/MobilePush/Create/index.js +2 -0
  30. package/v2Containers/MobilePush/Edit/index.js +2 -0
  31. package/v2Containers/MobilepushWrapper/index.js +3 -1
  32. package/v2Containers/Rcs/index.js +1 -0
  33. package/v2Containers/Sms/Create/index.js +2 -0
  34. package/v2Containers/Sms/Edit/index.js +2 -0
  35. package/v2Containers/SmsTrai/Edit/index.js +2 -0
  36. package/v2Containers/SmsWrapper/index.js +2 -0
  37. package/v2Containers/TagList/index.js +62 -5
  38. package/v2Containers/TagList/messages.js +4 -0
  39. package/v2Containers/TagList/tests/TagList.test.js +124 -20
  40. package/v2Containers/TagList/tests/mockdata.js +17 -0
  41. package/v2Containers/Viber/constants.js +8 -0
  42. package/v2Containers/Viber/index.js +8 -0
  43. package/v2Containers/Viber/reducer.js +44 -21
  44. package/v2Containers/Viber/sagas.js +62 -21
  45. package/v2Containers/Viber/tests/index.test.js +80 -0
  46. package/v2Containers/Viber/tests/reducer.test.js +297 -0
  47. package/v2Containers/Viber/tests/saga.test.js +365 -40
  48. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
  49. package/v2Containers/WebPush/Create/index.js +9 -1
  50. package/v2Containers/Whatsapp/index.js +5 -0
  51. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +20 -0
  52. package/v2Containers/Zalo/index.js +2 -0
@@ -149,3 +149,20 @@ export const eventContextTags = [
149
149
  "isDynamicFact": false
150
150
  }
151
151
  ];
152
+
153
+ export const waitEventContextTags = {
154
+ block1: {
155
+ eventName: 'Order Placed',
156
+ blockName: 'Wait Block',
157
+ tags: [
158
+ {
159
+ tagName: 'waitEvent.orderId',
160
+ label: 'Order ID',
161
+ profileId: 'ORDER_PROFILE',
162
+ profileName: 'Order Profile',
163
+ blockName: 'Wait Block',
164
+ eventName: 'Order Placed',
165
+ },
166
+ ],
167
+ },
168
+ };
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import CapHeading from "@capillarytech/cap-ui-library/CapHeading";
4
4
  import CapLabel from "@capillarytech/cap-ui-library/CapLabel";
5
5
  import messages from "./messages";
6
+ import { createAsyncAssetUploadConstants } from '../../utils/asyncAssetUpload';
6
7
 
7
8
  export const DEFAULT_ACTION = 'app/v2Containers/Viber/DEFAULT_ACTION';
8
9
  export const ALLOWED_EXTENSIONS_REGEX = (/\.(jpe?g|png)$/i);
@@ -16,6 +17,13 @@ export const UPLOAD_VIBER_ASSET_REQUEST = 'app/v2Containers/Viber/UPLOAD_ASSET_R
16
17
  export const UPLOAD_VIBER_ASSET_SUCCESS = 'app/v2Containers/Viber/UPLOAD_ASSET_SUCCESS';
17
18
  export const UPLOAD_VIBER_ASSET_FAILURE = 'app/v2Containers/Viber/UPLOAD_ASSET_FAILURE';
18
19
 
20
+ const viberAsyncPrefix = 'app/v2Containers/Viber';
21
+ const asyncUploadConstants = createAsyncAssetUploadConstants('VIBER', viberAsyncPrefix);
22
+ export const UPLOAD_VIBER_ASSET_PROCESSING = asyncUploadConstants.UPLOAD_VIBER_ASSET_PROCESSING;
23
+ export const UPLOAD_VIBER_ASSET_COMPLETED = asyncUploadConstants.UPLOAD_VIBER_ASSET_COMPLETED;
24
+ export const UPLOAD_VIBER_ASSET_FAILED = asyncUploadConstants.UPLOAD_VIBER_ASSET_FAILED;
25
+ export const UPLOAD_VIBER_ASSET_TIMEOUT = asyncUploadConstants.UPLOAD_VIBER_ASSET_TIMEOUT;
26
+
19
27
 
20
28
  export const CREATE_VIBER_TEMPLATE_REQUEST = 'app/v2Containers/Viber/CREATE_VIBER_TEMPLATE_REQUEST';
21
29
  export const CREATE_VIBER_TEMPLATE_SUCCESS = 'app/v2Containers/Viber/CREATE_VIBER_TEMPLATE_SUCCESS';
@@ -82,6 +82,7 @@ export const Viber = (props) => {
82
82
  viberData = {},
83
83
  selectedOfferDetails = [],
84
84
  eventContextTags,
85
+ waitEventContextTags,
85
86
  // TestAndPreviewSlidebox props
86
87
  showTestAndPreviewSlidebox: propsShowTestAndPreviewSlidebox,
87
88
  handleTestAndPreview: propsHandleTestAndPreview,
@@ -287,6 +288,7 @@ export const Viber = (props) => {
287
288
  userLocale={localStorage.getItem("jlocale") || "en"}
288
289
  selectedOfferDetails={selectedOfferDetails}
289
290
  eventContextTags={eventContextTags}
291
+ waitEventContextTags={waitEventContextTags}
290
292
  />
291
293
  </CapColumn>
292
294
  <div className="viber-textarea-wrapper">
@@ -417,6 +419,7 @@ export const Viber = (props) => {
417
419
  channel={VIBER}
418
420
  errorMessage={formatMessage(messages.videoErrorMessage)}
419
421
  showVideoNameAndDuration
422
+ assetUploading={viber?.assetUploading}
420
423
  />
421
424
  );
422
425
 
@@ -592,6 +595,7 @@ export const Viber = (props) => {
592
595
  userLocale={localStorage.getItem("jlocale") || "en"}
593
596
  selectedOfferDetails={selectedOfferDetails}
594
597
  eventContextTags={eventContextTags}
598
+ waitEventContextTags={waitEventContextTags}
595
599
  />
596
600
  <CapColumn className="cta-actions">
597
601
  <CapButton
@@ -792,6 +796,10 @@ export const Viber = (props) => {
792
796
  ) {
793
797
  return true;
794
798
  }
799
+ // block submit while a media asset upload is still in progress
800
+ if ((isMediaTypeImage || isMediaTypeVideo) && viber?.assetUploading) {
801
+ return true;
802
+ }
795
803
  if (isBtnTypeCta && !isCtaSaved) {
796
804
  return true;
797
805
  }
@@ -6,51 +6,71 @@
6
6
 
7
7
  import { fromJS } from 'immutable';
8
8
  import * as types from './constants';
9
+ import { createAsyncAssetUploadReducerCases } from '../../utils/asyncAssetUpload';
10
+
11
+ const asyncUploadCases = createAsyncAssetUploadReducerCases({
12
+ PROCESSING: types.UPLOAD_VIBER_ASSET_PROCESSING,
13
+ COMPLETED: types.UPLOAD_VIBER_ASSET_COMPLETED,
14
+ FAILED: types.UPLOAD_VIBER_ASSET_FAILED,
15
+ TIMEOUT: types.UPLOAD_VIBER_ASSET_TIMEOUT,
16
+ });
9
17
 
10
18
  const initialState = fromJS({
11
19
  uploadedAssetData: {},
12
20
  createTemplateInProgress: false,
21
+ assetProcessing: {},
13
22
  });
14
23
 
15
24
  function viberReducer(state = initialState, action) {
16
25
  switch (action.type) {
17
26
  case types.CREATE_VIBER_TEMPLATE_REQUEST:
18
27
  return state
19
- .set('createTemplateInProgress', true)
20
- .set('createTemplateError', false)
21
- .set('createTemplateErrorMessage', fromJS(""));
28
+ .set('createTemplateInProgress', true)
29
+ .set('createTemplateError', false)
30
+ .set('createTemplateErrorMessage', fromJS(""));
22
31
  case types.CREATE_VIBER_TEMPLATE_SUCCESS:
23
32
  return state.set('createTemplateInProgress', false)
24
- .set('response', action.data)
25
- .set('createTemplateError', (action.statusCode !== undefined && action.statusCode > 300))
26
- .set('createTemplateErrorMessage', fromJS(action.errorMsg));
33
+ .set('response', action.data)
34
+ .set('createTemplateError', (action.statusCode !== undefined && action.statusCode > 300))
35
+ .set('createTemplateErrorMessage', fromJS(action.errorMsg));
27
36
  case types.CREATE_VIBER_TEMPLATE_FAILURE:
28
37
  return state
29
- .set('createTemplateInProgress', false)
30
- .set('createTemplateError', true)
31
- .set('createTemplateErrorMessage', fromJS(action.errorMsg));
38
+ .set('createTemplateInProgress', false)
39
+ .set('createTemplateError', true)
40
+ .set('createTemplateErrorMessage', fromJS(action.errorMsg));
32
41
  case types.UPLOAD_VIBER_ASSET_REQUEST:
33
42
  return state
34
- .set('uploadAssetSuccess', false)
35
- .set('assetUploading', true);
43
+ .set('uploadAssetSuccess', false)
44
+ .set('assetUploading', true);
36
45
  case types.UPLOAD_VIBER_ASSET_SUCCESS:
37
46
  return state
38
- .set('uploadAssetSuccess', (action.statusCode !== undefined && action.statusCode !== '' && action.statusCode < 300))
39
- .set('assetUploading', false)
40
- .set(action.templateType !== undefined ? `uploadedAssetData${action.templateType}` : 'uploadedAssetData', action.data);
47
+ .set('uploadAssetSuccess', (action.statusCode !== undefined && action.statusCode !== '' && action.statusCode < 300))
48
+ .set('assetUploading', false)
49
+ .set(action.templateType !== undefined ? `uploadedAssetData${action.templateType}` : 'uploadedAssetData', fromJS(action.data));
41
50
  case types.UPLOAD_VIBER_ASSET_FAILURE:
42
51
  return state
43
- .set('uploadAssetSuccess', false)
44
- .set('assetUploading', false);
52
+ .set('uploadAssetSuccess', false)
53
+ .set('assetUploading', false);
54
+ case asyncUploadCases.PROCESSING:
55
+ return asyncUploadCases.handleProcessing(state, action);
56
+ case asyncUploadCases.COMPLETED:
57
+ return asyncUploadCases.handleCompleted(state, action);
58
+ case asyncUploadCases.FAILED:
59
+ return asyncUploadCases.handleFailed(state, action);
60
+ case asyncUploadCases.TIMEOUT:
61
+ return asyncUploadCases.handleTimeout(state, action);
45
62
  case types.CLEAR_VIBER_ASSET:
46
63
  return state
47
- .delete(action.templateType !== undefined ? `uploadedAssetData${action.templateType}` : 'uploadedAssetData');
64
+ .delete(action.templateType !== undefined ? `uploadedAssetData${action.templateType}` : 'uploadedAssetData')
65
+ .set('assetProcessing', fromJS({}))
66
+ .set('assetUploading', false)
67
+ .set('uploadAssetSuccess', false);
48
68
  // FOR EDIT
49
69
  case types.EDIT_VIBER_TEMPLATE_REQUEST:
50
70
  return state
51
- .set('editTemplateInProgress', true)
52
- .set('editTemplateError', false)
53
- .set('editTemplateErrorMessage', fromJS(""));
71
+ .set('editTemplateInProgress', true)
72
+ .set('editTemplateError', false)
73
+ .set('editTemplateErrorMessage', fromJS(""));
54
74
  case types.EDIT_VIBER_TEMPLATE_SUCCESS:
55
75
  return state.set('editTemplateInProgress', false)
56
76
  .set('editResponse', action.data)
@@ -75,7 +95,10 @@ function viberReducer(state = initialState, action) {
75
95
  return state
76
96
  .delete('uploadedAssetData')
77
97
  .delete('metaEntities')
78
- .delete('templateDetails');
98
+ .delete('templateDetails')
99
+ .set('assetProcessing', fromJS({}))
100
+ .set('assetUploading', false)
101
+ .set('uploadAssetSuccess', false);
79
102
  default:
80
103
  return state;
81
104
  }
@@ -2,17 +2,58 @@ import {
2
2
  call, put, takeLatest, all,
3
3
  } from 'redux-saga/effects';
4
4
  import * as Api from '../../services/api';
5
+ import { pollAssetStatus } from '../../sagas/assetPolling';
6
+ import { createPollingConfig } from '../../utils/asyncAssetUpload';
7
+ import { ASSET_STATUS } from '../../utils/assetStatusConstants';
5
8
  import * as types from './constants';
6
9
 
7
- export function* uploadViberAsset(file, assetType, fileParams ) {
10
+ export function* uploadViberAsset(params) {
8
11
  try {
9
- const result = yield call(Api.uploadFile, file, assetType, fileParams);
10
- yield put({
11
- type: types.UPLOAD_VIBER_ASSET_SUCCESS,
12
- data: result.response.asset,
13
- statusCode: result.status ? result.status.code : '',
14
- templateType: file.templateType,
15
- });
12
+ const result = yield call(Api.uploadFile, params);
13
+ const responseData = result.response || {};
14
+ const statusCode = result?.status?.code || result?.statusCode || 200;
15
+
16
+ if (statusCode === 202 || responseData?.processingStatus === ASSET_STATUS.PROCESSING) {
17
+ const assetId = responseData.assetId || responseData.asset?._id;
18
+ const { templateType } = params;
19
+ const assetType = params.assetType || responseData.asset?.type?.toLowerCase() || 'image';
20
+
21
+ if (assetId) {
22
+ yield put({
23
+ type: types.UPLOAD_VIBER_ASSET_PROCESSING,
24
+ payload: {
25
+ assetId,
26
+ asset: responseData.asset,
27
+ processingStatus: ASSET_STATUS.PROCESSING,
28
+ },
29
+ });
30
+
31
+ const actionTypes = {
32
+ COMPLETED: types.UPLOAD_VIBER_ASSET_COMPLETED,
33
+ FAILED: types.UPLOAD_VIBER_ASSET_FAILED,
34
+ TIMEOUT: types.UPLOAD_VIBER_ASSET_TIMEOUT,
35
+ };
36
+ const pollingConfig = createPollingConfig(assetType, assetId, actionTypes, templateType);
37
+ yield call(pollAssetStatus, pollingConfig);
38
+ } else {
39
+ const errorMessage = 'Asset upload initiated but no asset ID was returned from the server. Unable to track processing status.';
40
+ yield put({
41
+ type: types.UPLOAD_VIBER_ASSET_FAILED,
42
+ payload: {
43
+ assetId: undefined,
44
+ error: errorMessage,
45
+ },
46
+ templateType,
47
+ });
48
+ }
49
+ } else {
50
+ yield put({
51
+ type: types.UPLOAD_VIBER_ASSET_SUCCESS,
52
+ data: responseData.asset,
53
+ statusCode,
54
+ templateType: params.templateType,
55
+ });
56
+ }
16
57
  } catch (error) {
17
58
  yield put({ type: types.UPLOAD_VIBER_ASSET_FAILURE, error });
18
59
  }
@@ -26,7 +67,12 @@ export function* createViberTemplate({ template, callback }) {
26
67
  errorMsg = result.message;
27
68
  throw errorMsg;
28
69
  }
29
- yield put({ type: types.CREATE_VIBER_TEMPLATE_SUCCESS, data: result.response, statusCode: result.status ? result.status.code : '', errorMsg });
70
+ yield put({
71
+ type: types.CREATE_VIBER_TEMPLATE_SUCCESS,
72
+ data: result.response,
73
+ statusCode: result.status ? result.status.code : '',
74
+ errorMsg,
75
+ });
30
76
  if (callback) {
31
77
  callback(result.response);
32
78
  }
@@ -50,7 +96,12 @@ export function* editTemplate({ template, callback }) {
50
96
  if (callback) {
51
97
  callback(result.response);
52
98
  }
53
- yield put({ type: types.EDIT_VIBER_TEMPLATE_SUCCESS, data: result.response, statusCode: result.status ? result.status.code : '', errorMsg });
99
+ yield put({
100
+ type: types.EDIT_VIBER_TEMPLATE_SUCCESS,
101
+ data: result.response,
102
+ statusCode: result.status ? result.status.code : '',
103
+ errorMsg,
104
+ });
54
105
  } catch (error) {
55
106
  yield put({ type: types.EDIT_VIBER_TEMPLATE_FAILURE, error, errorMsg });
56
107
  if (callback) {
@@ -61,7 +112,6 @@ export function* editTemplate({ template, callback }) {
61
112
 
62
113
  export function* getTemplateDetails({id, callback}) {
63
114
  try {
64
-
65
115
  const result = yield call(Api.getTemplateDetails, {id, channel: 'VIBER'});
66
116
  yield put({ type: types.GET_VIBER_TEMPLATE_DETAILS_SUCCESS, data: result.response });
67
117
  if (callback) {
@@ -75,28 +125,19 @@ export function* getTemplateDetails({id, callback}) {
75
125
 
76
126
  function* watchUploadViberAsset() {
77
127
  yield takeLatest(types.UPLOAD_VIBER_ASSET_REQUEST, uploadViberAsset);
78
-
79
-
80
128
  }
81
129
 
82
130
 
83
131
  function* watchCreateTemplate() {
84
-
85
132
  yield takeLatest(types.CREATE_VIBER_TEMPLATE_REQUEST, createViberTemplate);
86
-
87
-
88
133
  }
89
134
 
90
135
  function* watchGetTemplateDetails() {
91
136
  yield takeLatest(types.GET_VIBER_TEMPLATE_DETAILS_REQUEST, getTemplateDetails);
92
-
93
-
94
137
  }
95
138
 
96
139
  function* watchEditTemplate() {
97
140
  yield takeLatest(types.EDIT_VIBER_TEMPLATE_REQUEST, editTemplate);
98
-
99
-
100
141
  }
101
142
 
102
143
  export default [
@@ -113,4 +154,4 @@ export function* v2ViberSagas() {
113
154
  watchGetTemplateDetails(),
114
155
  watchEditTemplate(),
115
156
  ]);
116
- }
157
+ }
@@ -303,4 +303,84 @@ describe('Test Viber container', () => {
303
303
  });
304
304
  expect(doneBtn).toBeDisabled();
305
305
  });
306
+
307
+ it('disables Done while a replacement video asset is uploading (finding 1)', async () => {
308
+ renderComponent({
309
+ actions: mockActions,
310
+ globalActions: mockGlobalActions,
311
+ templateData: { mode: 'create' },
312
+ viber: {
313
+ uploadedAssetData: {},
314
+ createTemplateInProgress: false,
315
+ templateDetails: templateDetailsVideo,
316
+ // a new upload has started after the template was loaded
317
+ assetUploading: true,
318
+ },
319
+ location: {
320
+ pathname: '/sms/edit',
321
+ query: { type: false, module: 'default' },
322
+ search: '',
323
+ },
324
+ isFullMode: true,
325
+ params: { id: 'test' },
326
+ handleClose: jest.fn(),
327
+ metaEntities,
328
+ getDefaultTags,
329
+ injectedTags,
330
+ });
331
+ const doneBtn = screen.getByRole('button', { name: /done/i });
332
+ expect(doneBtn).toBeDisabled();
333
+ });
334
+
335
+ it('disables Done while an image asset is uploading (finding 1)', async () => {
336
+ renderComponent({
337
+ actions: mockActions,
338
+ globalActions: mockGlobalActions,
339
+ templateData: { mode: 'create' },
340
+ viber: {
341
+ uploadedAssetData: {},
342
+ createTemplateInProgress: false,
343
+ templateDetails: templateDetailsImage,
344
+ assetUploading: true,
345
+ },
346
+ location: {
347
+ pathname: '/sms/edit',
348
+ query: { type: false, module: 'default' },
349
+ search: '',
350
+ },
351
+ isFullMode: true,
352
+ params: { id: 'test' },
353
+ handleClose: jest.fn(),
354
+ });
355
+ const doneBtn = screen.getByRole('button', { name: /done/i });
356
+ expect(doneBtn).toBeDisabled();
357
+ });
358
+
359
+ it('keeps Done enabled when assetUploading is true but media type is text', async () => {
360
+ renderComponent({
361
+ actions: mockActions,
362
+ globalActions: mockGlobalActions,
363
+ templateData: { mode: 'create' },
364
+ viber: {
365
+ uploadedAssetData: {},
366
+ createTemplateInProgress: false,
367
+ templateDetails: templateDetailsText,
368
+ // stale upload flag, but the form has no media so submission is safe
369
+ assetUploading: true,
370
+ },
371
+ location: {
372
+ pathname: '/sms/edit',
373
+ query: { type: false, module: 'default' },
374
+ search: '',
375
+ },
376
+ isFullMode: true,
377
+ params: { id: 'test' },
378
+ handleClose: jest.fn(),
379
+ metaEntities,
380
+ getDefaultTags,
381
+ injectedTags,
382
+ });
383
+ const doneBtn = screen.getByRole('button', { name: /done/i });
384
+ expect(doneBtn).toBeEnabled();
385
+ });
306
386
  });