@capillarytech/creatives-library 6.9.2 → 6.9.7

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 (32) hide show
  1. package/components/TemplatePreview/_templatePreview.scss +6 -0
  2. package/components/TemplatePreview/index.js +35 -28
  3. package/config/app.js +1 -1
  4. package/index.html +0 -2
  5. package/package.json +1 -1
  6. package/v2Components/Carousel/index.js +120 -0
  7. package/v2Components/Carousel/style.scss +40 -0
  8. package/v2Components/TemplatePreview/_templatePreview.scss +1 -0
  9. package/v2Components/TemplatePreview/index.js +36 -29
  10. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -1
  11. package/v2Containers/Line/Container/Image/index.js +21 -19
  12. package/v2Containers/Line/Container/ImageCarousel/Content.js +554 -0
  13. package/v2Containers/Line/Container/ImageCarousel/constants.js +10 -0
  14. package/v2Containers/Line/Container/ImageCarousel/index.js +526 -0
  15. package/v2Containers/Line/Container/ImageCarousel/messages.js +178 -0
  16. package/v2Containers/Line/Container/ImageCarousel/style.js +61 -0
  17. package/v2Containers/Line/Container/ImageMap/constants.js +2 -1
  18. package/v2Containers/Line/Container/ImageMap/index.js +31 -6
  19. package/v2Containers/Line/Container/ImageMap/messages.js +12 -0
  20. package/v2Containers/Line/Container/Wrapper/index.js +5 -1
  21. package/v2Containers/Line/Container/Wrapper/messages.js +4 -0
  22. package/v2Containers/Line/Container/Wrapper/utils.js +15 -16
  23. package/v2Containers/Line/Container/_lineCreate.scss +2 -2
  24. package/v2Containers/Line/Container/actions.js +4 -2
  25. package/v2Containers/Line/Container/constants.js +3 -0
  26. package/v2Containers/Line/Container/index.js +49 -11
  27. package/v2Containers/Line/Container/reducer.js +2 -2
  28. package/v2Containers/Line/Container/sagas.js +2 -2
  29. package/v2Containers/Line/Container/style.js +2 -1
  30. package/v2Containers/Templates/_templates.scss +9 -0
  31. package/v2Containers/Templates/index.js +28 -1
  32. package/v2Containers/Templates/messages.js +4 -0
@@ -0,0 +1,61 @@
1
+ import { css } from 'styled-components';
2
+ import {
3
+ CAP_G06,
4
+ CAP_SPACE_16,
5
+ CAP_SPACE_24,
6
+ FONT_COLOR_02,
7
+ } from '@capillarytech/cap-ui-library/styled/variables';
8
+
9
+ export default css`
10
+ padding: 0 ${CAP_SPACE_16} ${CAP_SPACE_16};
11
+ position: relative;
12
+
13
+ .carousel-content {
14
+ position: relative;
15
+ margin-top: 20px;
16
+ }
17
+
18
+ .image-container {
19
+ background-color: ${CAP_G06};
20
+ margin-top: 20px;
21
+ }
22
+
23
+ .choice-title {
24
+ margin-bottom: ${CAP_SPACE_24};
25
+ color: ${FONT_COLOR_02};
26
+ }
27
+
28
+ .image-template-title {
29
+ margin-top: ${CAP_SPACE_24};
30
+ }
31
+
32
+ .cap-tab-v2-wrapper {
33
+ .ant-tabs-bar.ant-tabs-top-bar {
34
+ padding: 0;
35
+ }
36
+ }
37
+
38
+ .extra-button-group {
39
+ button {
40
+ padding: 0;
41
+ margin-left: 6px;
42
+ }
43
+ }
44
+
45
+ .action-type-section {
46
+ margin: ${CAP_SPACE_24} 0;
47
+
48
+ .ant-input-group-addon {
49
+ background-color: transparent;
50
+ }
51
+ }
52
+
53
+ .title-textarea {
54
+ margin-top: ${CAP_SPACE_16};
55
+ }
56
+
57
+ .card-message-header {
58
+ margin-bottom: ${CAP_SPACE_16};
59
+ }
60
+ `;
61
+
@@ -16,4 +16,5 @@ export const DEFAULT_TEMPLATES = [
16
16
  ];
