@capillarytech/creatives-library 8.0.9 → 8.0.11

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 (46) hide show
  1. package/config/app.js +2 -0
  2. package/containers/App/constants.js +1 -0
  3. package/initialState.js +3 -0
  4. package/package.json +1 -1
  5. package/services/api.js +20 -0
  6. package/services/tests/api.test.js +148 -0
  7. package/utils/common.js +7 -0
  8. package/utils/commonUtils.js +7 -1
  9. package/utils/tagValidations.js +99 -1
  10. package/utils/tests/commonUtil.test.js +37 -1
  11. package/utils/tests/tagValidations.test.js +392 -2
  12. package/v2Components/Ckeditor/index.js +12 -10
  13. package/v2Components/ErrorInfoNote/index.js +89 -0
  14. package/v2Components/ErrorInfoNote/messages.js +29 -0
  15. package/v2Components/ErrorInfoNote/style.scss +72 -0
  16. package/v2Components/FormBuilder/_formBuilder.scss +4 -1
  17. package/v2Components/FormBuilder/index.js +171 -70
  18. package/v2Components/FormBuilder/messages.js +8 -0
  19. package/v2Containers/Cap/actions.js +8 -0
  20. package/v2Containers/Cap/constants.js +4 -0
  21. package/v2Containers/Cap/mockData.js +74 -0
  22. package/v2Containers/Cap/reducer.js +12 -0
  23. package/v2Containers/Cap/sagas.js +28 -1
  24. package/v2Containers/Cap/selectors.js +5 -0
  25. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +1 -0
  26. package/v2Containers/Cap/tests/reducer.test.js +50 -0
  27. package/v2Containers/Cap/tests/saga.test.js +81 -1
  28. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -0
  29. package/v2Containers/CreativesContainer/SlideBoxFooter.js +40 -17
  30. package/v2Containers/CreativesContainer/constants.js +1 -0
  31. package/v2Containers/CreativesContainer/index.js +45 -4
  32. package/v2Containers/CreativesContainer/index.scss +13 -1
  33. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +16 -0
  34. package/v2Containers/Email/_email.scss +3 -0
  35. package/v2Containers/Email/index.js +2 -0
  36. package/v2Containers/EmailWrapper/index.js +3 -0
  37. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +3 -0
  38. package/v2Containers/Line/Container/sagas.js +1 -1
  39. package/v2Containers/MobilePush/Edit/constants.js +2 -0
  40. package/v2Containers/MobilePush/Edit/index.js +91 -24
  41. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +93 -0
  42. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +12 -0
  43. package/v2Containers/Viber/constants.js +1 -1
  44. package/v2Containers/Viber/index.js +19 -19
  45. package/v2Containers/Viber/messages.js +0 -4
  46. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +12 -0
@@ -6,9 +6,20 @@ import {
6
6
  REQUEST,
7
7
  SUCCESS,
8
8
  FAILURE,
9
+ GET_LIQUID_TAGS_SUCCESS,
10
+ GET_LIQUID_TAGS_FAILURE,
11
+ GET_LIQUID_TAGS_REQUEST,
12
+ GET_SCHEMA_FOR_ENTITY_SUCCESS,
9
13
  } from '../constants';
10
14
  import reducer from '../reducer';
11
15
  import initialState from '../../../initialState';
16
+ import {
17
+ expectedStateGetLiquidTagsRequest,
18
+ expectedStateGetLiquidTagsFailure,
19
+ expectedStateGetLiquidTagsSuccess,
20
+ expectedStateGetSchemaForEntitySuccessTAG,
21
+ expectedStateGetSchemaForEntitySuccess
22
+ } from '../mockData';
12
23
 
13
24
  const mockedInitialState = fromJS(initialState.cap);
14
25
 
@@ -56,4 +67,43 @@ describe('should handle GET_SUPPORT_VIDEOS_CONFIG', () => {
56
67
  demoVideoAndLinkJSONStatus: FAILURE,
57
68
  });
58
69
  });
