@capillarytech/creatives-library 7.12.42 → 7.12.44

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": "7.12.42",
4
+ "version": "7.12.44",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -3,9 +3,9 @@ import { injectIntl } from 'react-intl';
3
3
 
4
4
  import * as actions from '../actions';
5
5
  import {Cap} from '../index';
6
- import mockData from '../../mockdata';
6
+ import mockdata from '../../mockdata';
7
7
  import { shallowWithIntl } from '../../../helpers/intl-enzym-test-helpers';
8
- const { match, location, capGlobal, language } = mockData;
8
+ const { match, location, capGlobal, language } = mockdata;
9
9
 
10
10
  jest.mock('@capillarytech/cap-ui-utils', () => ({
11
11
  GA: {
@@ -18,7 +18,6 @@ import messages from './messages';
18
18
 
19
19
  export class ChannelTemplates extends React.Component { // eslint-disable-line react/prefer-stateless-function
20
20
  componentDidMount() {
21
- debugger;
22
21
  this.props.actions.getTemplates(this.props.channel);
23
22
  }
24
23
  render() {
@@ -6,6 +6,7 @@ import cloneDeep from 'lodash/cloneDeep';
6
6
  import TemplatesV2 from '../TemplatesV2';
7
7
  import TemplatePreview from '../../v2Components/TemplatePreview';
8
8
  import SmsWrapper from '../SmsWrapper';
9
+ import isEmpty from 'lodash/isEmpty';
9
10
  // import SmsEdit from '../Sms/Edit';
10
11
  import Email from '../Email';
11
12
  import EmailWrapper from '../EmailWrapper';
@@ -239,7 +240,9 @@ export function SlideBoxContent(props) {
239
240
  baseUrl,
240
241
  video,
241
242
  template,
243
+ contents,
242
244
  }) => {
245
+ const isNewLineFormat = isEmpty(template) && !isEmpty(contents);
243
246
  const {
244
247
  originalContentUrl,
245
248
  externalLink: {
@@ -258,8 +261,14 @@ export function SlideBoxContent(props) {
258
261
  previewContent.baseUrl = baseUrl;
259
262
  previewContent.video = originalContentUrl;
260
263
  previewContent.actionUrl = linkUri;
261
- previewContent.imageCarousel = get(template, 'columns', [{}]).map(({ imageUrl, action: { label: actionLabel } = {} }) => ({ imageUrl, actionLabel }) );
262
-
264
+ if (isNewLineFormat) {
265
+ previewContent.imageCarousel = get(contents, 'contents', [{}]).map(({
266
+ hero: { url = ''} = {},
267
+ footer: { contents: [{ action: { label = '' } = {} }] = [{}] } = {},
268
+ }) => ({ imageUrl: url, actionLabel: label }));
269
+ } else {
270
+ previewContent.imageCarousel = get(template, 'columns', [{}]).map(({ imageUrl, action: { label: actionLabel } = {} }) => ({ imageUrl, actionLabel }) );
271
+ }
263
272
  const getType = () => {
264
273
  if (text) {
265
274
  return 'text';
@@ -273,7 +282,7 @@ export function SlideBoxContent(props) {
273
282
  if (baseUrl) {
274
283
  return 'imagemap';
275
284
  }
276
- if (template) {
285
+ if (template || contents) {
277
286
  return 'image_carousel';
278
287
  }
279
288
  if (video) {
@@ -4,7 +4,7 @@ import { shallowWithIntl } from '../../../helpers/intl-enzym-test-helpers';
4
4
  import { SlideBoxContent } from '../SlideBoxContent';
5
5
  import mockdata from '../../mockdata';
6
6
 
7
- const { whatsappEditTemplateData, whatsappPreviewTemplateData, rcsEditTemplateData, rcsPreviewTemplateData } = mockdata;
7
+ const { whatsappEditTemplateData, whatsappPreviewTemplateData, rcsEditTemplateData, rcsPreviewTemplateData, lineEditTemplateData, linePreviewTemplateData } = mockdata;
8
8
 
9
9
  jest.mock("../../../v2Components/FormBuilder", () => ({
10
10
  __esModule: true,
@@ -66,4 +66,14 @@ describe('Test SlideBoxContent container', () => {
66
66
  expect(renderedComponent).toMatchSnapshot();
67
67
  });
68
68
 
69
+ it('Should render correct component for line channel edit mode', () => {
70
+ renderFunction("LINE", "editTemplate", lineEditTemplateData);
71
+ expect(renderedComponent).toMatchSnapshot();
72
+ });
73
+
74
+ it('Should render correct component for line channel preview mode', () => {
75
+ renderFunction("LINE", "preview", linePreviewTemplateData);
76
+ expect(renderedComponent).toMatchSnapshot();
77
+ });
78
+
69
79
  });
@@ -1,5 +1,229 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`Test SlideBoxContent container Should render correct component for line channel edit mode 1`] = `
4
+ <SlideBoxContent__CreativesWrapper>
5
+ <Connect(UserIsAuthenticated(Connect(InjectIntl(CreativesCommon))))
6
+ location={
7
+ Object {
8
+ "pathname": "/sms/edit",
9
+ "query": Object {
10
+ "isEditFromCampaigns": undefined,
11
+ "module": "library",
12
+ "type": "embedded",
13
+ },
14
+ "search": "",
15
+ }
16
+ }
17
+ onCreateComplete={[MockFunction]}
18
+ params={
19
+ Object {
20
+ "id": "629f7ecf134738019b2e332e",
21
+ "mode": undefined,
22
+ }
23
+ }
24
+ route={
25
+ Object {
26
+ "name": "edit_text",
27
+ }
28
+ }
29
+ templateData={
30
+ Object {
31
+ "_id": "629f7ecf134738019b2e332e",
32
+ "channel": "LINE",
33
+ "mode": "edit",
34
+ "modeType": "",
35
+ "type": "LINE",
36
+ "validity": true,
37
+ }
38
+ }
39
+ />
40
+ </SlideBoxContent__CreativesWrapper>
41
+ `;
42
+
43
+ exports[`Test SlideBoxContent container Should render correct component for line channel preview mode 1`] = `
44
+ <SlideBoxContent__CreativesWrapper>
45
+ <InjectIntl(TemplatePreview)
46
+ channel="line"
47
+ charCounterEnabled={false}
48
+ content={
49
+ Array [
50
+ Object {
51
+ "actionUrl": undefined,
52
+ "baseUrl": undefined,
53
+ "imageCarousel": Array [
54
+ Object {
55
+ "actionLabel": "ggg",
56
+ "imageUrl": "https://crm-nightly-new-fileservice.s3.amazonaws.com/intouch_creative_assets/b9f2aa7a-3f1a-4a20-a737-8d50841.jpeg",
57
+ },
58
+ ],
59
+ "messageContent": undefined,
60
+ "previewImageUrl": undefined,
61
+ "selectedSticker": Object {
62
+ "animatedStickerUrl": undefined,
63
+ "packageId": undefined,
64
+ "stickerId": undefined,
65
+ "stickerUrl": undefined,
66
+ },
67
+ "type": "image_carousel",
68
+ "video": undefined,
69
+ },
70
+ ]
71
+ }
72
+ showCount={true}
73
+ templateData={
74
+ Object {
75
+ "_id": "629f7ecf134738019b2e332e",
76
+ "createdAt": "2022-06-07T16:37:35.447Z",
77
+ "createdBy": "15000449",
78
+ "isActive": true,
79
+ "mode": "preview",
80
+ "name": "ggg1",
81
+ "orgId": 1604,
82
+ "totalCount": 31,
83
+ "type": "LINE",
84
+ "updatedAt": "2022-06-07T16:42:02.243Z",
85
+ "updatedBy": "15000449",
86
+ "updatedByName": "Ashish Karan fd",
87
+ "versions": Object {
88
+ "base": Object {
89
+ "content": Object {
90
+ "messages": Array [
91
+ Object {
92
+ "altText": "ggg",
93
+ "contents": Object {
94
+ "contents": Array [
95
+ Object {
96
+ "footer": Object {
97
+ "contents": Array [
98
+ Object {
99
+ "action": Object {
100
+ "label": "ggg",
101
+ "text": "ggg",
102
+ "type": "message",
103
+ },
104
+ "height": "sm",
105
+ "style": "link",
106
+ "type": "button",
107
+ },
108
+ ],
109
+ "layout": "vertical",
110
+ "spacing": "xs",
111
+ "type": "box",
112
+ },
113
+ "hero": Object {
114
+ "aspectMode": "cover",
115
+ "aspectRatio": "1:1",
116
+ "size": "full",
117
+ "type": "image",
118
+ "url": "https://crm-nightly-new-fileservice.s3.amazonaws.com/intouch_creative_assets/b9f2aa7a-3f1a-4a20-a737-8d50841.jpeg",
119
+ },
120
+ "type": "bubble",
121
+ },
122
+ ],
123
+ "type": "carousel",
124
+ },
125
+ "type": "flex",
126
+ },
127
+ ],
128
+ "to": "{{line_id}}",
129
+ },
130
+ },
131
+ "history": Array [],
132
+ },
133
+ }
134
+ }
135
+ viberBrandName=""
136
+ />
137
+ <Connect(UserIsAuthenticated(Connect(InjectIntl(CreativesCommon))))
138
+ location={
139
+ Object {
140
+ "pathname": "/sms/edit",
141
+ "query": Object {
142
+ "isEditFromCampaigns": undefined,
143
+ "module": "library",
144
+ "type": "embedded",
145
+ },
146
+ "search": "",
147
+ }
148
+ }
149
+ onCreateComplete={[MockFunction]}
150
+ params={
151
+ Object {
152
+ "id": "629f7ecf134738019b2e332e",
153
+ "mode": undefined,
154
+ }
155
+ }
156
+ route={
157
+ Object {
158
+ "name": "edit_text",
159
+ }
160
+ }
161
+ templateData={
162
+ Object {
163
+ "_id": "629f7ecf134738019b2e332e",
164
+ "createdAt": "2022-06-07T16:37:35.447Z",
165
+ "createdBy": "15000449",
166
+ "isActive": true,
167
+ "mode": "preview",
168
+ "name": "ggg1",
169
+ "orgId": 1604,
170
+ "totalCount": 31,
171
+ "type": "LINE",
172
+ "updatedAt": "2022-06-07T16:42:02.243Z",
173
+ "updatedBy": "15000449",
174
+ "updatedByName": "Ashish Karan fd",
175
+ "versions": Object {
176
+ "base": Object {
177
+ "content": Object {
178
+ "messages": Array [
179
+ Object {
180
+ "altText": "ggg",
181
+ "contents": Object {
182
+ "contents": Array [
183
+ Object {
184
+ "footer": Object {
185
+ "contents": Array [
186
+ Object {
187
+ "action": Object {
188
+ "label": "ggg",
189
+ "text": "ggg",
190
+ "type": "message",
191
+ },
192
+ "height": "sm",
193
+ "style": "link",
194
+ "type": "button",
195
+ },
196
+ ],
197
+ "layout": "vertical",
198
+ "spacing": "xs",
199
+ "type": "box",
200
+ },
201
+ "hero": Object {
202
+ "aspectMode": "cover",
203
+ "aspectRatio": "1:1",
204
+ "size": "full",
205
+ "type": "image",
206
+ "url": "https://crm-nightly-new-fileservice.s3.amazonaws.com/intouch_creative_assets/b9f2aa7a-3f1a-4a20-a737-8d50841.jpeg",
207
+ },
208
+ "type": "bubble",
209
+ },
210
+ ],
211
+ "type": "carousel",
212
+ },
213
+ "type": "flex",
214
+ },
215
+ ],
216
+ "to": "{{line_id}}",
217
+ },
218
+ },
219
+ "history": Array [],
220
+ },
221
+ }
222
+ }
223
+ />
224
+ </SlideBoxContent__CreativesWrapper>
225
+ `;
226
+
3
227
  exports[`Test SlideBoxContent container Should render correct component for rcs channel create mode 1`] = `
4
228
  <SlideBoxContent__CreativesWrapper>
5
229
  <Connect(UserIsAuthenticated(Connect(InjectIntl(CreativesCommon))))
@@ -47,6 +47,7 @@ export const LineImageCarouselContent = ({
47
47
  const [isDrawerRequired, updateDrawerRequirement] = useState(false);
48
48
  const [isImageError, updateImageErrorMessage] = useState(false);
49
49
  const [imageSrc, updateImageSrc] = useState();
50
+ const [aspectRatio, updateAspectRatio] = useState();
50
51
  const [isImage, updateImageStatus] = useState(false);
51
52
  const [selectedActionType, updateActionType] = useState('');
52
53
  const [actionLabel, updateActionLabel] = useState('');
@@ -58,16 +59,18 @@ export const LineImageCarouselContent = ({
58
59
  const {
59
60
  originalContentUrl = '',
60
61
  type,
62
+ aspectRatio: contentAspectRatio = '',
61
63
  selectedActionType = '',
62
64
  actionLabel = '',
63
65
  actionContent = '',
64
66
  } = content;
65
- if (type === 'image_carousel') {
67
+ if (type === 'carousel') {
66
68
  updateImageStatus(!!originalContentUrl);
67
69
  updateImageSrc(originalContentUrl);
68
70
  updateActionType(selectedActionType);
69
71
  updateActionLabel(actionLabel);
70
72
  updateActionContent(actionContent);
73
+ if (!!contentAspectRatio) updateAspectRatio(contentAspectRatio);
71
74
  }
72
75
  }, [content]);
73
76
 
@@ -76,13 +79,14 @@ export const LineImageCarouselContent = ({
76
79
  updateCarouselMessageState({
77
80
  activeIndex,
78
81
  originalContentUrl: imageSrc,
82
+ aspectRatio,
79
83
  selectedActionType,
80
84
  actionContent,
81
85
  actionLabel,
82
86
  actionContentErrorMessage,
83
87
  actionLabelErrorMessage,
84
88
  index,
85
- type: 'image_carousel',
89
+ type: 'carousel',
86
90
  messageType: 'originalContentUrl',
87
91
  });
88
92
  }
@@ -120,10 +124,11 @@ export const LineImageCarouselContent = ({
120
124
  selectedActionType,
121
125
  actionContent,
122
126
  actionLabel,
127
+ aspectRatio,
123
128
  actionContentErrorMessage,
124
129
  actionLabelErrorMessage,
125
130
  index,
126
- type: 'image_carousel',
131
+ type: 'carousel',
127
132
  messageType: 'originalContentUrl',
128
133
  });
129
134
  }
@@ -140,10 +145,12 @@ export const LineImageCarouselContent = ({
140
145
  },
141
146
  type,
142
147
  } = data;
143
- if (incorrectFile || size > LINE_IMG_SIZE || height > LINE_IMG_HEIGHT || width > LINE_IMG_WIDTH || height / width !== 1) {
148
+ if (incorrectFile || size > LINE_IMG_SIZE || height > LINE_IMG_HEIGHT || width > LINE_IMG_WIDTH || height > (width * 3)) {
144
149
  updateImageErrorMessage(formatMessage(messages.lineImageIncorrectSize));
145
150
  } else {
146
151
  updateImageErrorMessage('');
152
+ const aspectRatio1 = calculateAspectRatio(width, height);
153
+ updateAspectRatio(aspectRatio1);
147
154
  actions.uploadAsset(
148
155
  data.file,
149
156
  data.type,
@@ -153,7 +160,18 @@ export const LineImageCarouselContent = ({
153
160
  }
154
161
  }
155
162
 
156
-
163
+ const calculateGCD = (width, height) => {
164
+ while (height !== 0 ) {
165
+ let reminder = width % height;
166
+ width = height;
167
+ height = reminder;
168
+ }
169
+ return Math.abs(width);
170
+ };
171
+ const calculateAspectRatio = (width, height) => {
172
+ const absValue = calculateGCD(width, height);
173
+ return `${width / absValue}:${height / absValue}`;
174
+ }
157
175
 
158
176
  const uploadImages = (e, { files }) => {
159
177
  if (e) {
@@ -240,10 +258,11 @@ export const LineImageCarouselContent = ({
240
258
  selectedActionType,
241
259
  actionContent,
242
260
  actionLabel,
261
+ aspectRatio,
243
262
  actionContentErrorMessage,
244
263
  actionLabelErrorMessage,
245
264
  index,
246
- type: 'image_carousel',
265
+ type: 'carousel',
247
266
  messageType: 'originalContentUrl',
248
267
  });
249
268
  }
@@ -303,10 +322,11 @@ export const LineImageCarouselContent = ({
303
322
  const imageHeight = get(imageTemplate, 'metaInfo.height');
304
323
  const imageWidth = get(imageTemplate, 'metaInfo.width');
305
324
  const imageSize = get(imageTemplate, 'metaInfo.file_size');
325
+ const aspectRatio1 = calculateAspectRatio(imageWidth, imageHeight);
306
326
  updateDrawerRequirement(false);
307
327
  if (
308
328
  !ALLOWED_EXTENSIONS_REGEX.test(image)
309
- || imageHeight / imageWidth !== 1
329
+ // || imageHeight / imageWidth !== 1
310
330
  || imageHeight > LINE_IMG_HEIGHT
311
331
  || imageWidth > LINE_IMG_WIDTH
312
332
  || imageSize > LINE_IMG_SIZE
@@ -316,17 +336,19 @@ export const LineImageCarouselContent = ({
316
336
  updateImageErrorMessage('');
317
337
  updateImageStatus(true);
318
338
  updateImageSrc(image);
339
+ updateAspectRatio(aspectRatio1);
319
340
  updateCarouselMessageState({
320
341
  activeIndex,
321
342
  isError: !image || isImageError,
322
343
  originalContentUrl: image,
344
+ aspectRatio: aspectRatio1,
323
345
  selectedActionType,
324
346
  actionContent,
325
347
  actionLabel,
326
348
  actionContentErrorMessage,
327
349
  actionLabelErrorMessage,
328
350
  index,
329
- type: 'image_carousel',
351
+ type: 'carousel',
330
352
  messageType: 'originalContentUrl',
331
353
  });
332
354
  }
@@ -383,10 +405,11 @@ export const LineImageCarouselContent = ({
383
405
  selectedActionType,
384
406
  actionContent,
385
407
  actionLabel: value,
408
+ aspectRatio,
386
409
  actionContentErrorMessage,
387
410
  actionLabelErrorMessage,
388
411
  index,
389
- type: 'image_carousel',
412
+ type: 'carousel',
390
413
  messageType: 'originalContentUrl',
391
414
  });
392
415
  }
@@ -400,10 +423,11 @@ export const LineImageCarouselContent = ({
400
423
  selectedActionType: type,
401
424
  actionContent: '',
402
425
  actionLabel,
426
+ aspectRatio,
403
427
  actionContentErrorMessage,
404
428
  actionLabelErrorMessage,
405
429
  index,
406
- type: 'image_carousel',
430
+ type: 'carousel',
407
431
  messageType: 'originalContentUrl',
408
432
  });
409
433
  }
@@ -430,10 +454,11 @@ export const LineImageCarouselContent = ({
430
454
  selectedActionType,
431
455
  actionContent: value,
432
456
  actionLabel,
457
+ aspectRatio,
433
458
  actionContentErrorMessage,
434
459
  actionLabelErrorMessage,
435
460
  index,
436
- type: 'image_carousel',
461
+ type: 'carousel',
437
462
  messageType: 'originalContentUrl',
438
463
  });
439
464
  }
@@ -10,6 +10,7 @@ import CapDrawer from '@capillarytech/cap-ui-library/CapDrawer';
10
10
  import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
11
11
  import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
12
12
  import CapTooltipWithInfo from '@capillarytech/cap-ui-library/CapTooltipWithInfo';
13
+ import isEmpty from 'lodash/isEmpty';
13
14
  import LineDrawer from '../Drawer';
14
15
  import style from './style';
15
16
  import { CAP_G06, FONT_COLOR_01, FONT_COLOR_02, CAP_SPACE_08, CAP_WHITE, CAP_SPACE_24, CAP_SPACE_04 } from '@capillarytech/cap-ui-library/styled/variables';
@@ -43,7 +44,7 @@ export const LineImageCarousel = (props) => {
43
44
  getAllTemplates,
44
45
  } = props;
45
46
 
46
- if (activeKey !== 'template') {
47
+ if (activeKey !== 'flex') {
47
48
  return null;
48
49
  }
49
50
 
@@ -52,8 +53,9 @@ export const LineImageCarousel = (props) => {
52
53
  const defaultCarouselContent = {
53
54
  messageTitle: '',
54
55
  originalContentUrl: '',
56
+ aspectRatio: '',
55
57
  previewImageUrl: '',
56
- type: 'image_carousel',
58
+ type: 'carousel',
57
59
  };
58
60
 
59
61
  const [carouselImages, updateCarouselImage] = useState([defaultCarouselContent]);
@@ -68,7 +70,7 @@ export const LineImageCarousel = (props) => {
68
70
 
69
71
  useEffect(() => {
70
72
  const { messageTitle = '', type, template, altText } = content;
71
- if (type === 'template') {
73
+ if (type === 'template' || type === 'flex') {
72
74
  updateCreateNew(!isFullMode ? !!template : true);
73
75
  if (messageTitle) {
74
76
  updateTextMessageTitle(messageTitle);
@@ -77,31 +79,66 @@ export const LineImageCarousel = (props) => {
77
79
  updateTitle(altText);
78
80
  }
79
81
  if (template) {
80
- const { columns } = template;
81
- if (columns && columns.length) {
82
- const validCarouselImages = [];
83
- columns.forEach((column = {}, index) => {
84
- const {
85
- action: {
86
- label,
87
- text,
88
- type,
89
- uri,
90
- } = {},
91
- imageUrl,
92
- } = column;
93
-
94
- validCarouselImages.push({
95
- activeIndex: index,
96
- originalContentUrl: imageUrl,
97
- selectedActionType: type ? (type === MESSAGE_ACTION_TYPE ? TEXT_ACTION_TYPE : URL_ACTION_TYPE) : '',
98
- actionContent: text || uri,
99
- actionLabel: label,
100
- type: 'image_carousel',
101
- });
102
- })
103
- updateCarouselImage(validCarouselImages);
82
+ const validCarouselImages = [];
83
+ if (template.type != undefined && template.type === "carousel") {
84
+ const { contents = [] } = template;
85
+ if(contents && contents.length) {
86
+ contents.forEach((content = {}, index1) => {
87
+ const {
88
+ footer: {
89
+ contents: [{
90
+ action: {
91
+ text = '',
92
+ label = '',
93
+ type: buttonType = '',
94
+ uri,
95
+ } = {},
96
+ }] = [],
97
+ } = {},
98
+ hero: {
99
+ url = '',
100
+ aspectRatio = '',
101
+ } = {},
102
+ } = content || {};
103
+ validCarouselImages.push({
104
+ activeIndex: index1,
105
+ originalContentUrl: url,
106
+ aspectRatio,
107
+ selectedActionType: buttonType ? (buttonType === MESSAGE_ACTION_TYPE ? TEXT_ACTION_TYPE : URL_ACTION_TYPE) : '',
108
+ actionContent: text || uri,
109
+ actionLabel: label,
110
+ type: 'carousel',
111
+ });
112
+ })
113
+ }
114
+ } else {
115
+ const { columns } = template;
116
+ if (columns && columns.length) {
117
+ columns.forEach((column = {}, index) => {
118
+ const {
119
+ action: {
120
+ label,
121
+ text,
122
+ type,
123
+ uri,
124
+ } = {},
125
+ imageUrl,
126
+ aspectRatio,
127
+ } = column;
128
+
129
+ validCarouselImages.push({
130
+ activeIndex: index,
131
+ originalContentUrl: imageUrl,
132
+ selectedActionType: type ? (type === MESSAGE_ACTION_TYPE ? TEXT_ACTION_TYPE : URL_ACTION_TYPE) : '',
133
+ actionContent: text || uri,
134
+ actionLabel: label,
135
+ aspectRatio,
136
+ type: 'carousel',
137
+ });
138
+ })
139
+ }
104
140
  }
141
+ updateCarouselImage(validCarouselImages);
105
142
  }
106
143
  }
107
144
  }, [content]);
@@ -111,8 +148,9 @@ export const LineImageCarousel = (props) => {
111
148
  const existingTitle = inheritedTitle !== undefined ? inheritedTitle : altText;
112
149
  let isErrorIndex;
113
150
  const columns = [];
114
- (newCarouselImages || carouselImages).forEach(({
151
+ (newCarouselImages || []).forEach(({
115
152
  originalContentUrl,
153
+ aspectRatio = '1:1',
116
154
  selectedActionType,
117
155
  actionLabel,
118
156
  actionContent,
@@ -125,6 +163,7 @@ export const LineImageCarousel = (props) => {
125
163
  : ((!originalContentUrl || !selectedActionType || actionContentErrorMessage || actionLabelErrorMessage || !actionContent) && activeIndex);
126
164
  columns.push({
127
165
  imageUrl: originalContentUrl,
166
+ aspectRatio,
128
167
  action: {
129
168
  type: selectedActionType ? (selectedActionType === TEXT_ACTION_TYPE ? MESSAGE_ACTION_TYPE : URL_ACTION_TYPE) : '',
130
169
  label: actionLabel,
@@ -137,7 +176,7 @@ export const LineImageCarousel = (props) => {
137
176
  isError: isErrorIndex !== undefined && isErrorIndex !== false,
138
177
  messageTitle: existingMessageTitle,
139
178
  altText: existingTitle,
140
- type: 'template',
179
+ type: 'flex',
141
180
  index,
142
181
  }
143
182
 
@@ -344,19 +383,32 @@ export const LineImageCarousel = (props) => {
344
383
  const {
345
384
  content: {
346
385
  messages: [{
386
+ contents: imageCarouselContents,
347
387
  template: imageCarouselTemplate,
348
388
  }] = [{}],
349
389
  } = {},
350
390
  } = template.versions.base;
351
- templateData.url = (imageCarouselTemplate ? get(imageCarouselTemplate, 'columns.0.imageUrl', '') : '');
352
- templateData.title = template.name;
353
- templateData.key = template.name;
391
+ let isNewLineFormat = false;
392
+ if(!imageCarouselTemplate && imageCarouselContents) {
393
+ isNewLineFormat = true;
394
+ }
395
+ if(isNewLineFormat) {
396
+ templateData.url = (imageCarouselContents ? get(imageCarouselContents, 'contents.0.hero.url', '') : '');
397
+ templateData.title = template.name;
398
+ templateData.key = template.name;
399
+
400
+ } else {
401
+ templateData.url = (imageCarouselTemplate ? get(imageCarouselTemplate, 'columns.0.imageUrl', '') : '');
402
+ templateData.title = template.name;
403
+ templateData.key = template.name;
404
+ }
405
+
354
406
  templateData.hoverOption = (
355
407
  <CapButton onClick={() => onTemplateSelection(template)}>
356
408
  <FormattedMessage {...messages.select} />
357
409
  </CapButton>
358
410
  );
359
- if (imageCarouselTemplate) {
411
+ if (imageCarouselTemplate || imageCarouselContents) {
360
412
  cardDataList.push(templateData);
361
413
  }
362
414
  });
@@ -383,32 +435,75 @@ export const LineImageCarousel = (props) => {
383
435
 
384
436
  const onTemplateSelection = (templateData) => {
385
437
  const template = get(templateData, 'versions.base.content.messages[0].template', {});
438
+ const contents1 = get(templateData, 'versions.base.content.messages[0].contents', {});
386
439
  const altText = get(templateData, 'versions.base.content.messages[0].altText', '');
387
- const { columns } = template;
388
- if (columns && columns.length) {
389
- const validCarouselImages = [];
390
- columns.forEach((column = {}, index) => {
391
- const {
392
- action: {
393
- label,
394
- text,
395
- type,
396
- uri,
397
- } = {},
398
- imageUrl,
399
- } = column;
400
-
401
- validCarouselImages.push({
402
- activeIndex: index,
403
- originalContentUrl: imageUrl,
404
- selectedActionType: type ? (type === MESSAGE_ACTION_TYPE ? TEXT_ACTION_TYPE : URL_ACTION_TYPE) : '',
405
- actionContent: text || uri,
406
- actionLabel: label,
407
- type: 'image_carousel',
408
- });
409
- })
410
- updateCarouselImage(validCarouselImages);
440
+ let isNewLineFormat = false;
441
+ const validCarouselImages = [];
442
+
443
+ if (!isEmpty(contents1) && isEmpty(template)) {
444
+ isNewLineFormat = true;
411
445
  }
446
+ if (isNewLineFormat) {
447
+ const { contents = [] } = contents1;
448
+
449
+ if(contents && contents.length) {
450
+ contents.forEach((content = {}, index1) => {
451
+ const {
452
+ footer: {
453
+ contents: [{
454
+ action: {
455
+ text = '',
456
+ label = '',
457
+ type: buttonType = '',
458
+ uri,
459
+ } = {},
460
+ }] = [],
461
+ } = {},
462
+ hero: {
463
+ url = '',
464
+ aspectRatio = '',
465
+ } = {},
466
+ } = content || {};
467
+ validCarouselImages.push({
468
+ activeIndex: index1,
469
+ originalContentUrl: url,
470
+ aspectRatio,
471
+ selectedActionType: buttonType ? (buttonType === MESSAGE_ACTION_TYPE ? TEXT_ACTION_TYPE : URL_ACTION_TYPE) : '',
472
+ actionContent: text || uri,
473
+ actionLabel: label,
474
+ type: 'carousel',
475
+ });
476
+ })
477
+ }
478
+
479
+ } else {
480
+ const { columns } = template;
481
+ if (columns && columns.length) {
482
+ columns.forEach((column = {}, index) => {
483
+ const {
484
+ action: {
485
+ label,
486
+ text,
487
+ type,
488
+ uri,
489
+ } = {},
490
+ imageUrl,
491
+ } = column;
492
+
493
+ validCarouselImages.push({
494
+ activeIndex: index,
495
+ originalContentUrl: imageUrl,
496
+ selectedActionType: type ? (type === MESSAGE_ACTION_TYPE ? TEXT_ACTION_TYPE : URL_ACTION_TYPE) : '',
497
+ actionContent: text || uri,
498
+ actionLabel: label,
499
+ type: 'carousel',
500
+ });
501
+ })
502
+
503
+ }
504
+ }
505
+ updateCarouselImage(validCarouselImages);
506
+
412
507
  updateSelectedTemplate(template);
413
508
  updateTitle(altText);
414
509
  updateTemplateDrawerRequirement(false);
@@ -37,7 +37,7 @@ export default defineMessages({
37
37
  },
38
38
  "imageDimenstionDescription": {
39
39
  id: `${scope}.imageDimenstionDescription`,
40
- defaultMessage: 'Format: JPEG, PNG Aspect Ratio: 1:1 Dimensions: 1024px x 1024px Size: 1 MB',
40
+ defaultMessage: 'Format: JPEG, PNG Dimensions: 1024px x 1024px Size: 1 MB',
41
41
  },
42
42
  "imageReUpload": {
43
43
  id: `${scope}.imageReUpload`,
@@ -6,7 +6,7 @@ import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
6
6
  import CapModal from '@capillarytech/cap-ui-library/CapModal';
7
7
  import style, { CapModalStyles } from './style';
8
8
  import withStyles from '../../../../hoc/withStyles';
9
- import { TEXT, IMAGE, IMAGE_MAP, STICKER, MAX_LINE_WRAPPER_LIMIT, MAX_LINE_WRAPPER_LIMIT_FULL_MODE } from '../constants';
9
+ import { TEXT, TEMPLATE } from '../constants';
10
10
  import { getTabPanes } from './utils';
11
11
  import messages from './messages';
12
12
  import { CAP_SPACE_16, CAP_SPACE_08 } from '@capillarytech/cap-ui-library/styled/variables';
@@ -30,7 +30,7 @@ export const LineWrapper = ({
30
30
  const [isConfirmModalVisible, togglePopup] = useState(false);
31
31
 
32
32
  useEffect(() => {
33
- updateActiveKey(selectedType);
33
+ updateActiveKey(selectedType === 'template' ? TEMPLATE : selectedType);
34
34
  }, [selectedType]);
35
35
 
36
36
  const onTabChange = (type) => {
@@ -43,8 +43,8 @@ export default defineMessages({
43
43
  id: `${scope}.imagemapLabel`,
44
44
  defaultMessage: 'Rich message',
45
45
  },
46
- "templateLabel": {
47
- id: `${scope}.templateLabel`,
46
+ "flexLabel": {
47
+ id: `${scope}.flexLabel`,
48
48
  defaultMessage: 'Card message',
49
49
  },
50
50
  "videoLabel": {
@@ -3,7 +3,7 @@ export const STICKER = 'sticker';
3
3
  export const IMAGE = 'image';
4
4
  export const IMAGE_MAP = 'imagemap';
5
5
  export const IMAGE_CAROUSEL = 'image_carousel';
6
- export const TEMPLATE = 'template';
6
+ export const TEMPLATE = 'flex';
7
7
  export const VIDEO = 'video';
8
8
  export const MAX_LINE_WRAPPER_LIMIT = 5;
9
9
  export const MAX_LINE_WRAPPER_LIMIT_FULL_MODE = 1;
@@ -115,7 +115,13 @@ export const LineContainer = ({
115
115
  const selectedTemplate = get(Line, 'templateDetails.selectedTemplate');
116
116
  const assetType = get(Line, 'templateDetails.assetType');
117
117
  const actionLinks = get(Line, 'templateDetails.actionLinks');
118
- const template = get(Line, `templateDetails.versions.base.content.messages.0.template`);
118
+ const templateType = get(Line, `templateDetails.versions.base.content.messages.0.type`);
119
+ let template = "";
120
+ if (templateType === "flex") {
121
+ template = get(Line, `templateDetails.versions.base.content.messages.0.contents`);
122
+ } else {
123
+ template = get(Line, `templateDetails.versions.base.content.messages.0.template`);
124
+ }
119
125
  const video = get(Line, `templateDetails.versions.base.content.messages.0.video`);
120
126
  const videoName = get(Line, `templateDetails.versions.base.content.messages.0.videoName`);
121
127
  const videoDuration = get(Line, `templateDetails.versions.base.content.messages.0.videoDuration`);
@@ -202,6 +208,7 @@ export const LineContainer = ({
202
208
  lineContent.push(obj);
203
209
  });
204
210
  updateLineWrapperContent(lineContent);
211
+
205
212
  }
206
213
  }, [templateData]);
207
214
 
@@ -294,7 +301,6 @@ export const LineContainer = ({
294
301
  if (supportedTags) {
295
302
  tags = supportedTags;
296
303
  }
297
-
298
304
  return (
299
305
  <LineWrapper
300
306
  id={`${lineWrapperContent.type}__${index}`}
@@ -387,7 +393,7 @@ export const LineContainer = ({
387
393
  videoWidth,
388
394
  } = {}] = lineWrapperContents;
389
395
  let messageData = { type };
390
- messageData[messageType] = messageContent;
396
+ if (messageType && messageContent) messageData[messageType] = messageContent;
391
397
  if (previewImageUrl) {
392
398
  messageData.previewImageUrl = previewImageUrl;
393
399
  }
@@ -407,9 +413,36 @@ export const LineContainer = ({
407
413
  if (baseSize) {
408
414
  messageData.baseSize = baseSize;
409
415
  }
416
+
410
417
  if (template) {
411
- messageData.template = template;
418
+ messageData.type = "flex";
412
419
  messageData.altText = altText;
420
+ messageData.contents = {};
421
+ const imageContents = (template?.columns || []).map((item) => {
422
+ return {
423
+ type: 'bubble',
424
+ hero: {
425
+ type: 'image',
426
+ url: item.imageUrl,
427
+ size: 'full',
428
+ aspectRatio: item.aspectRatio,
429
+ aspectMode: 'cover',
430
+ },
431
+ footer: {
432
+ type: 'box',
433
+ layout: 'vertical',
434
+ spacing: 'xs',
435
+ contents: [{
436
+ type: 'button',
437
+ style: 'link',
438
+ height: 'sm',
439
+ action: item.action,
440
+ }],
441
+ },
442
+ };
443
+ });
444
+ messageData.contents.contents = imageContents;
445
+ messageData.contents.type = "carousel";
413
446
  }
414
447
  if (videoSrc) {
415
448
  delete messageData.previewImageUrl;
@@ -513,7 +546,33 @@ export const LineContainer = ({
513
546
  messageData.actionLinks = actionLinks;
514
547
  }
515
548
  if (template) {
516
- messageData.template = template;
549
+ let contentsLocal = {};
550
+ const imageContents = (template?.columns || []).map((item) => {
551
+ return {
552
+ type: 'bubble',
553
+ hero: {
554
+ type: 'image',
555
+ url: item.imageUrl,
556
+ size: 'full',
557
+ aspectRatio: item.aspectRatio,
558
+ aspectMode: 'cover',
559
+ },
560
+ footer: {
561
+ type: 'box',
562
+ layout: 'vertical',
563
+ spacing: 'xs',
564
+ contents: [{
565
+ type: 'button',
566
+ style: 'link',
567
+ height: 'sm',
568
+ action: item.action,
569
+ }],
570
+ },
571
+ };
572
+ });
573
+ contentsLocal.contents = imageContents;
574
+ contentsLocal.type = "carousel";
575
+ messageData.template = contentsLocal;
517
576
  messageData.altText = altText;
518
577
  }
519
578
  if (videoSrc) {
@@ -595,7 +654,21 @@ export const LineContainer = ({
595
654
 
596
655
  const getPreviewSection = () => {
597
656
  const accountName = get(lineData, 'selectedLineAccount.name', '');
598
- const templateContent = lineWrapperContents.map(({ messageContent, type, previewImageUrl, selectedSticker, baseUrl, template, videoSrc, actionUrl }) => ({
657
+ const templateContent = lineWrapperContents.map(({ messageContent, type, previewImageUrl, selectedSticker, baseUrl, template, videoSrc, actionUrl }) => {
658
+ const isNewLineFormat = template && isEmpty(template.columns) && !isEmpty(template.contents);
659
+ let imageCarousel = [];
660
+ if (isNewLineFormat) {
661
+ imageCarousel = get(template, 'contents', [{}]).map(({
662
+ hero: { url = ''} = {},
663
+ footer: { contents: [{ action: { label = '' } = {} }] = [{}] } = {},
664
+ }) => ({
665
+ imageUrl: url,
666
+ actionLabel: label,
667
+ }));
668
+ } else {
669
+ imageCarousel = get(template, 'columns', [{}]).map(({ imageUrl, action: { label: actionLabel } = {} }) => ({ imageUrl, actionLabel }) );
670
+ }
671
+ return {
599
672
  messageContent,
600
673
  previewImageUrl,
601
674
  selectedSticker,
@@ -603,9 +676,9 @@ export const LineContainer = ({
603
676
  baseUrl,
604
677
  video: videoSrc,
605
678
  actionUrl,
606
- imageCarousel: get(template, 'columns', [{}]).map(({ imageUrl, action: { label: actionLabel } = {} }) => ({ imageUrl, actionLabel }) ),
607
- }));
608
-
679
+ imageCarousel,
680
+ };
681
+ });
609
682
  return (
610
683
  <TemplatePreview
611
684
  channel="LINE"
@@ -846,7 +846,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
846
846
  );
847
847
 
848
848
  getTemplateDataForGrid = ({templates, handlers, filterContent, channel, isLoading, loadingTip}) => {
849
- const currentChannel = channel.toUpperCase();
849
+ const currentChannel = channel.toUpperCase();
850
850
  const {channel: stateChannel} = this.state;
851
851
  const channelLowerCase = stateChannel.toLowerCase();
852
852
  let filteredTemplates = templates;
@@ -868,7 +868,6 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
868
868
  default:
869
869
  break;
870
870
  }
871
-
872
871
  const hoverButtonText =
873
872
  this.props.intl.formatMessage(
874
873
  this.props.isFullMode
@@ -979,48 +978,62 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
979
978
  const {
980
979
  content: {
981
980
  messages: [{
982
- text = '',
983
- originalContentUrl = '',
984
- stickerUrl = '',
985
- animatedStickerUrl = '',
986
- baseUrl = '',
987
- template: carouselTemplate,
988
- video: {
989
- originalContentUrl: originalVideoContentUrl,
981
+ type = '',
982
+ contents: {
983
+ contents = [],
990
984
  } = {},
991
- }] = [{}],
985
+ } = {}] = [],
992
986
  } = {},
993
987
  } = template.versions.base;
994
- templateData.content = text;
995
- templateData.url = originalContentUrl || animatedStickerUrl || stickerUrl || (baseUrl ? `${baseUrl}/1040` : '');
996
- if (originalVideoContentUrl) {
997
- templateData.content = (
998
- <video height="279">
999
- <source src={originalVideoContentUrl} type="video/mp4" />
1000
- </video>
1001
- );
1002
- }
1003
- if (carouselTemplate) {
1004
- const carouselContent = get(carouselTemplate, 'columns', [{}]).map(({ imageUrl, action: { label: actionLabel } = {} }) => ({ imageUrl, actionLabel }) );
1005
- templateData.content = (
1006
- <div style={{ display: 'flex'}}>
1007
- {
1008
- carouselContent.map(({
1009
- imageUrl,
1010
- actionLabel,
1011
- }) => (
1012
- <img
1013
- width={208}
1014
- height={279}
1015
- src={imageUrl}
1016
- alt={actionLabel}
1017
- key={`${imageUrl}_${actionLabel}`}
1018
- />
1019
- ))
1020
- }
1021
- </div>
1022
- );
1023
- templateData.className = 'carousel-img-section';
988
+ if (type === 'flex') {
989
+ templateData.url = contents[0]?.hero?.url;
990
+ } else {
991
+ const {
992
+ content: {
993
+ messages: [{
994
+ text = '',
995
+ originalContentUrl = '',
996
+ stickerUrl = '',
997
+ animatedStickerUrl = '',
998
+ baseUrl = '',
999
+ template: carouselTemplate,
1000
+ video: {
1001
+ originalContentUrl: originalVideoContentUrl,
1002
+ } = {},
1003
+ }] = [{}],
1004
+ } = {},
1005
+ } = template.versions.base;
1006
+ templateData.content = text;
1007
+ templateData.url = originalContentUrl || animatedStickerUrl || stickerUrl || (baseUrl ? `${baseUrl}/1040` : '');
1008
+ if (originalVideoContentUrl) {
1009
+ templateData.content = (
1010
+ <video height="279">
1011
+ <source src={originalVideoContentUrl} type="video/mp4" />
1012
+ </video>
1013
+ );
1014
+ }
1015
+ if (carouselTemplate) {
1016
+ const carouselContent = get(carouselTemplate, 'columns', [{}]).map(({ imageUrl, action: { label: actionLabel } = {} }) => ({ imageUrl, actionLabel }) );
1017
+ templateData.content = (
1018
+ <div style={{ display: 'flex'}}>
1019
+ {
1020
+ carouselContent.map(({
1021
+ imageUrl,
1022
+ actionLabel,
1023
+ }) => (
1024
+ <img
1025
+ width={208}
1026
+ height={279}
1027
+ src={imageUrl}
1028
+ alt={actionLabel}
1029
+ key={`${imageUrl}_${actionLabel}`}
1030
+ />
1031
+ ))
1032
+ }
1033
+ </div>
1034
+ );
1035
+ templateData.className = 'carousel-img-section';
1036
+ }
1024
1037
  }
1025
1038
  break;
1026
1039
  }
@@ -1069,6 +1082,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1069
1082
  }
1070
1083
  return templateData;
1071
1084
  }) : [];
1085
+
1072
1086
  const accountId = get(this.props, 'Templates.selectedWeChatAccount.uuid');
1073
1087
  const accounts = get(this.props, 'Templates.weCrmAccounts');
1074
1088
  const noWhatsappTemplates = this.isFullMode() && isEmpty(templates);
@@ -1191,6 +1191,14 @@ export default {
1191
1191
  channel: 'RCS',
1192
1192
  validity: true,
1193
1193
  },
1194
+ lineEditTemplateData: {
1195
+ mode: 'edit',
1196
+ _id: '629f7ecf134738019b2e332e',
1197
+ modeType: '',
1198
+ type: 'LINE',
1199
+ channel: 'LINE',
1200
+ validity: true,
1201
+ },
1194
1202
  getWhatsappContentOutput: '1234567890\nClick {{unsubscribe}} to unsubscribe',
1195
1203
  getWhatsappStatusOutput: {
1196
1204
  key: 'approved',
@@ -1422,4 +1430,64 @@ export default {
1422
1430
  language: {
1423
1431
  localeLoading: false,
1424
1432
  },
1433
+ linePreviewTemplateData: {
1434
+ mode: 'preview',
1435
+ _id: '629f7ecf134738019b2e332e',
1436
+ name: 'ggg1',
1437
+ type: 'LINE',
1438
+ versions: {
1439
+ history: [],
1440
+ base: {
1441
+ content: {
1442
+ to: '{{line_id}}',
1443
+ messages: [
1444
+ {
1445
+ type: 'flex',
1446
+ altText: 'ggg',
1447
+ contents: {
1448
+ contents: [
1449
+ {
1450
+ type: 'bubble',
1451
+ hero: {
1452
+ type: 'image',
1453
+ url: 'https://crm-nightly-new-fileservice.s3.amazonaws.com/intouch_creative_assets/b9f2aa7a-3f1a-4a20-a737-8d50841.jpeg',
1454
+ size: 'full',
1455
+ aspectRatio: '1:1',
1456
+ aspectMode: 'cover',
1457
+ },
1458
+ footer: {
1459
+ type: 'box',
1460
+ layout: 'vertical',
1461
+ spacing: 'xs',
1462
+ contents: [
1463
+ {
1464
+ type: 'button',
1465
+ style: 'link',
1466
+ height: 'sm',
1467
+ action: {
1468
+ type: 'message',
1469
+ label: 'ggg',
1470
+ text: 'ggg',
1471
+ },
1472
+ },
1473
+ ],
1474
+ },
1475
+ },
1476
+ ],
1477
+ type: "carousel",
1478
+ },
1479
+ },
1480
+ ],
1481
+ },
1482
+ },
1483
+ },
1484
+ isActive: true,
1485
+ orgId: 1604,
1486
+ createdBy: '15000449',
1487
+ updatedBy: '15000449',
1488
+ createdAt: '2022-06-07T16:37:35.447Z',
1489
+ updatedAt: '2022-06-07T16:42:02.243Z',
1490
+ totalCount: 31,
1491
+ updatedByName: 'Ashish Karan fd',
1492
+ },
1425
1493
  };