@capillarytech/creatives-library 8.0.341 → 8.0.343-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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.341",
4
+ "version": "8.0.343-alpha.0",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -80,7 +80,7 @@ class CapTagList extends React.Component { // eslint-disable-line react/prefer-s
80
80
 
81
81
  componentDidUpdate(prevProps, prevState) {
82
82
  if (this.props.tags !== prevProps.tags || this.state.searchValue !== prevState.searchValue) {
83
- const temp = this.renderTags(this.props.tags, this.state.searchValue);
83
+ const temp = this.renderTags(this.props.tags);
84
84
  this.setState({
85
85
  tagsList: temp,
86
86
  });
@@ -135,14 +135,13 @@ class CapTagList extends React.Component { // eslint-disable-line react/prefer-s
135
135
  const tagNameWithoutUnderscore = tagName.replace(/_/g, " ");
136
136
  const searchStringLower = _.toLower(value);
137
137
  if (_.has(val, "subtags")) {
138
- if (
139
- val?.name
138
+ const temp = this.getSearchedExpandedKeys(val?.subtags, value, nodeKey);
139
+ const nodeMatches = val?.name
140
140
  && (tagName.includes(searchStringLower)
141
- || tagNameWithoutUnderscore.includes(searchStringLower))
142
- ) {
141
+ || tagNameWithoutUnderscore.includes(searchStringLower));
142
+ if (nodeMatches || temp.length > 0) {
143
143
  list.push(nodeKey);
144
144
  }
145
- const temp = this.getSearchedExpandedKeys(val?.subtags, value, nodeKey);
146
145
  list = list.concat(temp);
147
146
  } else if (
148
147
  val?.name
@@ -109,8 +109,7 @@ function emailReducer(state = initialState, action) {
109
109
  .set('fetchingCmsData', false)
110
110
  .set('fetchingCmsDataFailed', true);
111
111
  case types.GET_CMS_ACCOUNTS_REQUEST:
112
- return state
113
- .set('isBeeEnabled', false); // default to false
112
+ return state; // preserve null — "still pending", only update on SUCCESS/FAILURE
114
113
  case types.GET_CMS_ACCOUNTS_SUCCESS:
115
114
  return state
116
115
  .set('isBeeEnabled', action.isBeeEnabled);
@@ -16,15 +16,15 @@ describe('emailReducer', () => {
16
16
  expect(emailReducer(undefined, action)).toMatchSnapshot();
17
17
  });
18
18
 
19
- it.concurrent('it handles GET_CMS_ACCOUNTS_REQUEST action (line 111-113)', () => {
19
+ it.concurrent('it handles GET_CMS_ACCOUNTS_REQUEST action (does not change isBeeEnabled)', () => {
20
20
  const initialState = fromJS({
21
- isBeeEnabled: true, // Start with true to verify it gets set to false
21
+ isBeeEnabled: true, // preserved during request "still pending"
22
22
  });
23
23
  const action = {
24
24
  type: types.GET_CMS_ACCOUNTS_REQUEST,
25
25
  };
26
26
  const result = emailReducer(initialState, action);
27
- expect(result.get('isBeeEnabled')).toBe(false);
27
+ expect(result.get('isBeeEnabled')).toBe(true);
28
28
  });
29
29
 
30
30
  it.concurrent('it handles GET_CMS_ACCOUNTS_SUCCESS action (line 114-116)', () => {
@@ -200,7 +200,9 @@ const useEmailWrapper = ({
200
200
  if (!isEditEmail) {
201
201
  return;
202
202
  }
203
- const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
203
+ const explicitId = params?.id || location?.query?.id || location?.params?.id;
204
+ const pathnameId = !explicitId && location?.pathname?.match(/\/edit\/([^/]+)/)?.[1];
205
+ const hasParamsId = explicitId || (pathnameId && pathnameId !== 'undefined');
204
206
  const hasTemplateDetails = Email?.templateDetails && !isEmpty(Email.templateDetails);
205
207
  const hasTemplateDataProp = templateData && !isEmpty(templateData);
206
208
  const isTemplateLoading = Email?.getTemplateDetailsInProgress;
@@ -230,13 +232,18 @@ const useEmailWrapper = ({
230
232
  // New flow: When template details are loaded and it's a BEE template, set it in Templates.BEETemplate
231
233
  // This allows Email component to properly initialize and call getCmsSetting
232
234
  const hasTemplateDetails = Email?.templateDetails && !isEmpty(Email.templateDetails);
235
+ const hasTemplateProp = templateData && !isEmpty(templateData);
233
236
  // Note: We check Email?.BEETemplate as a proxy, but the actual BEETemplate is in Templates reducer
234
237
  // The Email component will detect it via this.props.Templates.BEETemplate
235
238
  const hasBEETemplate = Email?.BEETemplate && !isEmpty(Email.BEETemplate);
236
239
 
237
- if (hasTemplateDetails && !hasBEETemplate && templatesActions?.setBEETemplate && !beeTemplateSetRef.current) {
240
+ // Use Email.templateDetails when available (edit-by-ID flow), otherwise fall back to
241
+ // the templateData prop (BEE free template flow — template passed directly by consumer)
242
+ const editTemplateSource = hasTemplateDetails ? Email.templateDetails : (hasTemplateProp ? templateData : null);
243
+
244
+ if (editTemplateSource && !hasBEETemplate && templatesActions?.setBEETemplate && !beeTemplateSetRef.current) {
238
245
  // Check if it's a BEE template
239
- const editTemplateData = Email.templateDetails;
246
+ const editTemplateData = editTemplateSource;
240
247
  const getIsDragDrop = (data) => {
241
248
  if (!data) return false;
242
249
  const baseDragDrop = get(data, 'versions.base.is_drag_drop', false);
@@ -265,13 +272,17 @@ const useEmailWrapper = ({
265
272
  || activeTabData.id
266
273
  || get(editTemplateData, 'versions.base.drag_drop_id')
267
274
  || get(editTemplateData, 'versions.base.id')
275
+ || get(editTemplateData, 'base.drag_drop_id')
276
+ || get(editTemplateData, 'base.id')
268
277
  || editTemplateData._id;
269
278
 
270
279
  const isBEESupport = (location?.query?.isBEESupport !== "false") || false;
271
280
  // IMPORTANT: isBEEAppEnable should be consistent across full mode and library mode
272
281
  // It represents whether BEE is enabled for the organization, not the mode
273
282
  // This ensures the same template behaves the same way in both modes
274
- const isBEEAppEnable = checkBeeEditorEnabled();
283
+ // isDragDrop is always true here — pass true directly rather than relying on
284
+ // checkBeeEditorEnabled() which may return false while getCmsAccounts is pending
285
+ const isBEEAppEnable = isDragDrop || checkBeeEditorEnabled();
275
286
  // Check if we're in edit mode - check multiple sources for id
276
287
  const hasParamsId = params?.id
277
288
  || location?.query?.id
@@ -291,11 +302,11 @@ const useEmailWrapper = ({
291
302
  }
292
303
  }
293
304
 
294
- // Reset ref when template changes (template details cleared)
295
- if (!hasTemplateDetails && beeTemplateSetRef.current) {
305
+ // Reset ref when all template sources are gone (prevents duplicate calls on re-render)
306
+ if (!hasTemplateDetails && !hasTemplateProp && beeTemplateSetRef.current) {
296
307
  beeTemplateSetRef.current = false;
297
308
  }
298
- }, [Email?.templateDetails, Email?.BEETemplate, Email?.getTemplateDetailsInProgress, Email?.fetchingCmsSettings, templatesActions, emailActions, params?.id, location?.query, checkBeeEditorEnabled, isFullMode]);
309
+ }, [Email?.templateDetails, Email?.BEETemplate, Email?.getTemplateDetailsInProgress, Email?.fetchingCmsSettings, templatesActions, emailActions, params?.id, location?.query, checkBeeEditorEnabled, isFullMode, templateData]);
299
310
 
300
311
  const onChange = useCallback((e) => {
301
312
  const { target: { value } } = e;
@@ -210,4 +210,8 @@ export default defineMessages({
210
210
  id: `${scope}.cancel`,
211
211
  defaultMessage: 'Cancel',
212
212
  },
213
+ assetIdMissingError: {
214
+ id: `${scope}.assetIdMissingError`,
215
+ defaultMessage: 'Asset upload initiated but no asset ID was returned from the server. Unable to track processing status.',
216
+ },
213
217
  });
@@ -25,32 +25,32 @@ function viberReducer(state = initialState, action) {
25
25
  switch (action.type) {
26
26
  case types.CREATE_VIBER_TEMPLATE_REQUEST:
27
27
  return state
28
- .set('createTemplateInProgress', true)
29
- .set('createTemplateError', false)
30
- .set('createTemplateErrorMessage', fromJS(""));
28
+ .set('createTemplateInProgress', true)
29
+ .set('createTemplateError', false)
30
+ .set('createTemplateErrorMessage', fromJS(""));
31
31
  case types.CREATE_VIBER_TEMPLATE_SUCCESS:
32
32
  return state.set('createTemplateInProgress', false)
33
- .set('response', action.data)
34
- .set('createTemplateError', (action.statusCode !== undefined && action.statusCode > 300))
35
- .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));
36
36
  case types.CREATE_VIBER_TEMPLATE_FAILURE:
37
37
  return state
38
- .set('createTemplateInProgress', false)
39
- .set('createTemplateError', true)
40
- .set('createTemplateErrorMessage', fromJS(action.errorMsg));
38
+ .set('createTemplateInProgress', false)
39
+ .set('createTemplateError', true)
40
+ .set('createTemplateErrorMessage', fromJS(action.errorMsg));
41
41
  case types.UPLOAD_VIBER_ASSET_REQUEST:
42
42
  return state
43
- .set('uploadAssetSuccess', false)
44
- .set('assetUploading', true);
43
+ .set('uploadAssetSuccess', false)
44
+ .set('assetUploading', true);
45
45
  case types.UPLOAD_VIBER_ASSET_SUCCESS:
46
46
  return state
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));
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));
50
50
  case types.UPLOAD_VIBER_ASSET_FAILURE:
51
51
  return state
52
- .set('uploadAssetSuccess', false)
53
- .set('assetUploading', false);
52
+ .set('uploadAssetSuccess', false)
53
+ .set('assetUploading', false);
54
54
  case asyncUploadCases.PROCESSING:
55
55
  return asyncUploadCases.handleProcessing(state, action);
56
56
  case asyncUploadCases.COMPLETED:
@@ -61,16 +61,16 @@ function viberReducer(state = initialState, action) {
61
61
  return asyncUploadCases.handleTimeout(state, action);
62
62
  case types.CLEAR_VIBER_ASSET:
63
63
  return state
64
- .delete(action.templateType !== undefined ? `uploadedAssetData${action.templateType}` : 'uploadedAssetData')
64
+ .delete(action.templateType !== undefined ? `uploadedAssetData${action.templateType}` : 'uploadedAssetData')
65
65
  .set('assetProcessing', fromJS({}))
66
66
  .set('assetUploading', false)
67
67
  .set('uploadAssetSuccess', false);
68
68
  // FOR EDIT
69
69
  case types.EDIT_VIBER_TEMPLATE_REQUEST:
70
70
  return state
71
- .set('editTemplateInProgress', true)
72
- .set('editTemplateError', false)
73
- .set('editTemplateErrorMessage', fromJS(""));
71
+ .set('editTemplateInProgress', true)
72
+ .set('editTemplateError', false)
73
+ .set('editTemplateErrorMessage', fromJS(""));
74
74
  case types.EDIT_VIBER_TEMPLATE_SUCCESS:
75
75
  return state.set('editTemplateInProgress', false)
76
76
  .set('editResponse', action.data)
@@ -6,24 +6,26 @@ import { pollAssetStatus } from '../../sagas/assetPolling';
6
6
  import { createPollingConfig } from '../../utils/asyncAssetUpload';
7
7
  import { ASSET_STATUS } from '../../utils/assetStatusConstants';
8
8
  import * as types from './constants';
9
+ import messages from './messages';
9
10
 
10
11
  export function* uploadViberAsset(params) {
11
12
  try {
12
13
  const result = yield call(Api.uploadFile, params);
13
- const responseData = result.response || {};
14
- const statusCode = result?.status?.code || result?.statusCode || 200;
14
+ const responseData = result?.response || {};
15
+ const statusCode = result?.status?.code || result?.statusCode;
16
+ const asset = responseData?.asset || responseData;
15
17
 
16
18
  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';
19
+ const assetId = asset?._id || responseData?.assetId;
20
+ const { templateType } = params || {};
21
+ const assetType = params?.assetType || asset?.type?.toLowerCase() || 'image';
20
22
 
21
23
  if (assetId) {
22
24
  yield put({
23
25
  type: types.UPLOAD_VIBER_ASSET_PROCESSING,
24
26
  payload: {
25
27
  assetId,
26
- asset: responseData.asset,
28
+ asset,
27
29
  processingStatus: ASSET_STATUS.PROCESSING,
28
30
  },
29
31
  });
@@ -36,12 +38,11 @@ export function* uploadViberAsset(params) {
36
38
  const pollingConfig = createPollingConfig(assetType, assetId, actionTypes, templateType);
37
39
  yield call(pollAssetStatus, pollingConfig);
38
40
  } else {
39
- const errorMessage = 'Asset upload initiated but no asset ID was returned from the server. Unable to track processing status.';
40
41
  yield put({
41
42
  type: types.UPLOAD_VIBER_ASSET_FAILED,
42
43
  payload: {
43
44
  assetId: undefined,
44
- error: errorMessage,
45
+ error: messages.assetIdMissingError,
45
46
  },
46
47
  templateType,
47
48
  });
@@ -49,9 +50,9 @@ export function* uploadViberAsset(params) {
49
50
  } else {
50
51
  yield put({
51
52
  type: types.UPLOAD_VIBER_ASSET_SUCCESS,
52
- data: responseData.asset,
53
+ data: asset,
53
54
  statusCode,
54
- templateType: params.templateType,
55
+ templateType: params?.templateType,
55
56
  });
56
57
  }
57
58
  } catch (error) {
@@ -67,12 +68,7 @@ export function* createViberTemplate({ template, callback }) {
67
68
  errorMsg = result.message;
68
69
  throw errorMsg;
69
70
  }
70
- yield put({
71
- type: types.CREATE_VIBER_TEMPLATE_SUCCESS,
72
- data: result.response,
73
- statusCode: result.status ? result.status.code : '',
74
- errorMsg,
75
- });
71
+ yield put({ type: types.CREATE_VIBER_TEMPLATE_SUCCESS, data: result.response, statusCode: result.status ? result.status.code : '', errorMsg });
76
72
  if (callback) {
77
73
  callback(result.response);
78
74
  }
@@ -96,12 +92,7 @@ export function* editTemplate({ template, callback }) {
96
92
  if (callback) {
97
93
  callback(result.response);
98
94
  }
99
- yield put({
100
- type: types.EDIT_VIBER_TEMPLATE_SUCCESS,
101
- data: result.response,
102
- statusCode: result.status ? result.status.code : '',
103
- errorMsg,
104
- });
95
+ yield put({ type: types.EDIT_VIBER_TEMPLATE_SUCCESS, data: result.response, statusCode: result.status ? result.status.code : '', errorMsg });
105
96
  } catch (error) {
106
97
  yield put({ type: types.EDIT_VIBER_TEMPLATE_FAILURE, error, errorMsg });
107
98
  if (callback) {
@@ -112,6 +103,7 @@ export function* editTemplate({ template, callback }) {
112
103
 
113
104
  export function* getTemplateDetails({id, callback}) {
114
105
  try {
106
+
115
107
  const result = yield call(Api.getTemplateDetails, {id, channel: 'VIBER'});
116
108
  yield put({ type: types.GET_VIBER_TEMPLATE_DETAILS_SUCCESS, data: result.response });
117
109
  if (callback) {
@@ -125,19 +117,28 @@ export function* getTemplateDetails({id, callback}) {
125
117
 
126
118
  function* watchUploadViberAsset() {
127
119
  yield takeLatest(types.UPLOAD_VIBER_ASSET_REQUEST, uploadViberAsset);
120
+
121
+
128
122
  }
129
123
 
130
124
 
131
125
  function* watchCreateTemplate() {
126
+
132
127
  yield takeLatest(types.CREATE_VIBER_TEMPLATE_REQUEST, createViberTemplate);
128
+
129
+
133
130
  }
134
131
 
135
132
  function* watchGetTemplateDetails() {
136
133
  yield takeLatest(types.GET_VIBER_TEMPLATE_DETAILS_REQUEST, getTemplateDetails);
134
+
135
+
137
136
  }
138
137
 
139
138
  function* watchEditTemplate() {
140
139
  yield takeLatest(types.EDIT_VIBER_TEMPLATE_REQUEST, editTemplate);
140
+
141
+
141
142
  }
142
143
 
143
144
  export default [
@@ -154,4 +155,4 @@ export function* v2ViberSagas() {
154
155
  watchGetTemplateDetails(),
155
156
  watchEditTemplate(),
156
157
  ]);
157
- }
158
+ }
@@ -7,6 +7,7 @@ import * as sagas from '../sagas';
7
7
  import * as types from '../constants';
8
8
  import { pollAssetStatus } from '../../../sagas/assetPolling';
9
9
  import { ASSET_STATUS } from '../../../utils/assetStatusConstants';
10
+ import messages from '../messages';
10
11
 
11
12
  describe('Viber Sagas', () => {
12
13
  describe('uploadViberAsset Saga', () => {
@@ -141,7 +142,7 @@ describe('Viber Sagas', () => {
141
142
  type: types.UPLOAD_VIBER_ASSET_FAILED,
142
143
  payload: {
143
144
  assetId: undefined,
144
- error: 'Asset upload initiated but no asset ID was returned from the server. Unable to track processing status.',
145
+ error: messages.assetIdMissingError,
145
146
  },
146
147
  templateType: 0,
147
148
  })
@@ -181,7 +182,7 @@ describe('Viber Sagas', () => {
181
182
  .run();
182
183
  });
183
184
 
184
- it('defaults statusCode to 200 when no status info present', () => {
185
+ it('passes undefined statusCode through when no status info present (no default)', () => {
185
186
  const mockResponse = { response: { asset: mockAsset } };
186
187
  return expectSaga(sagas.uploadViberAsset, mockParams)
187
188
  .provide([
@@ -190,7 +191,7 @@ describe('Viber Sagas', () => {
190
191
  .put({
191
192
  type: types.UPLOAD_VIBER_ASSET_SUCCESS,
192
193
  data: mockAsset,
193
- statusCode: 200,
194
+ statusCode: undefined,
194
195
  templateType: 0,
195
196
  })
196
197
  .run();
@@ -204,7 +205,53 @@ describe('Viber Sagas', () => {
204
205
  ])
205
206
  .put({
206
207
  type: types.UPLOAD_VIBER_ASSET_SUCCESS,
207
- data: undefined,
208
+ data: {},
209
+ statusCode: 201,
210
+ templateType: 0,
211
+ })
212
+ .run();
213
+ });
214
+
215
+ it('normalizes a flat async response (asset fields at top level) for polling', () => {
216
+ // API returns a flat asset object instead of { asset: {...} }
217
+ const flatResponse = {
218
+ status: { code: 202 },
219
+ response: {
220
+ _id: 'flat-asset-789',
221
+ type: 'VIDEO',
222
+ processingStatus: ASSET_STATUS.PROCESSING,
223
+ },
224
+ };
225
+ return expectSaga(sagas.uploadViberAsset, { ...mockParams, assetType: undefined })
226
+ .provide([
227
+ [matchers.call.fn(Api.uploadFile), flatResponse],
228
+ [matchers.call.fn(pollAssetStatus), undefined],
229
+ ])
230
+ .put({
231
+ type: types.UPLOAD_VIBER_ASSET_PROCESSING,
232
+ payload: {
233
+ assetId: 'flat-asset-789',
234
+ asset: flatResponse.response,
235
+ processingStatus: ASSET_STATUS.PROCESSING,
236
+ },
237
+ })
238
+ .call.fn(pollAssetStatus)
239
+ .run();
240
+ });
241
+
242
+ it('normalizes a flat sync response (asset fields at top level)', () => {
243
+ const flatAsset = { _id: 'flat-sync-1', url: 'https://cdn/x.jpg' };
244
+ const flatResponse = {
245
+ status: { code: 201 },
246
+ response: flatAsset,
247
+ };
248
+ return expectSaga(sagas.uploadViberAsset, mockParams)
249
+ .provide([
250
+ [matchers.call.fn(Api.uploadFile), flatResponse],
251
+ ])
252
+ .put({
253
+ type: types.UPLOAD_VIBER_ASSET_SUCCESS,
254
+ data: flatAsset,
208
255
  statusCode: 201,
209
256
  templateType: 0,
210
257
  })