@capillarytech/creatives-library 8.0.282-alpha.1 → 8.0.283

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.282-alpha.1",
4
+ "version": "8.0.283",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -47,6 +47,17 @@ import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox
47
47
  const PrefixWrapper = styled.div`
48
48
  margin-right: 16px;
49
49
  `;
50
+
51
+ const safeParseDeeplinkConfig = (value) => {
52
+ if (!value || typeof value !== 'string') return [];
53
+ try {
54
+ const parsed = JSON.parse(value);
55
+ return Array.isArray(parsed) ? parsed : [];
56
+ } catch {
57
+ return [];
58
+ }
59
+ };
60
+
50
61
  export class Edit extends React.Component { // eslint-disable-line react/prefer-stateless-function
51
62
  constructor(props) {
52
63
  super(props);
@@ -96,11 +107,12 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
96
107
  if (!_.isEmpty(this.state.schema)) {
97
108
  this.injectEvents(this.state.schema);
98
109
  }
99
- if (this.props.location.query && (typeof this.props.location.query.module === 'undefined' || this.props.isFullMode === false)) { // when this containers is imported from creatives library
100
- const templateId = get(this, "props.params.id");
101
- if (templateId) {
110
+ const templateId = get(this, "props.params.id");
111
+ const hasTemplateData = !_.isEmpty(this.props.templateData);
112
+ if (this.props.location?.query && (templateId || hasTemplateData)) {
113
+ if (templateId && templateId !== 'temp') {
102
114
  this.props.actions.getTemplateDetails(templateId);
103
- } else {
115
+ } else if (hasTemplateData) {
104
116
  this.props.actions.setTemplateDetails(this.props.templateData);
105
117
  }
106
118
  }
@@ -176,7 +188,9 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
176
188
  this.props.actions.getMobilepushTemplatesList('mobilepush', params);
177
189
  }
178
190
  if (nextProps.metaEntities && nextProps.metaEntities.layouts && nextProps.metaEntities.layouts.length > 0 && _.isEmpty(this.state.fullSchema)) {
179
- this.setState({fullSchema: nextProps.metaEntities.layouts[0].definition, schema: (nextProps.location.query.module === 'loyalty') ? nextProps.metaEntities.layouts[0].definition.textSchema : {}}, () => {
191
+ const definition = nextProps.metaEntities.layouts[0].definition;
192
+ const initialSchema = definition?.textSchema || definition?.imageSchema || {};
193
+ this.setState({fullSchema: definition, schema: initialSchema}, () => {
180
194
  // Use this.props (latest) in callback to avoid race: templateDetails may have arrived by now
181
195
  const latestSelectedAccount = this.getSelectedWeChatAccountFromProps(this.props);
182
196
  this.handleEditSchemaOnPropsChange(this.props, latestSelectedAccount);
@@ -240,7 +254,10 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
240
254
  newFormData[this.state.currentTab - 1][`secondary-cta-${this.state.currentTab - 1}-action2`] = get(templateCta, 'ctaTemplateDetails[1].buttonText');
241
255
  }
242
256
  }
243
- if (newFormData["mobilepush-accounts"] !== this.state.formData["mobilepush-accounts"]) {
257
+ const newAccount = newFormData["mobilepush-accounts"];
258
+ const currentAccount = this.state.formData["mobilepush-accounts"];
259
+ const isExplicitAccountChange = newAccount !== undefined && newAccount !== currentAccount;
260
+ if (isExplicitAccountChange) {
244
261
  this.setMobilePushAccountOptions(this.props.Edit.weCrmAccounts, newFormData["mobilepush-accounts"]);
245
262
  delete newFormData['mobilepush-template'];
246
263
  delete newFormData['template-name'];
@@ -250,6 +267,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
250
267
  if (!_.isEmpty(newFormData[1])) {
251
268
  delete newFormData[1];
252
269
  }
270
+ } else if (newAccount === undefined && currentAccount !== undefined) {
271
+ newFormData["mobilepush-accounts"] = currentAccount;
253
272
  }
254
273
  if (this.state.isSchemaChanged) {
255
274
  this.setState({isSchemaChanged: false});
@@ -281,7 +300,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
281
300
  if (isEmbeddedEditOrPreview(queryType, mode)) {
282
301
  selectedWeChatAccount = !_.isEmpty(editSelectedWeChatAccount)
283
302
  ? editSelectedWeChatAccount
284
- : templateSelectedWeChatAccount;
303
+ : (templateSelectedWeChatAccount || {});
285
304
  } else if (!_.isEmpty(templateSelectedWeChatAccount)) {
286
305
  selectedWeChatAccount = templateSelectedWeChatAccount;
287
306
  }
@@ -296,7 +315,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
296
315
  const id = field.id;
297
316
  const fieldIndex = findIndex(inputFields, {identifier: id});
298
317
  const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
299
- const deepLinkOptions = _.map(JSON.parse(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) );
318
+ const deepLinkOptions = _.map(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) );
300
319
  // let inputId = deeplinkValue && deeplinkValue.toLowerCase() === "deeplink" ? `${id}-select` : `${id}-text`;
301
320
  // if (field.id === "cta-deeplink-secondary-cta-1" && (tabIndex > 1 || this.state.currentTab > 1)) {
302
321
  // inputId = `${inputId}${tabIndex || this.state.currentTab}`;
@@ -668,7 +687,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
668
687
  getLinkName = (link) => {
669
688
  const selectedWeChatAccount = this.getWeChatAccount();
670
689
  const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
671
- const deepLinkOptions = _.filter(JSON.parse(ck ? selectedWeChatAccount?.configs?.deeplink ?? '[]' : '[]'), (l) => l.link === link);
690
+ const deepLinkOptions = _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (l) => l.link === link);
672
691
  if (deepLinkOptions[0]) {
673
692
  return deepLinkOptions[0].name;
674
693
  }
@@ -766,6 +785,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
766
785
 
767
786
 
768
787
  setEditState(data, schema) {
788
+ if (!data?.versions?.base || typeof data.versions.base !== 'object') return;
769
789
  const tabCount = Object.keys(data.versions.base).length;
770
790
  const formData = {};
771
791
  if (this.props.location.query.type === 'embedded' && this.props.location.query.module === "loyalty") {
@@ -1115,7 +1135,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
1115
1135
  const schema = inputSchema ? _.cloneDeep(inputSchema) : _.cloneDeep(this.state.schema);
1116
1136
  const selectedWeChatAccount = this.getWeChatAccount();
1117
1137
  const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
1118
- const deepLinkOptions = _.map(JSON.parse(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) );
1138
+ const deepLinkOptions = _.map(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) );
1119
1139
 
1120
1140
  const inputFields = get(schema, `containers[0].panes[${currentTab - 1}].sections[0].childSections[0].childSections[0].inputFields`);
1121
1141
  forEach(inputFields, (inputField, fieldIndex) => {
@@ -1267,7 +1287,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
1267
1287
  }
1268
1288
  if (child.inputFields[fieldIndex] && child.inputFields[fieldIndex].id === "cta-deeplink-select-section") {
1269
1289
  const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
1270
- const configkeys = selectedWeChatAccount ? _.filter(JSON.parse(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === selectedDeeplink) : [];
1290
+ const configkeys = selectedWeChatAccount ? _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === selectedDeeplink) : [];
1271
1291
  if (configkeys.length) {
1272
1292
  const options = configkeys[0].keys;
1273
1293
  _.forEach(options, (opt) => {
@@ -1379,7 +1399,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
1379
1399
  }
1380
1400
  if (child.inputFields[fieldIndex] && child.inputFields[fieldIndex].id === "cta-deeplink-select-section") {
1381
1401
  const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
1382
- const configkeys = selectedWeChatAccount ? _.filter(JSON.parse(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === selectedDeeplink) : [];
1402
+ const configkeys = selectedWeChatAccount ? _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === selectedDeeplink) : [];
1383
1403
 
1384
1404
  if (configkeys.length) {
1385
1405
  const options = configkeys[0].keys;
@@ -1733,7 +1753,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
1733
1753
  const fieldIndex = findIndex(inputFields, {identifier: id});
1734
1754
  const formDataKey = id.replace("-show-keys", "");
1735
1755
  const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
1736
- let keys = selectedWeChatAccount ? _.filter(JSON.parse(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === formData[currentTab - 1][formDataKey]) : [];
1756
+ let keys = selectedWeChatAccount ? _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === formData[currentTab - 1][formDataKey]) : [];
1737
1757
  if (keys[0]) {
1738
1758
  keys = keys[0].keys;
1739
1759
  }
@@ -1763,7 +1783,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
1763
1783
  inputFields.splice(fieldIndex + index + 1, 0, row);
1764
1784
  });
1765
1785
  if (!tabIndex) { // removes the existing selected options keys so that newly selected options keys can be added.
1766
- const configkeys = _.filter(JSON.parse(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === this.state.formData[currentTab - 1][field.id]);
1786
+ const configkeys = _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === this.state.formData[currentTab - 1][field.id]);
1767
1787
  if (configkeys.length) {
1768
1788
  const options = configkeys[0].keys;
1769
1789
  inputFields = inputFields.slice(0, fieldIndex + 1).concat(inputFields.slice(fieldIndex + options.length + 1, inputFields.length));
@@ -1783,7 +1803,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
1783
1803
  const id = field.id;
1784
1804
  const schema = inputSchema ? _.cloneDeep(inputSchema) : _.cloneDeep(this.state.schema);
1785
1805
  const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
1786
- const deepLinkOptions = selectedWeChatAccount ? _.map(JSON.parse(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) ) : [];
1806
+ const deepLinkOptions = selectedWeChatAccount ? _.map(safeParseDeeplinkConfig(ck ? selectedWeChatAccount?.configs?.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) ) : [];
1787
1807
  // const eventsMap = _.cloneDeep(this.state.eventsMap);
1788
1808
  const tabIndex = currentTab || this.state.currentTab;
1789
1809
  const inputFields = get(schema, `containers[0].panes[${tabIndex - 1}].sections[0].childSections[0].childSections[0].inputFields`);
@@ -1814,7 +1834,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
1814
1834
  const schema = inputSchema ? _.cloneDeep(inputSchema) : _.cloneDeep(this.state.schema);
1815
1835
  const selectedWeChatAccount = this.getWeChatAccount();
1816
1836
  const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
1817
- const deepLinkOptions = selectedWeChatAccount ? _.map(JSON.parse(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) ) : [];
1837
+ const deepLinkOptions = selectedWeChatAccount ? _.map(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) ) : [];
1818
1838
  const inputFields = get(schema, `containers[0].panes[${tabIndex - 1}].sections[0].childSections[0].childSections[0].inputFields`);
1819
1839
  const fieldIndex = findIndex(inputFields, {identifier: id});
1820
1840
  let newInputFields;
@@ -2030,49 +2050,94 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
2030
2050
  }
2031
2051
 
2032
2052
  handleEditSchemaOnPropsChange = (nextProps, selectedWeChatAccount) => {
2053
+ const templateDetails = nextProps.templateDetails || nextProps.templateData;
2033
2054
  const queryType = String(get(this.props, 'location.query.type', ''))?.toLowerCase();
2034
2055
  const isEmbeddedLibrary = queryType === EMBEDDED && !nextProps.isFullMode;
2035
2056
  const canSetAccountFromTemplate =
2036
- !selectedWeChatAccount &&
2037
- nextProps.templateDetails?.definition?.accountId &&
2057
+ (_.isEmpty(selectedWeChatAccount) || !selectedWeChatAccount?.configs) &&
2058
+ templateDetails?.definition?.accountId &&
2038
2059
  nextProps.Edit?.weCrmAccounts?.length > 0;
2039
- const isLibraryMode = this.props.location.query.type !== 'embedded' || this.props.isFullMode === false;
2060
+ const hasAccountOrEmbedded =
2061
+ !_.isEmpty(selectedWeChatAccount) ||
2062
+ isEmbeddedLibrary ||
2063
+ canSetAccountFromTemplate ||
2064
+ !nextProps.isFullMode ||
2065
+ queryType === EMBEDDED;
2066
+ const hasTemplateDetails = !_.isEmpty(templateDetails);
2067
+ const hasEditData = !_.isEmpty(this.state.editData);
2068
+ const hasFullSchema = !_.isEmpty(this.state.fullSchema);
2069
+ const locationCheck = (this.props.location.query.type !== 'embedded' || this.props.isFullMode === false || queryType === EMBEDDED);
2040
2070
  const canPopulateForm =
2041
- !_.isEmpty(nextProps.templateDetails) &&
2042
- _.isEmpty(this.state.editData) &&
2043
- !_.isEmpty(this.state.fullSchema) &&
2044
- isLibraryMode &&
2045
- (selectedWeChatAccount || isEmbeddedLibrary || canSetAccountFromTemplate || !nextProps.isFullMode);
2071
+ hasTemplateDetails &&
2072
+ !hasEditData &&
2073
+ hasFullSchema &&
2074
+ locationCheck &&
2075
+ hasAccountOrEmbedded;
2046
2076
  if (canPopulateForm) {
2047
2077
  this.props = nextProps;
2048
2078
  if (canSetAccountFromTemplate) {
2049
- this.setMobilePushAccountOptions(nextProps.Edit.weCrmAccounts, nextProps.templateDetails.definition.accountId);
2079
+ this.setMobilePushAccountOptions(nextProps.Edit.weCrmAccounts, templateDetails.definition.accountId);
2050
2080
  }
2051
- const mode = nextProps.templateDetails.definition ? nextProps.templateDetails.definition.mode : nextProps.templateDetails.mode;
2081
+ const mode = templateDetails.definition ? templateDetails.definition.mode : templateDetails.mode;
2052
2082
  const schema = mode === "text" ? this.state.fullSchema?.textSchema : this.state.fullSchema?.imageSchema;
2053
- const isAndroidSupported = get(this, "props.Templates.selectedWeChatAccount.configs.android", '') === '1';
2054
- const isIosSupported = get(this, "props.Templates.selectedWeChatAccount.configs.ios", '') === '1';
2083
+ if (!schema) return;
2084
+ const configs = nextProps.Templates?.selectedWeChatAccount?.configs || {};
2085
+ const hasExplicitConfigs = !_.isEmpty(configs) && ('android' in configs || 'ios' in configs);
2086
+ const isAndroidSupported = hasExplicitConfigs ? configs.android === '1' : true;
2087
+ const isIosSupported = hasExplicitConfigs ? configs.ios === '1' : true;
2055
2088
  if (!isAndroidSupported) {
2056
2089
  const androidField = get(schema, "containers[0].panes[0]");
2057
- androidField.isSupported = false;
2058
- this.setState({currentTab: 2});
2059
- set(schema, "containers[0].panes[0]", androidField);
2090
+ if (androidField) {
2091
+ androidField.isSupported = false;
2092
+ this.setState({currentTab: 2});
2093
+ set(schema, "containers[0].panes[0]", androidField);
2094
+ }
2060
2095
  }
2061
2096
  if (!isIosSupported) {
2062
2097
  const iosField = get(schema, "containers[0].panes[1]");
2063
- iosField.isSupported = false;
2064
-
2065
- set(schema, "containers[0].panes[1]", iosField);
2098
+ if (iosField) {
2099
+ iosField.isSupported = false;
2100
+ set(schema, "containers[0].panes[1]", iosField);
2101
+ }
2066
2102
  }
2067
- this.setEditState(nextProps.templateDetails, schema);
2068
- this.getTags();
2103
+ const dataToUse = this.normalizeTemplateDataForEdit(templateDetails);
2104
+ if (dataToUse?.versions?.base) {
2105
+ this.setEditState(dataToUse, schema);
2106
+ this.getTags();
2107
+ } else {
2108
+ console.warn('[MobliPushEdit] Skipped setEditState - dataToUse.versions.base missing', { dataToUse });
2109
+ }
2110
+ }
2111
+ };
2112
+
2113
+ normalizeTemplateDataForEdit = (data) => {
2114
+ if (!data) return null;
2115
+ if (data.versions?.base) return data;
2116
+ if (data.content?.versions?.base) {
2117
+ return { ...data, versions: data.content.versions };
2069
2118
  }
2119
+ const baseContent = data.content || {};
2120
+ if (baseContent.ANDROID || baseContent.IOS) {
2121
+ return {
2122
+ ...data,
2123
+ versions: { base: baseContent },
2124
+ name: data.name || data.templateName || '',
2125
+ definition: data.definition || {},
2126
+ mode: data.mode || data.definition?.mode || 'text',
2127
+ };
2128
+ }
2129
+ return data;
2070
2130
  }
2071
2131
 
2072
2132
  render() {
2133
+ const queryType = String(get(this.props, 'location.query.type', ''))?.toLowerCase();
2134
+ const isEmbeddedOrLibrary = queryType === 'embedded' || this.props.isFullMode === false;
2135
+ const hasFormContent = !_.isEmpty(this.state.formData) && !_.isEmpty(this.state.schema);
2136
+ const showFormBuilder = !this.props.isLoadingMetaEntities || hasFormContent;
2073
2137
  const schema = this.state.schema;
2074
2138
  const loadingContentEdit = this.state.loadingContentEdit || (this.props.location.query.module === 'dvs' && _.isEmpty(this.state.schema));
2075
- const spinning = get(this.props, "Edit.fetchingWeCrmAccounts") || this.props.isLoadingMetaEntities || loadingContentEdit || this.props.Edit.fetchingDefaultTemplates || this.props.Edit.assetUploading || this.state.loading || (this.props.Edit && (("getTemplateDetailsInProgress" in this.props.Edit && this.props.Edit.getTemplateDetailsInProgress) || ("editTemplateInProgress" in this.props.Edit && this.props.Edit.editTemplateInProgress)));
2139
+ const metaEntitiesBlockSpinner = hasFormContent;
2140
+ const spinning = get(this.props, "Edit.fetchingWeCrmAccounts") || (!metaEntitiesBlockSpinner && this.props.isLoadingMetaEntities) || loadingContentEdit || this.props.Edit.fetchingDefaultTemplates || this.props.Edit.assetUploading || this.state.loading || (this.props.Edit && (("getTemplateDetailsInProgress" in this.props.Edit && this.props.Edit.getTemplateDetailsInProgress) || ("editTemplateInProgress" in this.props.Edit && this.props.Edit.editTemplateInProgress)));
2076
2141
  let tags = this.props.metaEntities && this.props.metaEntities.tags ? this.props.metaEntities.tags.standard : [];
2077
2142
  if (this.props.supportedTags) {
2078
2143
  tags = this.props.supportedTags;
@@ -2082,7 +2147,11 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
2082
2147
  <CapSpin spinning={spinning}>
2083
2148
  <CapRow>
2084
2149
  <CapColumn>
2085
- {!this.props.isLoadingMetaEntities && <FormBuilder
2150
+ {(() => {
2151
+ if (isEmbeddedOrLibrary && !showFormBuilder && hasFormContent) {
2152
+ console.warn('[MobliPushEdit] FormBuilder HIDDEN (isLoadingMetaEntities=true) but formData+schema exist');
2153
+ }
2154
+ return showFormBuilder && <FormBuilder
2086
2155
  channel={MOBILE_PUSH}
2087
2156
  schema={schema}
2088
2157
  showLiquidErrorInFooter={this.props.showLiquidErrorInFooter}
@@ -2117,7 +2186,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
2117
2186
  hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
2118
2187
  isFullMode={this.props.isFullMode}
2119
2188
  eventContextTags={this.props?.eventContextTags}
2120
- />}
2189
+ />;
2190
+ })()}
2121
2191
  </CapColumn>
2122
2192
  {this.props.iosCtasData && this.state.showIosCtaTable &&
2123
2193
  <CapSlideBox