17
17
  export const CUSTOM_TEMPLATES = [
18
18
  "custom"
19
- ];
19
+ ];
20
+ export const MAX_ALLOWED_TITLE_LENGTH = 100;
@@ -26,7 +26,7 @@ import messages from './messages';
26
26
  import {
27
27
  LINE_ASSET_WIDTH,
28
28
  LINE_ASSET_HEIGHT,
29
- LINE_IMG_SIZE,
29
+ MAX_ALLOWED_TITLE_LENGTH,
30
30
  CUSTOM_ASSET_TYPE,
31
31
  DEFAULT_ASSET_TYPE,
32
32
  DEFAULT_TEMPLATES,
@@ -80,6 +80,8 @@ export const LineImageMap = ({
80
80
  const [isImageError, updateImageErrorMessage] = useState(false);
81
81
  const [templateSchema, updateTemplateSchema] = useState([]);
82
82
  const [isTemplateDrawerRequired, updateTemplateDrawerRequirement] = useState(false);
83
+ const [altText, updateTitle] = useState('');
84
+ const [errorTitle, updateErrorTitle] = useState(false);
83
85
 
84
86
  useEffect(() => {
85
87
  const { messageTitle = '',
@@ -88,7 +90,8 @@ export const LineImageMap = ({
88
90
  baseSize = {},
89
91
  selectedTemplate,
90
92
  assetType,
91
- actionLinks
93
+ actionLinks,
94
+ altText,
92
95
  } = content;
93
96
  if ( baseUrl && type === IMAGE_MAP) {
94
97
  updateImageStatus(true);
@@ -100,13 +103,14 @@ export const LineImageMap = ({
100
103
  updateActionLinks(actionLinks);
101
104
  updateTemplateSchema(TEMPLATES_JSON[selectedTemplate]);
102
105
  updateBaseSize(baseSize);
106
+ updateTitle(altText);
103
107
  }
104
108
  }, [content]);
105
109
 
106
110
  useEffect(() => {
107
111
  if (imageSrc && (isFullMode ? messageTitle: true) && imageMapTemplate && actionLinks) {
108
112
  updateMessageState({
109
- isError: !imageSrc || !(isFullMode ? messageTitle : true) || !imageMapTemplate || (isImageError && errorMessageTitle),
113
+ isError: !imageSrc || !(isFullMode ? messageTitle : true) || !imageMapTemplate || (isImageError && errorMessageTitle) || errorTitle || !altText,
110
114
  baseUrl: imageSrc,
111
115
  messageTitle,
112
116
  index,
@@ -116,10 +120,11 @@ export const LineImageMap = ({
116
120
  messageContent: getActions(),
117
121
  selectedTemplate: imageMapTemplate,
118
122
  assetType,
119
- actionLinks
123
+ actionLinks,
124
+ altText,
120
125
  });
121
126
  }
122
- }, [errorMessageTitle, imageSrc, messageTitle, isImageError, imageMapTemplate, actionLinks, assetType, isImage, templateSchema]);
127
+ }, [errorMessageTitle, imageSrc, messageTitle, isImageError, imageMapTemplate, actionLinks, assetType, isImage, templateSchema, altText]);
123
128
 
124
129
  useEffect(() => {
125
130
  const imgSrc = get(Line, 'uploadedAssetData', false);
@@ -195,6 +200,15 @@ export const LineImageMap = ({
195
200
  updateErrorMessageTitle(errorMessage);
196
201
  }
197
202
 
203
+ const onTitleChange = ({ target: { value } }) => {
204
+ updateTitle(value);
205
+ let errorMessage = false;
206
+ if (value === '') {
207
+ errorMessage = formatMessage(messages.emptyAltTextErrorMessage);
208
+ }
209
+ updateErrorTitle(errorMessage);
210
+ }
211
+
198
212
  const uploadImages = (e, {files}) => {
199
213
  if (e) {
200
214
  e.preventDefault();
@@ -467,10 +481,12 @@ export const LineImageMap = ({
467
481
  const baseSize = get(template, 'versions.base.content.messages[0].baseSize', '');
468
482
  const selectedTemplate = get(template, 'definition.selectedTemplate', '');
469
483
  const assetType = get(template, 'definition.assetType', '');
484
+ const altText = get(template, 'versions.base.content.messages[0].altText', '');
470
485
  const actionLinks = get(template, 'definition.actionLinks', {});
471
486
  updateImageStatus(true);
472
487
  updateCreateNew(true);
473
488
  updateImageSrc(baseUrl);
489
+ updateTitle(altText);
474
490
  updateBaseSize(baseSize);
475
491
  updateImageMapTemplate(selectedTemplate);
476
492
  updateAssetType(assetType);
@@ -502,11 +518,20 @@ export const LineImageMap = ({
502
518
  <CapButton
503
519
  className="dragger-button"
504
520
  type="flat"
505
- style={{ top:'-12px', position: 'absolute', right: 0, color: FONT_COLOR_05 }}
521
+ style={{ top: 180 , position: 'absolute', right: 0, color: FONT_COLOR_05 }}
506
522
  onClick={onReUpload}
507
523
  >
508
524
  <FormattedMessage {...messages.imageReUpload} />
509
525
  </CapButton>}
526
+ <CapInput.TextArea
527
+ maxLength={MAX_ALLOWED_TITLE_LENGTH}
528
+ label={<FormattedMessage {...messages.titleLabel} />}
529
+ inductiveText={<FormattedMessage {...messages.titleDescription} />}
530
+ onChange={onTitleChange}
531
+ value={altText}
532
+ errorMessage={errorTitle}
533
+ className="title-textarea"
534
+ />
510
535
  <CapHeading type="h4">{formatMessage(messages.uploadImageLabel)}</CapHeading>
511
536
  <CapLabel type="label1" style={{paddingTop: CAP_SPACE_12, paddingBottom: CAP_SPACE_08}}>{formatMessage(messages.uploadImageDesc)}</CapLabel>
512
537
  <CapError key={`${id}-with-label`}>{isImageError}</CapError>
@@ -27,6 +27,10 @@ export default defineMessages({
27
27
  id: `${scope}.emptyTitleErrorMessage`,
28
28
  defaultMessage: 'Template title can not be empty',
29
29
  },
30
+ "emptyAltTextErrorMessage": {
31
+ id: `${scope}.emptyAltTextErrorMessage`,
32
+ defaultMessage: 'Title can not be empty',
33
+ },
30
34
  "imageDimenstionDescription": {
31
35
  id: `${scope}.imageDimenstionDescription`,
32
36
  defaultMessage: 'Dimensions: {dimensions} Size: Up to 10MB',
@@ -123,4 +127,12 @@ export default defineMessages({
123
127
  id: `${scope}.select`,
124
128
  defaultMessage: 'Select',
125
129
  },
130
+ "titleLabel": {
131
+ id: `${scope}.titleLabel`,
132
+ defaultMessage: 'Title',
133
+ },
134
+ "titleDescription": {
135
+ id: `${scope}.titleDescription`,
136
+ defaultMessage: 'The title is shown in push notifications and in the user\'s chat list.',
137
+ },
126
138
  });
@@ -46,7 +46,9 @@ export const LineWrapper = ({
46
46
  messageContent,
47
47
  messageTitle,
48
48
  baseUrl,
49
- selectedTemplate
49
+ selectedTemplate,
50
+ template,
51
+ altText,
50
52
  } = content;
51
53
 
52
54
  const isTouched = (
@@ -61,6 +63,8 @@ export const LineWrapper = ({
61
63
  || messageContent
62
64
  || baseUrl
63
65
  || selectedTemplate
66
+ || template
67
+ || altText
64
68
  );
65
69
  if (!isTouched) {
66
70
  updateActiveKey(type);
@@ -43,4 +43,8 @@ export default defineMessages({
43
43
  id: `${scope}.imagemapLabel`,
44
44
  defaultMessage: 'Rich message',
45
45
  },
46
+ "templateLabel": {
47
+ id: `${scope}.templateLabel`,
48
+ defaultMessage: 'Card message',
49
+ },
46
50
  });
@@ -1,13 +1,13 @@
1
1
  import React from 'react';
2
2
  import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
3
3
  import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
4
- import { CAP_WHITE, FONT_SIZE_VL } from '@capillarytech/cap-ui-library/styled/variables';
5
4
 
6
- import { TEXT, IMAGE, IMAGE_MAP, STICKER } from '../constants';
5
+ import { TEXT, IMAGE, IMAGE_MAP, STICKER, IMAGE_CAROUSEL, TEMPLATE } from '../constants';
7
6
  import LineText from '../Text';
8
7
  import LineImage from '../Image';
9
8
  import LineSticker from '../Sticker';
10
9
  import LineImageMap from '../ImageMap';
10
+ import LineImageCarousel from '../ImageCarousel';
11
11
  import messages from './messages';
12
12
 
13
13
  export const getTabContent = ({ item, props }) => {
@@ -24,20 +24,24 @@ export const getTabContent = ({ item, props }) => {
24
24
  case IMAGE_MAP: {
25
25
  return <LineImageMap {...props} />;
26
26
  }
27
+ case TEMPLATE: {
28
+ return <LineImageCarousel {...props} />;
29
+ }
27
30
  }
28
31
  };
29
32
 
30
33
  export const itemIcons = {
31
- [TEXT]: 'chat-bubble',
32
- [IMAGE]: 'picture',
33
- [STICKER]: 'smile',
34
- [IMAGE_MAP]: 'add-media', // to change
34
+ [TEXT]: 'text-message',
35
+ [IMAGE]: 'image-message',
36
+ [STICKER]: 'smiley-message',
37
+ [IMAGE_MAP]: 'rich-message',
38
+ [TEMPLATE]: 'carousel-message',
35
39
  };
36
40
 
37
41
 
38
42
  export const getTabPanes = (props) => {
39
- const tableKeys = [TEXT, IMAGE, STICKER, IMAGE_MAP];
40
- const tableKeysCreatives = [TEXT, IMAGE, IMAGE_MAP];
43
+ const tableKeys = [TEXT, IMAGE, STICKER, IMAGE_MAP, TEMPLATE];
44
+ const tableKeysCreatives = [TEXT, IMAGE, IMAGE_MAP, TEMPLATE];
41
45
  return (props.isFullMode ? tableKeysCreatives : tableKeys).map((item) => {
42
46
  const isSelected = props.activeKey === item;
43
47
  return {
@@ -47,14 +51,9 @@ export const getTabPanes = (props) => {
47
51
  title={props.formatMessage(messages[`${item}Label`])}
48
52
  >
49
53
  <CapIcon
50
- type={itemIcons[item]}
51
- size="s"
52
- style={{ fontSize: FONT_SIZE_VL }}
53
- theme={isSelected ? 'filled' : ''}
54
- svgProps={{
55
- fill: isSelected ? '#000' : CAP_WHITE,
56
- stroke: isSelected ? CAP_WHITE : '#000',
57
- }}
54
+ type={isSelected ? `${itemIcons[item]}-filled`: itemIcons[item]}
55
+ size="m"
56
+ style={{ margin: 0 }}
58
57
  />
59
58
  </CapTooltip>
60
59
  ),
@@ -37,7 +37,7 @@
37
37
  bottom: 20px;
38
38
  }
39
39
  .cancel-msg {
40
- margin-left: 120px;
40
+ margin-left: 100px;
41
41
  }
42
42
 
43
43
  .image-container {
@@ -53,7 +53,7 @@
53
53
  object-fit: cover;
54
54
  max-width: 100%;
55
55
  max-height: 100%;
56
- height: auto !important;
56
+ height: 152px !important;
57
57
  width: auto !important;
58
58
  }
59
59
  }
@@ -28,18 +28,20 @@ export function defaultAction() {
28
28
  };
29
29
  }
30
30
 
31
- export function uploadAsset(file, assetType, fileParams) {
31
+ export function uploadAsset(file, assetType, fileParams, templateType) {
32
32
  return {
33
33
  type: types.UPLOAD_ASSET_REQUEST,
34
34
  file,
35
35
  assetType,
36
36
  fileParams,
37
+ templateType,
37
38
  };
38
39
  }
39
40
 
40
- export function clearAsset() {
41
+ export function clearAsset(templateType) {
41
42
  return {
42
43
  type: types.CLEAR_ASSET,
44
+ templateType,
43
45
  };
44
46
  }
45
47
 
@@ -2,8 +2,11 @@ export const TEXT = 'text';
2
2
  export const STICKER = 'sticker';
3
3
  export const IMAGE = 'image';
4
4
  export const IMAGE_MAP = 'imagemap';
5
+ export const IMAGE_CAROUSEL = 'image_carousel';
6
+ export const TEMPLATE = 'template';
5
7
  export const MAX_LINE_WRAPPER_LIMIT = 5;
6
8
  export const MAX_LINE_WRAPPER_LIMIT_FULL_MODE = 1;
9
+ export const IMAGE_MAP_CAMEL_CASE = 'imageMap';
7
10
 
8
11
  /*
9
12
  *
@@ -16,9 +16,13 @@ import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
16
16
  import CapRadioCard from '@capillarytech/cap-ui-library/CapRadioCard';
17
17
  import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
18
18
  import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
19
+ // GA
20
+ import { GA } from '@capillarytech/cap-ui-utils';
21
+ import { TRACK_CREATE_LINE, TRACK_EDIT_LINE } from '../../App/constants';
22
+
19
23
  import LineWrapper from './Wrapper';
20
24
  import messages from './messages';
21
- import { TEXT, IMAGE, IMAGE_MAP, STICKER, MAX_LINE_WRAPPER_LIMIT, MAX_LINE_WRAPPER_LIMIT_FULL_MODE } from './constants';
25
+ import { TEXT, IMAGE, IMAGE_MAP, IMAGE_CAROUSEL, MAX_LINE_WRAPPER_LIMIT, MAX_LINE_WRAPPER_LIMIT_FULL_MODE } from './constants';
22
26
  import { FONT_COLOR_05 } from '@capillarytech/cap-ui-library/styled/variables';
23
27
 
24
28
  import { makeSelectMetaEntities, setInjectedTags } from '../../Cap/selectors';
@@ -29,7 +33,7 @@ import * as compActions from './actions';
29
33
  import * as templateActionsConfig from '../../Templates/actions';
30
34
  import withCreatives from '../../../hoc/withCreatives';
31
35
 
32
-
36
+ const { stopTimer } = GA.timeTracker;
33
37
 
34
38
  export const LineContainer = ({
35
39
  isFullMode,
@@ -105,9 +109,11 @@ export const LineContainer = ({
105
109
  const messageTitle = get(Line, 'templateDetails.name');
106
110
  const baseUrl = get(Line, `templateDetails.versions.base.content.messages.0.baseUrl`);
107
111
  const baseSize = get(Line, `templateDetails.versions.base.content.messages.0.baseSize`);
112
+ const altText = get(Line, `templateDetails.versions.base.content.messages.0.altText`);
108
113
  const selectedTemplate = get(Line, 'templateDetails.selectedTemplate');
109
114
  const assetType = get(Line, 'templateDetails.assetType');
110
115
  const actionLinks = get(Line, 'templateDetails.actionLinks');
116
+ const template = get(Line, `templateDetails.versions.base.content.messages.0.template`);
111
117
  const lineContent = {
112
118
  type,
113
119
  messageContent,
@@ -125,6 +131,8 @@ export const LineContainer = ({
125
131
  baseUrl,
126
132
  actionLinks,
127
133
  baseSize,
134
+ template,
135
+ altText,
128
136
  };
129
137
  updateLineWrapperContent([lineContent]);
130
138
  }
@@ -148,7 +156,9 @@ export const LineContainer = ({
148
156
  baseSize,
149
157
  actionLinks,
150
158
  assetType,
151
- selectedTemplate
159
+ selectedTemplate,
160
+ template,
161
+ altText,
152
162
  }) => {
153
163
  const obj = {
154
164
  type,
@@ -160,7 +170,9 @@ export const LineContainer = ({
160
170
  baseSize,
161
171
  actionLinks,
162
172
  assetType,
163
- selectedTemplate
173
+ selectedTemplate,
174
+ template,
175
+ altText,
164
176
  };
165
177
  if (stickerUrl) {
166
178
  obj.selectedSticker = {
@@ -322,7 +334,9 @@ export const LineContainer = ({
322
334
  baseSize,
323
335
  selectedTemplate,
324
336
  assetType,
325
- actionLinks
337
+ actionLinks,
338
+ template,
339
+ altText,
326
340
  } = {}] = lineWrapperContents;
327
341
  let messageData = { type };
328
342
  messageData[messageType] = messageContent;
@@ -340,11 +354,15 @@ export const LineContainer = ({
340
354
  }
341
355
  if (baseUrl) {
342
356
  messageData.baseUrl = baseUrl;
343
- messageData.altText = IMAGE_MAP;
357
+ messageData.altText = altText;
344
358
  }
345
359
  if (baseSize) {
346
360
  messageData.baseSize = baseSize;
347
361
  }
362
+ if (template) {
363
+ messageData.template = template;
364
+ messageData.altText = altText;
365
+ }
348
366
  return {
349
367
  versions: {
350
368
  base: {
@@ -377,7 +395,9 @@ export const LineContainer = ({
377
395
  baseSize,
378
396
  selectedTemplate,
379
397
  assetType,
380
- actionLinks
398
+ actionLinks,
399
+ template,
400
+ altText,
381
401
  }) => {
382
402
  let messageData = { type };
383
403
  messageData[messageType] = messageContent;
@@ -395,12 +415,16 @@ export const LineContainer = ({
395
415
  }
396
416
  if (baseUrl) {
397
417
  messageData.baseUrl = baseUrl;
398
- messageData.altText = IMAGE_MAP;
418
+ messageData.altText = altText;
399
419
  messageData.baseSize = baseSize;
400
420
  messageData.selectedTemplate = selectedTemplate;
401
421
  messageData.assetType = assetType;
402
422
  messageData.actionLinks = actionLinks;
403
423
  }
424
+ if (template) {
425
+ messageData.template = template;
426
+ messageData.altText = altText;
427
+ }
404
428
  return messageData;
405
429
  });
406
430
  return ({
@@ -415,10 +439,18 @@ export const LineContainer = ({
415
439
  });
416
440
  }
417
441
 
442
+ const getLineType = lineWrapperContents => get(lineWrapperContents, '0.type', TEXT);
443
+
418
444
  const onCreateLine = () => {
419
445
  actions.createTemplate(
420
446
  formatSubmitPayload(lineWrapperContents),
421
447
  () => {
448
+ // stop timer for create line
449
+ stopTimer(TRACK_CREATE_LINE, {
450
+ category: 'Creatives',
451
+ action: TRACK_CREATE_LINE,
452
+ label: getLineType(lineWrapperContents),
453
+ });
422
454
  createCallback();
423
455
  onCreateComplete();
424
456
  }
@@ -427,17 +459,17 @@ export const LineContainer = ({
427
459
 
428
460
  const getPreviewSection = () => {
429
461
  const accountName = get(lineData, 'selectedLineAccount.name', '');
430
- const templateContent = lineWrapperContents.map(({ messageContent, type, previewImageUrl, selectedSticker, baseUrl }) => ({
462
+ const templateContent = lineWrapperContents.map(({ messageContent, type, previewImageUrl, selectedSticker, baseUrl, template }) => ({
431
463
  messageContent,
432
464
  previewImageUrl,
433
465
  selectedSticker,
434
466
  type,
435
- baseUrl
467
+ baseUrl,
468
+ imageCarousel: get(template, 'columns', [{}]).map(({ imageUrl, action: { label: actionLabel } = {} }) => ({ imageUrl, actionLabel }) ),
436
469
  }));
437
470
 
438
471
  return (
439
472
  <TemplatePreview
440
- // style={val.customStyling ? val.customStyling : {}}
441
473
  channel="LINE"
442
474
  content={templateContent}
443
475
  LineAccountName={accountName[0]}
@@ -452,6 +484,12 @@ export const LineContainer = ({
452
484
  _id: params.id,
453
485
  },
454
486
  () => {
487
+ // stop timer for edit line
488
+ stopTimer(TRACK_EDIT_LINE, {
489
+ category: 'Creatives',
490
+ action: TRACK_EDIT_LINE,
491
+ label: getLineType(lineWrapperContents),
492
+ });
455
493
  editCallback();
456
494
  onCreateComplete();
457
495
  });
@@ -42,14 +42,14 @@ function createReducer(state = initialState, action) {
42
42
  return state
43
43
  .set('uploadAssetSuccess', (action.statusCode !== undefined && action.statusCode !== '' && action.statusCode < 300))
44
44
  .set('assetUploading', false)
45
- .set('uploadedAssetData', action.data);
45
+ .set(action.templateType ? `uploadedAssetData${action.templateType}` : 'uploadedAssetData', action.data);
46
46
  case types.UPLOAD_ASSET_FAILURE:
47
47
  return state
48
48
  .set('uploadAssetSuccess', false)
49
49
  .set('assetUploading', false);
50
50
  case types.CLEAR_ASSET:
51
51
  return state
52
- .delete('uploadedAssetData');
52
+ .delete(action.templateType ? `uploadedAssetData${action.templateType}` : 'uploadedAssetData');
53
53
  // FOR EDIT
54
54
  case types.EDIT_TEMPLATE_REQUEST:
55
55
  return state
@@ -21,10 +21,10 @@ export function* createTemplate({ template, callback }) {
21
21
  yield put({ type: types.CREATE_TEMPLATE_FAILURE, error, errorMsg });
22
22
  }
23
23
  }
24
- export function* uploadAsset(file, assetType, fileParams) {
24
+ export function* uploadAsset(file, assetType, fileParams ) {
25
25
  try {
26
26
  const result = yield call(Api.uploadFile, file, assetType, fileParams);
27
- yield put({ type: types.UPLOAD_ASSET_SUCCESS, data: result.response.asset, statusCode: result.status ? result.status.code : '' });
27
+ yield put({ type: types.UPLOAD_ASSET_SUCCESS, data: result.response.asset, statusCode: result.status ? result.status.code : '', templateType: file.templateType });
28
28
  } catch (error) {
29
29
  yield put({ type: types.UPLOAD_ASSET_FAILURE, error });
30
30
  }
@@ -50,7 +50,8 @@ export default css`
50
50
 
51
51
  .text-template-title,
52
52
  .sticker-template-title,
53
- .image-template-title {
53
+ .image-template-title,
54
+ .title-textarea {
54
55
  margin-bottom: ${CAP_SPACE_16};
55
56
  }
56
57
  `;
@@ -36,6 +36,15 @@
36
36
  word-wrap: break-word;
37
37
  }
38
38
  }
39
+
40
+ &.carousel-img-section {
41
+ .ant-card-body {
42
+ padding: $CAP_SPACE_24 0;
43
+ }
44
+ .ant-card-meta {
45
+ padding: 0;
46
+ }
47
+ }
39
48
  }
40
49
  }
41
50
  }
@@ -82,6 +82,7 @@ const LINE_FILTERS = {
82
82
  TEXT: 'text',
83
83
  IMAGE_VIDEO: 'image',
84
84
  IMAGE_MAP: 'imagemap',
85
+ IMAGE_CAROUSEL: 'template',
85
86
  };
86
87
 
87
88
  export class Templates extends React.Component { // eslint-disable-line react/prefer-stateless-function
@@ -635,11 +636,34 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
635
636
  stickerUrl = '',
636
637
  animatedStickerUrl = '',
637
638
  baseUrl = '',
639
+ template: carouselTemplate,
638
640
  }] = [{}],
639
641
  } = {},
640
642
  } = template.versions.base;
641
643
  templateData.content = text;
642
644
  templateData.url = originalContentUrl || animatedStickerUrl || stickerUrl || (baseUrl ? `${baseUrl}/1040` : '');
645
+ if (carouselTemplate) {
646
+ const carouselContent = get(carouselTemplate, 'columns', [{}]).map(({ imageUrl, action: { label: actionLabel } = {} }) => ({ imageUrl, actionLabel }) );
647
+ templateData.content = (
648
+ <div style={{ display: 'flex'}}>
649
+ {
650
+ carouselContent.map(({
651
+ imageUrl,
652
+ actionLabel,
653
+ }) => (
654
+ <img
655
+ width={208}
656
+ height={279}
657
+ src={imageUrl}
658
+ alt={actionLabel}
659
+ key={`${imageUrl}_${actionLabel}`}
660
+ />
661
+ ))
662
+ }
663
+ </div>
664
+ );
665
+ templateData.className = 'carousel-img-section';
666
+ }
643
667
  break;
644
668
  }
645
669
  default:
@@ -1789,7 +1813,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1789
1813
  <CapRadio.CapRadioGroup className="line-filters" defaultValue={lineFilter} onChange={this.setLineFilter}>
1790
1814
  {
1791
1815
  (() => {
1792
- const { ALL, TEXT, IMAGE_VIDEO, STICKER, IMAGE_MAP } = LINE_FILTERS;
1816
+ const { ALL, TEXT, IMAGE_VIDEO, IMAGE_CAROUSEL, IMAGE_MAP } = LINE_FILTERS;
1793
1817
  return (
1794
1818
  <>
1795
1819
  <CapRadio.Button value={ALL}><CapLabel type="label2">
@@ -1804,6 +1828,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1804
1828
  <CapRadio.Button value={IMAGE_MAP}><CapLabel type="label2">
1805
1829
  <FormattedMessage {...messages.imageMapTemplate} />
1806
1830
  </CapLabel></CapRadio.Button>
1831
+ <CapRadio.Button value={IMAGE_CAROUSEL}><CapLabel type="label2">
1832
+ <FormattedMessage {...messages.imageCarouselTemplate} />
1833
+ </CapLabel></CapRadio.Button>
1807
1834
  </>
1808
1835
  );
1809
1836
  })()
@@ -242,6 +242,10 @@ export default defineMessages({
242
242
  id: `${scope}.imageMapTemplate`,
243
243
  defaultMessage: `Rich message`,
244
244
  },
245
+ "imageCarouselTemplate": {
246
+ id: `${scope}.imageCarouselTemplate`,
247
+ defaultMessage: `Card message`,
248
+ },
245
249
  "selectDefaultButton": {
246
250
  id: `${scope}.selectDefaultButton`,
247
251
  defaultMessage: `Select`,