70
+ it('handles the GET_LIQUID_TAGS_REQUEST action', () => {
71
+ const action = {
72
+ type: GET_LIQUID_TAGS_REQUEST,
73
+ };
74
+ expect(reducer(mockedInitialState, action).toJS()).toEqual(expectedStateGetLiquidTagsRequest);
75
+ });
76
+
77
+ it('handles the GET_LIQUID_TAGS_FAILURE action', () => {
78
+ const action = {
79
+ type: GET_LIQUID_TAGS_FAILURE,
80
+ };
81
+ expect(reducer(mockedInitialState, action).toJS()).toEqual(expectedStateGetLiquidTagsFailure);
82
+ });
83
+
84
+ it('handles the GET_LIQUID_TAGS_SUCCESS action', () => {
85
+ const action = {
86
+ type: GET_LIQUID_TAGS_SUCCESS,
87
+ };
88
+ expect(reducer(mockedInitialState, action).toJS()).toEqual(expectedStateGetLiquidTagsSuccess);
89
+ });
90
+
91
+ it('handles the GET_SCHEMA_FOR_ENTITY_SUCCESS action with action type as TAG', () => {
92
+ const action = {
93
+ type: GET_SCHEMA_FOR_ENTITY_SUCCESS,
94
+ data: {metaEntities:{standard:{"random": "32"}}},
95
+ entityType: "TAG"
96
+ };
97
+
98
+ expect(reducer(mockedInitialState, action).toJS()).toEqual(expectedStateGetSchemaForEntitySuccessTAG);
99
+ });
100
+
101
+ it('handles the GET_SCHEMA_FOR_ENTITY_SUCCESS action', () => {
102
+ const action = {
103
+ type: GET_SCHEMA_FOR_ENTITY_SUCCESS,
104
+ data: {metaEntities:{standard:{"random": "32"}}},
105
+ };
106
+
107
+ expect(reducer(mockedInitialState, action).toJS()).toEqual(expectedStateGetSchemaForEntitySuccess);
108
+ });
59
109
  });
@@ -1,7 +1,7 @@
1
1
  import { take, fork, cancel, takeLatest } from 'redux-saga/effects';
2
2
  import { expectSaga } from 'redux-saga-test-plan';
3
3
  import * as matchers from 'redux-saga-test-plan/matchers';
4
- import { authorize, loginFlow, fetchSchemaForEntity, getSupportVideosConfig, watchForGetVideosConfig, watchFetchSchemaForEntity } from '../sagas';
4
+ import { authorize, loginFlow, fetchSchemaForEntity, getSupportVideosConfig, watchForGetVideosConfig, watchFetchSchemaForEntity,watchLiquidEntity, getLiquidTags } from '../sagas';
5
5
  import { throwError } from 'redux-saga-test-plan/providers';
6
6
  import * as api from '../../../services/api';
7
7
  import {
@@ -14,6 +14,9 @@ import {
14
14
  GET_SUPPORT_VIDEOS_CONFIG_SUCCESS,
15
15
  GET_SUPPORT_VIDEOS_CONFIG_FAILURE,
16
16
  GET_SCHEMA_FOR_ENTITY_REQUEST,
17
+ GET_LIQUID_TAGS_SUCCESS,
18
+ GET_LIQUID_TAGS_FAILURE,
19
+ GET_LIQUID_TAGS_REQUEST,
17
20
  } from '../constants';
18
21
  import { callback, error, error2, videoConfigData } from '../../mockdata';
19
22
 
@@ -207,4 +210,81 @@ describe('watchFetchSchemaForEntity saga', () => {
207
210
  takeLatest(GET_SCHEMA_FOR_ENTITY_REQUEST, fetchSchemaForEntity),
208
211
  );
209
212
  });
