@capillarytech/creatives-library 8.0.242-alpha.12 → 8.0.242-alpha.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.242-alpha.12",
4
+ "version": "8.0.242-alpha.14",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -142,7 +142,7 @@ function CapImageUrlUpload(props) {
142
142
 
143
143
  img.src = objectUrl;
144
144
  });
145
- } catch (error) {
145
+ } catch (err) {
146
146
  setIsValidating(false);
147
147
  return {
148
148
  isValid: false,
@@ -37,7 +37,7 @@ export default defineMessages({
37
37
  },
38
38
  sizeLimit: {
39
39
  id: `${scope}.sizeLimit`,
40
- defaultMessage: 'Size upto: {size}',
40
+ defaultMessage: 'Size up to: {size}',
41
41
  },
42
42
  formatTypes: {
43
43
  id: `${scope}.formatTypes`,
@@ -348,7 +348,7 @@ export default defineMessages({
348
348
  },
349
349
  "newWebPushTemplate": {
350
350
  id: `${scope}.newWebPushTemplate`,
351
- defaultMessage: 'Add new Web push {template}',
351
+ defaultMessage: 'Add new Web Push {template}',
352
352
  },
353
353
  "newInAppMessageTemplate": {
354
354
  id: `${scope}.newInAppMessageTemplate`,
@@ -388,7 +388,7 @@ export default defineMessages({
388
388
  },
389
389
  "webPushTitleIllustration": {
390
390
  id: `${scope}.webPushTitleIllustration`,
391
- defaultMessage: 'Add a new Web push creative {template}',
391
+ defaultMessage: 'Add a new Web Push creative {template}',
392
392
  },
393
393
  "webPushDescIllustration": {
394
394
  id: `${scope}.webPushDescIllustration`,
@@ -480,7 +480,7 @@ export default defineMessages({
480
480
  },
481
481
  "webpushAccount": {
482
482
  id: `${scope}.webpushAccount`,
483
- defaultMessage: 'Web push account',
483
+ defaultMessage: 'Web Push account',
484
484
  },
485
485
  "rcsAccount": {
486
486
  id: `${scope}.rcsAccount`,
@@ -520,7 +520,7 @@ export default defineMessages({
520
520
  },
521
521
  "noAccountsPresentWebpush": {
522
522
  id: `${scope}.noAccountsPresentWebpush`,
523
- defaultMessage: "Web push accounts are not setup for your brand",
523
+ defaultMessage: "Web Push accounts are not setup for your brand",
524
524
  },
525
525
  "noAccountsPresentRcs": {
526
526
  id: `${scope}.noAccountsPresentRcs`,
@@ -125,7 +125,9 @@ function templatesReducer(state = initialState, action) {
125
125
  .set('selectedFacebookAccount', fromJS(action.faceBookAccount))
126
126
  .set('templates', []);
127
127
  case types.SET_WEBPUSH_ACCOUNT:
128
- return state.set('selectedWebPushAccount', fromJS(action.account));
128
+ return state
129
+ .set('selectedWebPushAccount', fromJS(action.account))
130
+ .set('templates', []);
129
131
  case types.RESET_ACCOUNT:
130
132
  return state
131
133
  .remove('selectedWeChatAccount')
@@ -18,7 +18,7 @@ const ButtonItem = ({
18
18
  const handleDragStart = (e) => {
19
19
  if (disabled) return;
20
20
  e.dataTransfer.effectAllowed = 'move';
21
- e.dataTransfer.setData('text/html', e.currentTarget);
21
+ e.dataTransfer.setData('text/plain', String(index));
22
22
  onDragStart(index);
23
23
  };
24
24
 
@@ -1,20 +1,12 @@
1
1
  import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { FormattedMessage } from 'react-intl';
4
- import CapRow from '@capillarytech/cap-ui-library/CapRow';
5
- import CapButton from '@capillarytech/cap-ui-library/CapButton';
6
3
  import ButtonItem from './ButtonItem';
7
- import messages from '../messages';
8
4
 
9
5
  const ButtonList = ({
10
6
  buttons,
11
7
  onEdit,
12
8
  onDelete,
13
9
  onReorder,
14
- onAddPrimary,
15
- onAddSecondary,
16
- showAddPrimary,
17
- showAddSecondary,
18
10
  disabled,
19
11
  disableSecondaryButton,
20
12
  isInlineFormVisible,
@@ -82,32 +74,6 @@ const ButtonList = ({
82
74
  />
83
75
  );
84
76
  })}
85
- {showAddPrimary && (
86
- <CapRow className="button-list-add-button">
87
- <CapButton
88
- type="flat"
89
- onClick={onAddPrimary}
90
- className="add-primary-button button-add-trigger"
91
- icon="plus"
92
- disabled={disabled}
93
- >
94
- <FormattedMessage {...messages.addPrimaryButton} />
95
- </CapButton>
96
- </CapRow>
97
- )}
98
- {showAddSecondary && (
99
- <CapRow className="button-list-add-button">
100
- <CapButton
101
- type="flat"
102
- onClick={onAddSecondary}
103
- className="add-secondary-button button-add-trigger"
104
- icon="plus"
105
- disabled={disableSecondaryButton || disabled}
106
- >
107
- <FormattedMessage {...messages.addSecondaryButton} />
108
- </CapButton>
109
- </CapRow>
110
- )}
111
77
  </div>
112
78
  );
113
79
  };
@@ -122,10 +88,6 @@ ButtonList.propTypes = {
122
88
  onEdit: PropTypes.func.isRequired,
123
89
  onDelete: PropTypes.func.isRequired,
124
90
  onReorder: PropTypes.func.isRequired,
125
- onAddPrimary: PropTypes.func.isRequired,
126
- onAddSecondary: PropTypes.func.isRequired,
127
- showAddPrimary: PropTypes.bool.isRequired,
128
- showAddSecondary: PropTypes.bool.isRequired,
129
91
  disabled: PropTypes.bool,
130
92
  disableSecondaryButton: PropTypes.bool,
131
93
  isInlineFormVisible: PropTypes.bool,
@@ -94,10 +94,6 @@ export const ButtonsLinksSection = ({
94
94
  onEdit={handleButtonEdit}
95
95
  onDelete={handleButtonDelete}
96
96
  onReorder={handleButtonReorder}
97
- onAddPrimary={handleAddPrimaryButton}
98
- onAddSecondary={handleAddSecondaryButton}
99
- showAddPrimary={false}
100
- showAddSecondary={false}
101
97
  disabled={isAddFlow}
102
98
  disableSecondaryButton={disableSecondaryAddButton}
103
99
  isInlineFormVisible={isEditFlow}
@@ -355,14 +355,27 @@ describe('ButtonsLinksSection', () => {
355
355
  });
356
356
 
357
357
  it('should render disabled secondary button when showDisabledSecondaryDuringPrimary is true', () => {
358
+ const handleAddPrimaryButton = jest.fn();
359
+ const handleAddSecondaryButton = jest.fn();
358
360
  const buttonState = createMockButtonState({
359
361
  showDisabledSecondaryDuringPrimary: true,
362
+ handleAddPrimaryButton,
363
+ handleAddSecondaryButton,
360
364
  });
361
365
  const wrapper = mountWithIntl(
362
366
  <ButtonsLinksSection {...defaultProps} buttonState={buttonState} />
363
367
  );
364
- const addButton = wrapper.find(CapButton).find('.add-secondary-button');
368
+ const addButton = wrapper.find(CapButton).filterWhere(btn => btn.hasClass('add-secondary-button')).first();
365
369
  expect(addButton.exists()).toBe(true);
370
+ expect(addButton.prop('disabled')).toBe(true);
371
+
372
+ // Simulate click on the disabled button
373
+ addButton.simulate('click');
374
+ wrapper.update();
375
+
376
+ // Verify the callbacks are not called when disabled
377
+ expect(handleAddPrimaryButton).not.toHaveBeenCalled();
378
+ expect(handleAddSecondaryButton).not.toHaveBeenCalled();
366
379
  });
367
380
 
368
381
  it('should call handleAddPrimaryButton when add primary button is clicked', () => {
@@ -59,7 +59,7 @@ export const MediaSection = ({
59
59
  options={WEBPUSH_MEDIA_TYPES_OPTIONS}
60
60
  value={mediaType}
61
61
  onChange={onMediaTypeChange}
62
- disabled={isAnyUploadActive}
62
+ disabled={isAnyUploadActive || isLocked}
63
63
  />
64
64
  </CapRow>
65
65
  {mediaType === WEBPUSH_MEDIA_TYPES.IMAGE && (
@@ -85,6 +85,7 @@ export const MediaSection = ({
85
85
  channel={WEBPUSH}
86
86
  showReUploadButton
87
87
  recommendedDimensions={WEBPUSH_RECOMMENDED_DIMENSIONS}
88
+ disabled={isLocked}
88
89
  />
89
90
  </CapRow>
90
91
  )}
@@ -72,14 +72,10 @@ exports[`ButtonsLinksSection Rendering should render correctly with default prop
72
72
  disabled={false}
73
73
  inlineFormIndex={null}
74
74
  isInlineFormVisible={false}
75
- onAddPrimary={[MockFunction]}
76
- onAddSecondary={[MockFunction]}
77
75
  onDelete={[MockFunction]}
78
76
  onEdit={[MockFunction]}
79
77
  onReorder={[MockFunction]}
80
78
  renderInlineForm={null}
81
- showAddPrimary={false}
82
- showAddSecondary={false}
83
79
  />
84
80
  </CapRow>
85
81
  </Fragment>
@@ -213,7 +213,7 @@ describe('ButtonItem', () => {
213
213
 
214
214
  container.simulate('dragStart', mockEvent);
215
215
 
216
- expect(mockEvent.dataTransfer.setData).toHaveBeenCalledWith('text/html', mockEvent.currentTarget);
216
+ expect(mockEvent.dataTransfer.setData).toHaveBeenCalledWith('text/plain', '0');
217
217
  });
218
218
 
219
219
  it('should not call onDragStart when disabled is true', () => {
@@ -1,9 +1,8 @@
1
- import React, { act } from 'react';
1
+ import React from 'react';
2
+ import { act } from 'react-dom/test-utils';
2
3
  import { mountWithIntl, shallowWithIntl } from '../../../../../helpers/intl-enzym-test-helpers';
3
- import CapButton from '@capillarytech/cap-ui-library/CapButton';
4
4
  import ButtonList from '../ButtonList';
5
5
  import ButtonItem from '../ButtonItem';
6
- import messages from '../../messages';
7
6
 
8
7
  // Mock ButtonItem component
9
8
  jest.mock('../ButtonItem', () => {
@@ -75,13 +74,11 @@ describe('ButtonList', () => {
75
74
  const mockOnEdit = jest.fn();
76
75
  const mockOnDelete = jest.fn();
77
76
  const mockOnReorder = jest.fn();
78
- const mockOnAddPrimary = jest.fn();
79
- const mockOnAddSecondary = jest.fn();
80
77
  const mockRenderInlineForm = jest.fn(() => <div className="inline-form">Inline Form</div>);
81
78
 
82
79
  const mockButtons = [
83
- { text: 'Primary Button', url: 'https://example.com', type: 'primary' },
84
- { text: 'Secondary Button', url: 'https://example2.com', type: 'secondary' },
80
+ { id: 'btn-1', text: 'Primary Button', url: 'https://example.com', type: 'primary' },
81
+ { id: 'btn-2', text: 'Secondary Button', url: 'https://example2.com', type: 'secondary' },
85
82
  ];
86
83
 
87
84
  const defaultProps = {
@@ -89,10 +86,6 @@ describe('ButtonList', () => {
89
86
  onEdit: mockOnEdit,
90
87
  onDelete: mockOnDelete,
91
88
  onReorder: mockOnReorder,
92
- onAddPrimary: mockOnAddPrimary,
93
- onAddSecondary: mockOnAddSecondary,
94
- showAddPrimary: true,
95
- showAddSecondary: true,
96
89
  disabled: false,
97
90
  disableSecondaryButton: false,
98
91
  isInlineFormVisible: false,
@@ -135,133 +128,6 @@ describe('ButtonList', () => {
135
128
  });
136
129
  });
137
130
 
138
- describe('Add Primary Button', () => {
139
- it('should render add primary button when showAddPrimary is true', () => {
140
- const wrapper = mountWithIntl(<ButtonList {...defaultProps} showAddPrimary={true} />);
141
- const addPrimaryButton = wrapper.find(CapButton).findWhere(
142
- (node) => node.prop('className') === 'add-primary-button button-add-trigger'
143
- );
144
-
145
- expect(addPrimaryButton.exists()).toBe(true);
146
- });
147
-
148
- it('should not render add primary button when showAddPrimary is false', () => {
149
- const wrapper = mountWithIntl(<ButtonList {...defaultProps} showAddPrimary={false} />);
150
- const addPrimaryButton = wrapper.find(CapButton).findWhere(
151
- (node) => node.prop('className') === 'add-primary-button button-add-trigger'
152
- );
153
-
154
- expect(addPrimaryButton.exists()).toBe(false);
155
- });
156
-
157
- it('should call onAddPrimary when add primary button is clicked', () => {
158
- const wrapper = mountWithIntl(<ButtonList {...defaultProps} showAddPrimary={true} />);
159
- const addPrimaryButton = wrapper.find(CapButton).findWhere(
160
- (node) => node.prop('className') === 'add-primary-button button-add-trigger'
161
- ).first();
162
-
163
- addPrimaryButton.prop('onClick')();
164
-
165
- expect(mockOnAddPrimary).toHaveBeenCalledTimes(1);
166
- });
167
-
168
- it('should disable add primary button when disabled prop is true', () => {
169
- const wrapper = mountWithIntl(
170
- <ButtonList {...defaultProps} showAddPrimary={true} disabled={true} />
171
- );
172
- const addPrimaryButton = wrapper.find(CapButton).findWhere(
173
- (node) => node.prop('className') === 'add-primary-button button-add-trigger'
174
- ).first();
175
-
176
- expect(addPrimaryButton.prop('disabled')).toBe(true);
177
- });
178
-
179
- it('should not call onAddPrimary when button is disabled and clicked', () => {
180
- const wrapper = mountWithIntl(
181
- <ButtonList {...defaultProps} showAddPrimary={true} disabled={true} />
182
- );
183
- const addPrimaryButton = wrapper.find(CapButton).findWhere(
184
- (node) => node.prop('className') === 'add-primary-button button-add-trigger'
185
- ).first();
186
-
187
- // Even if we try to call onClick, it should be disabled
188
- expect(addPrimaryButton.prop('disabled')).toBe(true);
189
- });
190
- });
191
-
192
- describe('Add Secondary Button', () => {
193
- it('should render add secondary button when showAddSecondary is true', () => {
194
- const wrapper = mountWithIntl(<ButtonList {...defaultProps} showAddSecondary={true} />);
195
- const addSecondaryButton = wrapper.find(CapButton).findWhere(
196
- (node) => node.prop('className') === 'add-secondary-button button-add-trigger'
197
- );
198
-
199
- expect(addSecondaryButton.exists()).toBe(true);
200
- });
201
-
202
- it('should not render add secondary button when showAddSecondary is false', () => {
203
- const wrapper = mountWithIntl(<ButtonList {...defaultProps} showAddSecondary={false} />);
204
- const addSecondaryButton = wrapper.find(CapButton).findWhere(
205
- (node) => node.prop('className') === 'add-secondary-button button-add-trigger'
206
- );
207
-
208
- expect(addSecondaryButton.exists()).toBe(false);
209
- });
210
-
211
- it('should call onAddSecondary when add secondary button is clicked', () => {
212
- const wrapper = mountWithIntl(<ButtonList {...defaultProps} showAddSecondary={true} />);
213
- const addSecondaryButton = wrapper.find(CapButton).findWhere(
214
- (node) => node.prop('className') === 'add-secondary-button button-add-trigger'
215
- ).first();
216
-
217
- addSecondaryButton.prop('onClick')();
218
-
219
- expect(mockOnAddSecondary).toHaveBeenCalledTimes(1);
220
- });
221
-
222
- it('should disable add secondary button when disabled prop is true', () => {
223
- const wrapper = mountWithIntl(
224
- <ButtonList {...defaultProps} showAddSecondary={true} disabled={true} />
225
- );
226
- const addSecondaryButton = wrapper.find(CapButton).findWhere(
227
- (node) => node.prop('className') === 'add-secondary-button button-add-trigger'
228
- ).first();
229
-
230
- expect(addSecondaryButton.prop('disabled')).toBe(true);
231
- });
232
-
233
- it('should disable add secondary button when disableSecondaryButton prop is true', () => {
234
- const wrapper = mountWithIntl(
235
- <ButtonList
236
- {...defaultProps}
237
- showAddSecondary={true}
238
- disableSecondaryButton={true}
239
- />
240
- );
241
- const addSecondaryButton = wrapper.find(CapButton).findWhere(
242
- (node) => node.prop('className') === 'add-secondary-button button-add-trigger'
243
- ).first();
244
-
245
- expect(addSecondaryButton.prop('disabled')).toBe(true);
246
- });
247
-
248
- it('should disable add secondary button when both disabled and disableSecondaryButton are true', () => {
249
- const wrapper = mountWithIntl(
250
- <ButtonList
251
- {...defaultProps}
252
- showAddSecondary={true}
253
- disabled={true}
254
- disableSecondaryButton={true}
255
- />
256
- );
257
- const addSecondaryButton = wrapper.find(CapButton).findWhere(
258
- (node) => node.prop('className') === 'add-secondary-button button-add-trigger'
259
- ).first();
260
-
261
- expect(addSecondaryButton.prop('disabled')).toBe(true);
262
- });
263
- });
264
-
265
131
  describe('Edit Button', () => {
266
132
  it('should call onEdit with correct index when edit is clicked on primary button', () => {
267
133
  const wrapper = mountWithIntl(<ButtonList {...defaultProps} />);
@@ -291,6 +157,14 @@ describe('ButtonList', () => {
291
157
 
292
158
  // ButtonItem should be disabled, so onEdit should not be called
293
159
  expect(firstButtonItem.prop('disabled')).toBe(true);
160
+
161
+ // Simulate click on the edit button - the onClick handler checks disabled state
162
+ const editButton = wrapper.find('.edit-button').first();
163
+ editButton.simulate('click');
164
+ wrapper.update();
165
+
166
+ // Verify the callback is not called when disabled
167
+ expect(mockOnEdit).not.toHaveBeenCalled();
294
168
  });
295
169
  });
296
170
 
@@ -313,6 +187,14 @@ describe('ButtonList', () => {
313
187
 
314
188
  // ButtonItem should be disabled, so onDelete should not be called
315
189
  expect(firstButtonItem.prop('disabled')).toBe(true);
190
+
191
+ // Simulate click on the delete button - the onClick handler checks disabled state
192
+ const deleteButton = wrapper.find('.delete-button').first();
193
+ deleteButton.simulate('click');
194
+ wrapper.update();
195
+
196
+ // Verify the callback is not called when disabled
197
+ expect(mockOnDelete).not.toHaveBeenCalled();
316
198
  });
317
199
  });
318
200
 
@@ -606,8 +488,8 @@ describe('ButtonList', () => {
606
488
  describe('Button Item Props', () => {
607
489
  it('should pass correct button data to ButtonItem', () => {
608
490
  const customButtons = [
609
- { text: 'Custom Primary', url: 'https://custom1.com', type: 'primary' },
610
- { text: 'Custom Secondary', url: 'https://custom2.com', type: 'secondary' },
491
+ { id: 'btn-3', text: 'Custom Primary', url: 'https://custom1.com', type: 'primary' },
492
+ { id: 'btn-4', text: 'Custom Secondary', url: 'https://custom2.com', type: 'secondary' },
611
493
  ];
612
494
  const wrapper = mountWithIntl(
613
495
  <ButtonList {...defaultProps} buttons={customButtons} />
@@ -7,6 +7,7 @@ exports[`ButtonList Rendering should render correctly with default props 1`] = `
7
7
  <MockButtonItem
8
8
  button={
9
9
  Object {
10
+ "id": "btn-1",
10
11
  "text": "Primary Button",
11
12
  "type": "primary",
12
13
  "url": "https://example.com",
@@ -14,6 +15,7 @@ exports[`ButtonList Rendering should render correctly with default props 1`] = `
14
15
  }
15
16
  disabled={false}
16
17
  index={0}
18
+ key="btn-1"
17
19
  onDelete={[MockFunction]}
18
20
  onDragEnd={[Function]}
19
21
  onDragOver={[Function]}
@@ -24,6 +26,7 @@ exports[`ButtonList Rendering should render correctly with default props 1`] = `
24
26
  <MockButtonItem
25
27
  button={
26
28
  Object {
29
+ "id": "btn-2",
27
30
  "text": "Secondary Button",
28
31
  "type": "secondary",
29
32
  "url": "https://example2.com",
@@ -31,6 +34,7 @@ exports[`ButtonList Rendering should render correctly with default props 1`] = `
31
34
  }
32
35
  disabled={false}
33
36
  index={1}
37
+ key="btn-2"
34
38
  onDelete={[MockFunction]}
35
39
  onDragEnd={[Function]}
36
40
  onDragOver={[Function]}
@@ -38,41 +42,5 @@ exports[`ButtonList Rendering should render correctly with default props 1`] = `
38
42
  onDrop={[Function]}
39
43
  onEdit={[MockFunction]}
40
44
  />
41
- <CapRow
42
- className="button-list-add-button"
43
- >
44
- <CapButton
45
- className="add-primary-button button-add-trigger"
46
- disabled={false}
47
- icon="plus"
48
- isAddBtn={false}
49
- onClick={[MockFunction]}
50
- type="flat"
51
- >
52
- <FormattedMessage
53
- defaultMessage="Add primary button"
54
- id="creatives.containersV2.WebPush.addPrimaryButton"
55
- values={Object {}}
56
- />
57
- </CapButton>
58
- </CapRow>
59
- <CapRow
60
- className="button-list-add-button"
61
- >
62
- <CapButton
63
- className="add-secondary-button button-add-trigger"
64
- disabled={false}
65
- icon="plus"
66
- isAddBtn={false}
67
- onClick={[MockFunction]}
68
- type="flat"
69
- >
70
- <FormattedMessage
71
- defaultMessage="Add secondary button"
72
- id="creatives.containersV2.WebPush.addSecondaryButton"
73
- values={Object {}}
74
- />
75
- </CapButton>
76
- </CapRow>
77
45
  </div>
78
46
  `;
@@ -58,6 +58,18 @@ export const useButtonManagement = (initialButtons = []) => {
58
58
 
59
59
  const handleButtonEdit = useCallback(
60
60
  (index) => {
61
+ if (
62
+ typeof index !== 'number' ||
63
+ !Number.isInteger(index) ||
64
+ index < 0 ||
65
+ index >= buttons.length
66
+ ) {
67
+ console.warn(
68
+ 'handleButtonEdit: Invalid index provided',
69
+ { index, buttonsLength: buttons.length, indexType: typeof index },
70
+ );
71
+ return;
72
+ }
61
73
  setIsAddingButton(true);
62
74
  setButtonBeingAdded(buttons[index].type);
63
75
  setEditingButtonIndex(index);
@@ -22,7 +22,7 @@ const AndroidMobileChromeHeader = ({
22
22
  <div className="notification-body">{notificationBody}</div>
23
23
  </div>
24
24
  <div className="notification-right-rail">
25
- {shouldShowBrandIcon && (
25
+ {shouldShowBrandIcon && brandIcon && (
26
26
  <div className="notification-brand-icon-container android-mobile-chrome-brand-icon">
27
27
  <img src={brandIcon} alt="Brand icon" className="notification-brand-icon" />
28
28
  </div>