213
+ });
214
+
215
+
216
+ describe('getLiquidTags saga', () => {
217
+ it('handles successful API response', () => {
218
+ const action = { data: 'templateContent', callback: () =>{}};
219
+ const result = { result :{errors: [{message: "error in content"}]} };
220
+
221
+ expectSaga(getLiquidTags, action)
222
+ .provide([
223
+ [matchers.call.fn(api.getLiquidTags, 'templateContent'), result],
224
+ [matchers.call.fn(api.askAiraForLiquid, { templateContent: 'templateContent', errorMessage: result?.result?.errors[0]?.message }), { result: { errors: [] } }],
225
+ ])
226
+ .call.fn(action.callback, result)
227
+ .put({ type: GET_LIQUID_TAGS_SUCCESS })
228
+ .run();
229
+ });
230
+
231
+ it('handles successful API response for askAira', () => {
232
+ const action = { data: 'templateContent', callback: () =>{}};
233
+ const result = { result :{errors: [{message: "error in content"}]} };
234
+
235
+ expectSaga(getLiquidTags, action)
236
+ .provide([
237
+ [matchers.call.fn(api.getLiquidTags, 'templateContent'), result],
238
+ [matchers.call.fn(api.askAiraForLiquid, { templateContent: 'templateContent', errorMessage: result?.result?.errors[0]?.message }), {result: { errors: [{message: "Something went wrong"}]} }],
239
+ ])
240
+ .call.fn(action.callback, result)
241
+ .put({ type: GET_LIQUID_TAGS_SUCCESS })
242
+ .run();
243
+ });
244
+
245
+ it('handles API response with errors', () => {
246
+ const action = { data: 'templateContent' };
247
+ const result = { errors: [{ message: 'Error message' }] };
248
+
249
+ expectSaga(getLiquidTags, action)
250
+ .provide([
251
+ [matchers.call.fn(api.getLiquidTags, 'templateContent'), result],
252
+ [matchers.call.fn(api.askAiraForLiquid, { templateContent: 'templateContent', errorMessage: result.errors[0].message }), {result: { errors: [{message: "Something went wrong"}]} }],
253
+ ])
254
+ .not.call.fn(action.callback, result)
255
+ .put({ type: GET_LIQUID_TAGS_FAILURE, error: true })
256
+ .run();
257
+ });
258
+ it('handles API response with undefined', () => {
259
+ const action = { data: 'templateContent' };
260
+ const result = undefined;
261
+
262
+ expectSaga(getLiquidTags, action)
263
+ .provide([
264
+ [matchers.call.fn(api.getLiquidTags, 'templateContent'), result],
265
+ ])
266
+ .not.call.fn(action.callback, result)
267
+ .put({ type: GET_LIQUID_TAGS_FAILURE, error: true })
268
+ .run();
269
+ });
270
+ it('handles error thrown during API call', () => {
271
+ const action = { data: 'templateContent' };
272
+ const error = new Error('API error');
273
+
274
+ expectSaga(getLiquidTags, action)
275
+ .provide([
276
+ [matchers.call.fn(api.getLiquidTags, 'templateContent'), throwError(error)],
277
+ ])
278
+ .put({ type: GET_LIQUID_TAGS_FAILURE, error })
279
+ .run();
280
+ });
281
+ });
282
+
283
+ describe('watchForGetLiquidTags saga', () => {
284
+ const generator = watchLiquidEntity();
285
+ it('should call watchers functions', () => {
286
+ expect(generator.next().value).toEqual(
287
+ takeLatest(GET_LIQUID_TAGS_REQUEST, getLiquidTags),
288
+ );
289
+ });
210
290
  });
@@ -153,6 +153,8 @@ export function SlideBoxContent(props) {
153
153
  hideTestAndPreviewBtn,
154
154
  getCmsTemplatesInProgress = false,
155
155
  moduleType,
156
+ showLiquidErrorInFooter,
157
+ creativesMode,
156
158
  } = props;
157
159
  const type = (messageDetails.type || '').toLowerCase(); // type is context in get tags values : outbound | dvs | referral | loyalty | coupons
158
160
  const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'default' : 'library', isEditFromCampaigns: (templateData || {}).isEditFromCampaigns};
@@ -601,6 +603,7 @@ export function SlideBoxContent(props) {
601
603
  onTestContentClicked={onTestContentClicked}
602
604
  getCmsTemplatesInProgress={getCmsTemplatesInProgress}
603
605
  moduleType={moduleType}
606
+ showLiquidErrorInFooter={showLiquidErrorInFooter}
604
607
  />
605
608
  )}
606
609
  {(isEditEmailWithId || isEmailEditWithContent) && (
@@ -628,6 +631,7 @@ export function SlideBoxContent(props) {
628
631
  onPreviewContentClicked={onPreviewContentClicked}
629
632
  onTestContentClicked={onTestContentClicked}
630
633
  moduleType={moduleType}
634
+ showLiquidErrorInFooter={showLiquidErrorInFooter}
631
635
  />
632
636
  )}
633
637
  {isEditMPush &&
@@ -652,6 +656,7 @@ export function SlideBoxContent(props) {
652
656
  onTestContentClicked={onTestContentClicked}
653
657
  type={type}
654
658
  hideTestAndPreviewBtn={hideTestAndPreviewBtn}
659
+ creativesMode={creativesMode}
655
660
  />
656
661
  }
657
662
  {isCreateMPush &&
@@ -917,5 +922,7 @@ SlideBoxContent.propTypes = {
917
922
  smsRegister: PropTypes.any,
918
923
  getCmsTemplatesInProgress: PropTypes.bool,
919
924
  moduleType: PropTypes.string,
925
+ showLiquidErrorInFooter: PropTypes.bool,
926
+ creativesMode: PropTypes.string,
920
927
  };
921
928
  export default SlideBoxContent;
@@ -1,8 +1,13 @@
1
1
  import React from 'react';
2
2
  import { FormattedMessage } from 'react-intl';
3
- import { CapButton, CapError } from '@capillarytech/cap-ui-library';
3
+ import CapRow from '@capillarytech/cap-ui-library/CapRow';
4
+ import CapButton from '@capillarytech/cap-ui-library/CapButton';
5
+ import CapError from '@capillarytech/cap-ui-library/CapError';
4
6
  import PropTypes from 'prop-types';
5
7
  import messages from './messages';
8
+ import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
9
+ import { PREVIEW } from './constants';
10
+
6
11
  function getFullModeSaveBtn(slidBoxContent) {
7
12
  return slidBoxContent === "editTemplate" ?
8
13
  <FormattedMessage {...messages.creativesTemplatesUpdate}/>
@@ -10,36 +15,53 @@ function getFullModeSaveBtn(slidBoxContent) {
10
15
  <FormattedMessage {...messages.creativesTemplatesSaveFullMode}/>;
11
16
  }
12
17
  function SlideBoxFooter(props) {
13
- const { slidBoxContent, onSave, onEditTemplate, onCreateNextStep, isFullMode, fetchingCmsData, isTemplateNameEmpty} = props;
18
+ const {
19
+ slidBoxContent,
20
+ onSave,
21
+ onEditTemplate,
22
+ onCreateNextStep,
23
+ isFullMode,
24
+ fetchingCmsData,
25
+ isTemplateNameEmpty,
26
+ errorMessages,
27
+ isLiquidValidationError,
28
+ } = props;
14
29
  return (
15
- <div>
30
+ <div className='template-footer-width'>
31
+ {isLiquidValidationError && (<ErrorInfoNote errorMessages={errorMessages} />)}
16
32
  <div>
17
33
  {props.shouldShowDoneFooter() && (
18
34
  <div>
19
- { isFullMode && isTemplateNameEmpty &&
35
+ {isFullMode && isTemplateNameEmpty && (
20
36
  <CapError type="error">
21
37
  <FormattedMessage {...messages.templateNameEmpty} />
22
38
  </CapError>
23
- }
24
- <CapButton onClick={onSave} disabled={isTemplateNameEmpty || fetchingCmsData || false}>
25
- {isFullMode ?
26
- getFullModeSaveBtn(slidBoxContent)
27
- :
28
- <FormattedMessage {...messages.creativesTemplatesSave} />
29
- }
30
- </CapButton>
39
+ )}
40
+ <CapRow>
41
+ <CapButton
42
+ onClick={onSave}
43
+ disabled={isTemplateNameEmpty || fetchingCmsData || false}
44
+ >
45
+ {isFullMode ? (
46
+ getFullModeSaveBtn(slidBoxContent)
47
+ ) : (
48
+ <FormattedMessage {...messages.creativesTemplatesSave} />
49
+ )}
50
+ </CapButton>
51
+ </CapRow>
31
52
  {/* {isFullMode && <CapButton type="secondary" onClick={onDiscard}><FormattedMessage {...messages.creativesTemplatesDiscard}/></CapButton>} */}
32
- </div>)}
33
- {props.shouldShowContinueFooter() &&
53
+ </div>
54
+ )}
55
+ {props.shouldShowContinueFooter() && (
34
56
  <CapButton onClick={onCreateNextStep}>
35
57
  <FormattedMessage {...messages.continue} />
36
58
  </CapButton>
37
- }
38
- {slidBoxContent === 'preview' && (
59
+ )}
60
+ {slidBoxContent === PREVIEW && (
39
61
  <CapButton onClick={onEditTemplate} type="secondary">
40
62
  <FormattedMessage {...messages.creativesTemplatesEdit} />
41
63
  </CapButton>
42
- )}
64
+ )}
43
65
  </div>
44
66
  </div>
45
67
  );
@@ -53,5 +75,6 @@ SlideBoxFooter.propTypes = {
53
75
  shouldShowDoneFooter: PropTypes.func,
54
76
  isFullMode: PropTypes.bool,
55
77
  isTemplateNameEmpty: PropTypes.bool,
78
+ isLiquidValidationError: PropTypes.bool,
56
79
  };
57
80
  export default SlideBoxFooter;
@@ -30,3 +30,4 @@ export const HIDE_CONTAINER_LOADER = "app/CreativesContainer/HIDE_CONTAINER_LOAD
30
30
  export const WHATSAPP_HELP_DOC_LINK = "https://docs.capillarytech.com/docs/create-whatsapp-template";
31
31
 
32
32
  export const ENABLE_AI_SUGGESTIONS = "ENABLE_AI_SUGGESTIONS";
33
+ export const LIQUID_SUPPORTED_CHANNELS = [EMAIL];
@@ -47,6 +47,7 @@ import creativesContainerReducer from './reducer';
47
47
  import { compose } from 'redux';
48
48
  import { capSagaForFetchSchemaForEntity } from '../Cap/sagas';
49
49
  import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
50
+ import { CAP_SPACE_28, CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64, CAP_SPACE_72, CAP_SPACE_80 } from '@capillarytech/cap-ui-library/styled/variables';
50
51
 
51
52
  const classPrefix = 'add-creatives-section';
52
53
  const CREATIVES_CONTAINER = 'creativesContainer';
@@ -54,7 +55,8 @@ const CREATIVES_CONTAINER = 'creativesContainer';
54
55
  const SlideBoxWrapper = styled.div`
55
56
  .cap-slide-box-v2-container{
56
57
  .slidebox-header, .slidebox-content-container, .slidebox-footer{
57
- padding: 0 3rem;
58
+ margin-bottom: ${({ slideBoxWrapperMargin }) => `${slideBoxWrapperMargin}`};
59
+ padding: 0 rem;
58
60
  &.has-footer{
59
61
  overflow-x: hidden;
60
62
  }
@@ -74,6 +76,8 @@ export class Creatives extends React.Component {
74
76
  currentChannel: this.props.channel || 'sms',
75
77
  weChatTemplateType: '',
76
78
  weChatMaptemplateStep: 0,
79
+ isLiquidValidationError: false,
80
+ errorMessages: [],
77
81
  };
78
82
  this.creativesTemplateSteps = {
79
83
  1: 'modeSelection',
@@ -1135,6 +1139,12 @@ export class Creatives extends React.Component {
1135
1139
  }
1136
1140
  }
1137
1141
  }
1142
+
1143
+ showLiquidErrorInFooter = (errorMessages) => {
1144
+ const isError = ( errorMessages?.STANDARD_ERROR_MSG?.length > 0 || errorMessages?.LIQUID_ERROR_MSG?.length > 0);
1145
+ this.setState({isLiquidValidationError: isError, errorMessages});
1146
+ };
1147
+
1138
1148
  shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
1139
1149
  const {slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType} = this.state;
1140
1150
  let isShowContinueFooter = false;
@@ -1175,7 +1185,23 @@ export class Creatives extends React.Component {
1175
1185
  return true;
1176
1186
  }
1177
1187
  render() {
1178
- const {slidBoxContent, isGetFormData, showSlideBox, templateData, currentChannel, emailCreateMode, templateStep, isLoadingContent, mobilePushCreateMode, isDiscardMessage, weChatTemplateType, weChatMaptemplateStep, isTemplateNameEmpty} = this.state;
1188
+ const {
1189
+ slidBoxContent,
1190
+ isGetFormData,
1191
+ showSlideBox,
1192
+ templateData,
1193
+ currentChannel,
1194
+ emailCreateMode,
1195
+ templateStep,
1196
+ isLoadingContent,
1197
+ mobilePushCreateMode,
1198
+ isDiscardMessage,
1199
+ weChatTemplateType,
1200
+ weChatMaptemplateStep,
1201
+ isTemplateNameEmpty,
1202
+ isLiquidValidationError,
1203
+ errorMessages,
1204
+ } = this.state;
1179
1205
  const {
1180
1206
  isFullMode,
1181
1207
  creativesMode,
@@ -1194,10 +1220,21 @@ export class Creatives extends React.Component {
1194
1220
  smsRegister,
1195
1221
  enableNewChannels,
1196
1222
  } = this.props;
1197
- const mapTemplateCreate = slidBoxContent === 'createTemplate' && weChatTemplateType === MAP_TEMPLATE && templateStep !== 'modeSelection';
1223
+ const mapTemplateCreate =
1224
+ slidBoxContent === "createTemplate" &&
1225
+ weChatTemplateType === MAP_TEMPLATE &&
1226
+ templateStep !== "modeSelection";
1227
+ const slideBoxWrapperMargin =
1228
+ errorMessages?.STANDARD_ERROR_MSG?.length > 0 && errorMessages?.LIQUID_ERROR_MSG?.length > 0
1229
+ ? CAP_SPACE_64
1230
+ : errorMessages?.LIQUID_ERROR_MSG?.length > 0
1231
+ ? CAP_SPACE_56
1232
+ : errorMessages?.STANDARD_ERROR_MSG?.length > 0
1233
+ ? CAP_SPACE_32
1234
+ : 0;
1198
1235
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
1199
1236
  return (
1200
- <SlideBoxWrapper className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}>
1237
+ <SlideBoxWrapper slideBoxWrapperMargin={slideBoxWrapperMargin} className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}>
1201
1238
  <CapSlideBox
1202
1239
  header={
1203
1240
  this.shouldShowHeader() && <SlideBoxHeader
@@ -1280,6 +1317,8 @@ export class Creatives extends React.Component {
1280
1317
  hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
1281
1318
  getCmsTemplatesInProgress={this.props.Templates?.getCmsTemplatesInProgress}
1282
1319
  moduleType={this.props.messageDetails?.type}
1320
+ showLiquidErrorInFooter={this.showLiquidErrorInFooter}
1321
+ creativesMode={creativesMode} // An existing prop that we're using here. Required to ensure correct account details in Edit or Preview in case of Embedded mode.
1283
1322
  />
1284
1323
  }
1285
1324
  footer={this.shouldShowFooter() &&
@@ -1298,6 +1337,8 @@ export class Creatives extends React.Component {
1298
1337
  shouldShowDoneFooter={this.shouldShowDoneFooter}
1299
1338
  fetchingCmsData={fetchingCmsData}
1300
1339
  isTemplateNameEmpty={isTemplateNameEmpty}
1340
+ isLiquidValidationError ={isLiquidValidationError}
1341
+ errorMessages={errorMessages}
1301
1342
  />
1302
1343
  }
1303
1344
  handleClose={this.handleCloseSlideBox}
@@ -69,4 +69,16 @@ $classPrefix: add-creatives-section;
69
69
  i {
70
70
  height: $ICON_SIZE_M;
71
71
  }
72
- }
72
+ }
73
+ .liquid-error {
74
+ display: flex;
75
+ gap: $CAP_SPACE_04;
76
+ color: $CAP_COLOR_03;
77
+ vertical-align: text-top;
78
+ align-items: center;
79
+ margin-left: $CAP_SPACE_24;
80
+ }
81
+
82
+ .template-footer-width {
83
+ width: 100%;;
84
+ }
@@ -3,6 +3,7 @@
3
3
  exports[`Test SlideBoxContent container campaign message, add creative click rcs 1`] = `
4
4
  <CreativesContainer__SlideBoxWrapper
5
5
  className="add-creatives-section creatives-library-mode "
6
+ slideBoxWrapperMargin={0}
6
7
  >
7
8
  <CapSlideBox
8
9
  closeIconPosition="right"
@@ -33,6 +34,7 @@ exports[`Test SlideBoxContent container campaign message, add creative click rcs
33
34
  onWechatTemplateChange={[Function]}
34
35
  saveMessage={[Function]}
35
36
  setIsLoadingContent={[Function]}
37
+ showLiquidErrorInFooter={[Function]}
36
38
  showTemplateName={[Function]}
37
39
  slidBoxContent="templates"
38
40
  templateData={
@@ -77,6 +79,7 @@ exports[`Test SlideBoxContent container campaign message, add creative click rcs
77
79
  exports[`Test SlideBoxContent container campaign message, add creative click whatsapp 1`] = `
78
80
  <CreativesContainer__SlideBoxWrapper
79
81
  className="add-creatives-section creatives-library-mode "
82
+ slideBoxWrapperMargin={0}
80
83
  >
81
84
  <CapSlideBox
82
85
  closeIconPosition="right"
@@ -107,6 +110,7 @@ exports[`Test SlideBoxContent container campaign message, add creative click wha
107
110
  onWechatTemplateChange={[Function]}
108
111
  saveMessage={[Function]}
109
112
  setIsLoadingContent={[Function]}
113
+ showLiquidErrorInFooter={[Function]}
110
114
  showTemplateName={[Function]}
111
115
  slidBoxContent="templates"
112
116
  templateData={
@@ -151,6 +155,7 @@ exports[`Test SlideBoxContent container campaign message, add creative click wha
151
155
  exports[`Test SlideBoxContent container campaign message, whatsapp edit all data 1`] = `
152
156
  <CreativesContainer__SlideBoxWrapper
153
157
  className="add-creatives-section creatives-library-mode "
158
+ slideBoxWrapperMargin={0}
154
159
  >
155
160
  <CapSlideBox
156
161
  closeIconPosition="right"
@@ -181,6 +186,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit all data
181
186
  onWechatTemplateChange={[Function]}
182
187
  saveMessage={[Function]}
183
188
  setIsLoadingContent={[Function]}
189
+ showLiquidErrorInFooter={[Function]}
184
190
  showTemplateName={[Function]}
185
191
  slidBoxContent="editTemplate"
186
192
  templateStep="modeSelection"
@@ -191,6 +197,8 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit all data
191
197
  footer={
192
198
  <SlideBoxFooter
193
199
  currentChannel="WHATSAPP"
200
+ errorMessages={Array []}
201
+ isLiquidValidationError={false}
194
202
  onCreateNextStep={[Function]}
195
203
  onDiscard={[Function]}
196
204
  onEditTemplate={[Function]}
@@ -227,6 +235,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit all data
227
235
  exports[`Test SlideBoxContent container campaign message, whatsapp edit min data 1`] = `
228
236
  <CreativesContainer__SlideBoxWrapper
229
237
  className="add-creatives-section creatives-library-mode "
238
+ slideBoxWrapperMargin={0}
230
239
  >
231
240
  <CapSlideBox
232
241
  closeIconPosition="right"
@@ -257,6 +266,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit min data
257
266
  onWechatTemplateChange={[Function]}
258
267
  saveMessage={[Function]}
259
268
  setIsLoadingContent={[Function]}
269
+ showLiquidErrorInFooter={[Function]}
260
270
  showTemplateName={[Function]}
261
271
  slidBoxContent="editTemplate"
262
272
  templateStep="modeSelection"
@@ -267,6 +277,8 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit min data
267
277
  footer={
268
278
  <SlideBoxFooter
269
279
  currentChannel="WHATSAPP"
280
+ errorMessages={Array []}
281
+ isLiquidValidationError={false}
270
282
  onCreateNextStep={[Function]}
271
283
  onDiscard={[Function]}
272
284
  onEditTemplate={[Function]}
@@ -303,6 +315,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit min data
303
315
  exports[`Test SlideBoxContent container it should clear the url, on channel change from new whatsapp to another 1`] = `
304
316
  <CreativesContainer__SlideBoxWrapper
305
317
  className="add-creatives-section creatives-library-mode "
318
+ slideBoxWrapperMargin={0}
306
319
  >
307
320
  <CapSlideBox
308
321
  closeIconPosition="right"
@@ -333,6 +346,7 @@ exports[`Test SlideBoxContent container it should clear the url, on channel chan
333
346
  onWechatTemplateChange={[Function]}
334
347
  saveMessage={[Function]}
335
348
  setIsLoadingContent={[Function]}
349
+ showLiquidErrorInFooter={[Function]}
336
350
  showTemplateName={[Function]}
337
351
  slidBoxContent="editTemplate"
338
352
  templateStep="modeSelection"
@@ -343,6 +357,8 @@ exports[`Test SlideBoxContent container it should clear the url, on channel chan
343
357
  footer={
344
358
  <SlideBoxFooter
345
359
  currentChannel="WHATSAPP"
360
+ errorMessages={Array []}
361
+ isLiquidValidationError={false}
346
362
  onCreateNextStep={[Function]}
347
363
  onDiscard={[Function]}
348
364
  onEditTemplate={[Function]}
@@ -1,4 +1,7 @@
1
+ @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
2
+
1
3
  .email-container {
4
+ padding-bottom: $CAP_SPACE_80;
2
5
  .email-text{
3
6
  height: 100%;
4
7
  overflow: hidden;
@@ -2740,6 +2740,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2740
2740
  type={CmsSettings.type}
2741
2741
  isEmailLoading={isLoading}
2742
2742
  moduleType={moduleType}
2743
+ showLiquidErrorInFooter={this.props.showLiquidErrorInFooter}
2743
2744
  /> : ''}
2744
2745
  </Col>
2745
2746
  </Row>
@@ -2796,6 +2797,7 @@ Email.propTypes = {
2796
2797
  onPreviewContentClicked: PropTypes.func,
2797
2798
  onTestContentClicked: PropTypes.func,
2798
2799
  moduleType: PropTypes.string,
2800
+ showLiquidErrorInFooter: PropTypes.func,
2799
2801
  };
2800
2802
 
2801
2803
  const mapStateToProps = (state, props) => createStructuredSelector({
@@ -214,6 +214,7 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
214
214
  editor,
215
215
  currentOrgDetails,
216
216
  moduleType,
217
+ showLiquidErrorInFooter,
217
218
  } = this.props;
218
219
  const {
219
220
  templateName,
@@ -278,6 +279,7 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
278
279
  defaultData={{ 'template-name': templateName }}
279
280
  cap={cap}
280
281
  showTemplateName={showTemplateName}
282
+ showLiquidErrorInFooter = {showLiquidErrorInFooter}
281
283
  onValidationFail={onValidationFail}
282
284
  forwardedTags={forwardedTags}
283
285
  selectedOfferDetails={selectedOfferDetails}
@@ -321,6 +323,7 @@ EmailWrapper.propTypes = {
321
323
  isUploading: PropTypes.bool,
322
324
  setIsLoadingContent: PropTypes.func,
323
325
  showTemplateName: PropTypes.func,
326
+ showLiquidErrorInFooter: PropTypes.func,
324
327
  onValidationFail: PropTypes.func,
325
328
  forwardedTags: PropTypes.object,
326
329
  selectedOfferDetails: PropTypes.array,
@@ -23084,11 +23084,14 @@ new message content.",
23084
23084
  Object {
23085
23085
  "app": Object {},
23086
23086
  "cap": Object {
23087
+ "fetchingLiquidTags": false,
23087
23088
  "fetchingSchema": true,
23088
23089
  "fetchingSchemaError": "",
23090
+ "liquidTags": Array [],
23089
23091
  "messages": Array [],
23090
23092
  "metaEntities": Object {
23091
23093
  "layouts": Array [],
23094
+ "tagLookupMap": Object {},
23092
23095
  "tags": Array [],
23093
23096
  },
23094
23097
  "orgID": "",
@@ -50,7 +50,7 @@ function* watchUploadAsset() {
50
50
  export function* editTemplate({ template, callback }) {
51
51
  let errorMsg;
52
52
  try {
53
- const result = yield call(Api.createLineTemplate, {template});
53
+ const result = yield call(Api.createLineTemplate, template);
54
54
  if (result.status.code >= 400) {
55
55
  errorMsg = result.message;
56
56
  throw errorMsg;
@@ -33,3 +33,5 @@ export const GET_WECRM_ACCOUNTS_FAILURE = "app/v2Containers/MobilePush/GET_WECRM
33
33
  export const GET_MOBILEPUSH_TEMPLATES_LIST_REQUEST = 'app/v2Containers/WeChat/GET_MOBILEPUSH_TEMPLATES_LIST_REQUEST';
34
34
  export const GET_MOBILEPUSH_TEMPLATES_LIST_SUCCESS = 'app/v2Containers/WeChat/GET_MOBILEPUSH_TEMPLATES_LIST_SUCCESS';
35
35
  export const GET_MOBILEPUSH_TEMPLATES_LIST_FAILURE = 'app/v2Containers/WeChat/GET_MOBILEPUSH_TEMPLATES_LIST_FAILURE';
36
+
37
+ export const MAPP_SDK = 'MAPP_SDK';