@capillarytech/creatives-library 8.0.241 → 8.0.242-alpha.0
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 +1 -1
- package/sagas/__tests__/assetPolling.test.js +607 -0
- package/sagas/assetPolling.js +156 -0
- package/services/api.js +16 -0
- package/services/tests/api.test.js +124 -0
- package/translations/en.json +1 -0
- package/utils/assetStatusConstants.js +12 -0
- package/utils/asyncAssetUpload.js +161 -0
- package/utils/tests/asyncAssetUpload.test.js +292 -0
- package/utils/transformerUtils.js +42 -0
- package/v2Components/CapImageUpload/constants.js +2 -0
- package/v2Components/CapImageUpload/index.js +54 -14
- package/v2Components/CapImageUpload/index.scss +4 -1
- package/v2Components/CapImageUpload/messages.js +4 -0
- package/v2Components/CapImageUrlUpload/constants.js +19 -0
- package/v2Components/CapImageUrlUpload/index.js +455 -0
- package/v2Components/CapImageUrlUpload/index.scss +35 -0
- package/v2Components/CapImageUrlUpload/messages.js +47 -0
- package/v2Containers/App/constants.js +5 -0
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +1 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +57 -2
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -0
- package/v2Containers/CreativesContainer/constants.js +2 -0
- package/v2Containers/CreativesContainer/index.js +152 -0
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +25 -0
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +18 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +46 -0
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +4 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +8 -0
- package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
- package/v2Containers/Templates/_templates.scss +203 -0
- package/v2Containers/Templates/actions.js +2 -1
- package/v2Containers/Templates/constants.js +1 -0
- package/v2Containers/Templates/index.js +273 -30
- package/v2Containers/Templates/messages.js +24 -0
- package/v2Containers/Templates/reducer.js +2 -0
- package/v2Containers/Templates/tests/index.test.js +10 -0
- package/v2Containers/TemplatesV2/index.js +3 -2
- package/v2Containers/TemplatesV2/messages.js +4 -0
- package/v2Containers/WebPush/Create/components/ButtonForm.js +175 -0
- package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
- package/v2Containers/WebPush/Create/components/ButtonList.js +144 -0
- package/v2Containers/WebPush/Create/components/_buttons.scss +246 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +554 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +607 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +633 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +666 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +74 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +80 -0
- package/v2Containers/WebPush/Create/index.js +1755 -0
- package/v2Containers/WebPush/Create/index.scss +123 -0
- package/v2Containers/WebPush/Create/messages.js +199 -0
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +241 -0
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +290 -0
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +81 -0
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +240 -0
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +23 -0
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +144 -0
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +53 -0
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +5 -0
- package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +106 -0
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +26 -0
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +18 -0
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +29 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +44 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +110 -0
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +72 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +55 -0
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +70 -0
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +512 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +77 -0
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +527 -0
- package/v2Containers/WebPush/Create/preview/constants.js +162 -0
- package/v2Containers/WebPush/Create/preview/notification-container.scss +104 -0
- package/v2Containers/WebPush/Create/preview/preview.scss +409 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +300 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +303 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +188 -0
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +106 -0
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +75 -0
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +174 -0
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +909 -0
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1077 -0
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +723 -0
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +943 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +128 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +121 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +144 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +127 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.js +116 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
- package/v2Containers/WebPush/actions.js +60 -0
- package/v2Containers/WebPush/constants.js +108 -0
- package/v2Containers/WebPush/index.js +2 -0
- package/v2Containers/WebPush/reducer.js +104 -0
- package/v2Containers/WebPush/sagas.js +119 -0
- package/v2Containers/WebPush/selectors.js +65 -0
- package/v2Containers/WebPush/tests/reducer.test.js +863 -0
- package/v2Containers/WebPush/tests/sagas.test.js +566 -0
- package/v2Containers/WebPush/tests/selectors.test.js +960 -0
- package/v2Containers/Whatsapp/constants.js +9 -0
- package/v2Containers/Whatsapp/reducer.js +34 -5
- package/v2Containers/Whatsapp/sagas.js +61 -10
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +132 -0
- package/v2Containers/Whatsapp/tests/reducer.test.js +188 -0
- package/v2Containers/Whatsapp/tests/saga.test.js +420 -7
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { fromJS } from 'immutable';
|
|
2
|
+
import {
|
|
3
|
+
createAsyncAssetUploadConstants,
|
|
4
|
+
createAsyncAssetUploadReducerCases,
|
|
5
|
+
createPollingConfig,
|
|
6
|
+
} from '../asyncAssetUpload';
|
|
7
|
+
|
|
8
|
+
describe('asyncAssetUpload utilities', () => {
|
|
9
|
+
describe('createAsyncAssetUploadConstants', () => {
|
|
10
|
+
it('should create constants for a given channel prefix', () => {
|
|
11
|
+
const constants = createAsyncAssetUploadConstants('WHATSAPP', 'app/v2Containers/Whatsapp');
|
|
12
|
+
|
|
13
|
+
expect(constants).toEqual({
|
|
14
|
+
UPLOAD_WHATSAPP_ASSET_PROCESSING: 'app/v2Containers/Whatsapp/UPLOAD_WHATSAPP_ASSET_PROCESSING',
|
|
15
|
+
UPLOAD_WHATSAPP_ASSET_COMPLETED: 'app/v2Containers/Whatsapp/UPLOAD_WHATSAPP_ASSET_COMPLETED',
|
|
16
|
+
UPLOAD_WHATSAPP_ASSET_FAILED: 'app/v2Containers/Whatsapp/UPLOAD_WHATSAPP_ASSET_FAILED',
|
|
17
|
+
UPLOAD_WHATSAPP_ASSET_TIMEOUT: 'app/v2Containers/Whatsapp/UPLOAD_WHATSAPP_ASSET_TIMEOUT',
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should use default container path when not provided', () => {
|
|
22
|
+
const constants = createAsyncAssetUploadConstants('MOBILEPUSH');
|
|
23
|
+
|
|
24
|
+
expect(constants.UPLOAD_MOBILEPUSH_ASSET_PROCESSING).toBe(
|
|
25
|
+
'app/v2Containers/MOBILEPUSH/UPLOAD_MOBILEPUSH_ASSET_PROCESSING'
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should handle lowercase channel prefix', () => {
|
|
30
|
+
const constants = createAsyncAssetUploadConstants('email', 'app/v2Containers/Email');
|
|
31
|
+
|
|
32
|
+
expect(constants.UPLOAD_EMAIL_ASSET_PROCESSING).toBe(
|
|
33
|
+
'app/v2Containers/Email/UPLOAD_EMAIL_ASSET_PROCESSING'
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should create constants for different channels', () => {
|
|
38
|
+
const smsConstants = createAsyncAssetUploadConstants('SMS', 'app/v2Containers/Sms');
|
|
39
|
+
|
|
40
|
+
expect(smsConstants.UPLOAD_SMS_ASSET_PROCESSING).toContain('SMS');
|
|
41
|
+
expect(smsConstants.UPLOAD_SMS_ASSET_COMPLETED).toContain('SMS');
|
|
42
|
+
expect(smsConstants.UPLOAD_SMS_ASSET_FAILED).toContain('SMS');
|
|
43
|
+
expect(smsConstants.UPLOAD_SMS_ASSET_TIMEOUT).toContain('SMS');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('createAsyncAssetUploadReducerCases', () => {
|
|
48
|
+
const mockActionTypes = {
|
|
49
|
+
PROCESSING: 'TEST_PROCESSING',
|
|
50
|
+
COMPLETED: 'TEST_COMPLETED',
|
|
51
|
+
FAILED: 'TEST_FAILED',
|
|
52
|
+
TIMEOUT: 'TEST_TIMEOUT',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const createInitialState = () => fromJS({
|
|
56
|
+
uploadedAssetData: {},
|
|
57
|
+
assetUploading: false,
|
|
58
|
+
uploadAssetSuccess: false,
|
|
59
|
+
assetProcessing: {},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should create reducer cases with default options', () => {
|
|
63
|
+
const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
|
|
64
|
+
|
|
65
|
+
expect(reducerCases.PROCESSING).toBe('TEST_PROCESSING');
|
|
66
|
+
expect(reducerCases.COMPLETED).toBe('TEST_COMPLETED');
|
|
67
|
+
expect(reducerCases.FAILED).toBe('TEST_FAILED');
|
|
68
|
+
expect(reducerCases.TIMEOUT).toBe('TEST_TIMEOUT');
|
|
69
|
+
expect(typeof reducerCases.handleProcessing).toBe('function');
|
|
70
|
+
expect(typeof reducerCases.handleCompleted).toBe('function');
|
|
71
|
+
expect(typeof reducerCases.handleFailed).toBe('function');
|
|
72
|
+
expect(typeof reducerCases.handleTimeout).toBe('function');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('handleProcessing', () => {
|
|
76
|
+
it('should set processing state correctly', () => {
|
|
77
|
+
const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
|
|
78
|
+
const state = createInitialState();
|
|
79
|
+
const action = {
|
|
80
|
+
payload: {
|
|
81
|
+
assetId: 'asset-123',
|
|
82
|
+
asset: { _id: 'asset-123', url: 'https://example.com/image.jpg' },
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const newState = reducerCases.handleProcessing(state, action);
|
|
87
|
+
|
|
88
|
+
expect(newState.get('uploadAssetSuccess')).toBe(false);
|
|
89
|
+
expect(newState.get('assetUploading')).toBe(true);
|
|
90
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('processing');
|
|
91
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'asset'])).toBeDefined();
|
|
92
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'startTime'])).toBeDefined();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('handleCompleted', () => {
|
|
97
|
+
it('should set completed state correctly without templateType', () => {
|
|
98
|
+
const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
|
|
99
|
+
const state = createInitialState();
|
|
100
|
+
const action = {
|
|
101
|
+
payload: {
|
|
102
|
+
assetId: 'asset-123',
|
|
103
|
+
asset: { _id: 'asset-123', url: 'https://example.com/image.jpg' },
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const newState = reducerCases.handleCompleted(state, action);
|
|
108
|
+
|
|
109
|
+
expect(newState.get('uploadAssetSuccess')).toBe(true);
|
|
110
|
+
expect(newState.get('assetUploading')).toBe(false);
|
|
111
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('completed');
|
|
112
|
+
expect(newState.get('uploadedAssetData')).toEqual(fromJS(action.payload.asset));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should set completed state correctly with templateType', () => {
|
|
116
|
+
const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
|
|
117
|
+
const state = createInitialState();
|
|
118
|
+
const action = {
|
|
119
|
+
templateType: 0,
|
|
120
|
+
payload: {
|
|
121
|
+
assetId: 'asset-123',
|
|
122
|
+
asset: { _id: 'asset-123', url: 'https://example.com/image.jpg' },
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const newState = reducerCases.handleCompleted(state, action);
|
|
127
|
+
|
|
128
|
+
expect(newState.get('uploadAssetSuccess')).toBe(true);
|
|
129
|
+
expect(newState.get('assetUploading')).toBe(false);
|
|
130
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('completed');
|
|
131
|
+
expect(newState.get('uploadedAssetData0')).toEqual(fromJS(action.payload.asset));
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('handleFailed', () => {
|
|
136
|
+
it('should set failed state correctly', () => {
|
|
137
|
+
const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
|
|
138
|
+
const state = createInitialState();
|
|
139
|
+
const action = {
|
|
140
|
+
payload: {
|
|
141
|
+
assetId: 'asset-123',
|
|
142
|
+
error: 'Processing failed',
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const newState = reducerCases.handleFailed(state, action);
|
|
147
|
+
|
|
148
|
+
expect(newState.get('uploadAssetSuccess')).toBe(false);
|
|
149
|
+
expect(newState.get('assetUploading')).toBe(false);
|
|
150
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('failed');
|
|
151
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'error'])).toBe('Processing failed');
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('handleTimeout', () => {
|
|
156
|
+
it('should set timeout state correctly', () => {
|
|
157
|
+
const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
|
|
158
|
+
const state = createInitialState();
|
|
159
|
+
const action = {
|
|
160
|
+
payload: {
|
|
161
|
+
assetId: 'asset-123',
|
|
162
|
+
message: 'Processing timeout',
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const newState = reducerCases.handleTimeout(state, action);
|
|
167
|
+
|
|
168
|
+
expect(newState.get('uploadAssetSuccess')).toBe(false);
|
|
169
|
+
expect(newState.get('assetUploading')).toBe(false);
|
|
170
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('timeout');
|
|
171
|
+
expect(newState.getIn(['assetProcessing', 'asset-123', 'error'])).toBe('Processing timeout');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should use custom state keys when provided', () => {
|
|
176
|
+
const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes, {
|
|
177
|
+
uploadedAssetDataKey: 'customAssetData',
|
|
178
|
+
assetUploadingKey: 'customUploading',
|
|
179
|
+
uploadAssetSuccessKey: 'customSuccess',
|
|
180
|
+
assetProcessingKey: 'customProcessing',
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const state = fromJS({
|
|
184
|
+
customAssetData: {},
|
|
185
|
+
customUploading: false,
|
|
186
|
+
customSuccess: false,
|
|
187
|
+
customProcessing: {},
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const action = {
|
|
191
|
+
payload: {
|
|
192
|
+
assetId: 'asset-123',
|
|
193
|
+
asset: { _id: 'asset-123' },
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const newState = reducerCases.handleProcessing(state, action);
|
|
198
|
+
|
|
199
|
+
expect(newState.get('customSuccess')).toBe(false);
|
|
200
|
+
expect(newState.get('customUploading')).toBe(true);
|
|
201
|
+
expect(newState.getIn(['customProcessing', 'asset-123'])).toBeDefined();
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('createPollingConfig', () => {
|
|
206
|
+
const mockActionTypes = {
|
|
207
|
+
COMPLETED: 'TEST_COMPLETED',
|
|
208
|
+
FAILED: 'TEST_FAILED',
|
|
209
|
+
TIMEOUT: 'TEST_TIMEOUT',
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
it('should create polling config correctly', () => {
|
|
213
|
+
const config = createPollingConfig('image', 'asset-123', mockActionTypes, 0);
|
|
214
|
+
|
|
215
|
+
expect(config).toEqual({
|
|
216
|
+
type: 'image',
|
|
217
|
+
assetId: 'asset-123',
|
|
218
|
+
onCompleted: expect.any(Function),
|
|
219
|
+
onFailed: expect.any(Function),
|
|
220
|
+
onTimeout: expect.any(Function),
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should create onCompleted action creator', () => {
|
|
225
|
+
const config = createPollingConfig('image', 'asset-123', mockActionTypes, 0);
|
|
226
|
+
const data = {
|
|
227
|
+
assetId: 'asset-123',
|
|
228
|
+
asset: { _id: 'asset-123' },
|
|
229
|
+
duration: 1000,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const action = config.onCompleted(data);
|
|
233
|
+
|
|
234
|
+
expect(action).toEqual({
|
|
235
|
+
type: 'TEST_COMPLETED',
|
|
236
|
+
payload: data,
|
|
237
|
+
templateType: 0,
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should create onFailed action creator', () => {
|
|
242
|
+
const config = createPollingConfig('image', 'asset-123', mockActionTypes, 0);
|
|
243
|
+
const data = {
|
|
244
|
+
assetId: 'asset-123',
|
|
245
|
+
error: 'Processing failed',
|
|
246
|
+
duration: 1000,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const action = config.onFailed(data);
|
|
250
|
+
|
|
251
|
+
expect(action).toEqual({
|
|
252
|
+
type: 'TEST_FAILED',
|
|
253
|
+
payload: data,
|
|
254
|
+
templateType: 0,
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should create onTimeout action creator', () => {
|
|
259
|
+
const config = createPollingConfig('image', 'asset-123', mockActionTypes, 0);
|
|
260
|
+
const data = {
|
|
261
|
+
assetId: 'asset-123',
|
|
262
|
+
message: 'Timeout',
|
|
263
|
+
duration: 90000,
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const action = config.onTimeout(data);
|
|
267
|
+
|
|
268
|
+
expect(action).toEqual({
|
|
269
|
+
type: 'TEST_TIMEOUT',
|
|
270
|
+
payload: data,
|
|
271
|
+
templateType: 0,
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('should handle undefined templateType', () => {
|
|
276
|
+
const config = createPollingConfig('image', 'asset-123', mockActionTypes);
|
|
277
|
+
const data = { assetId: 'asset-123', asset: {} };
|
|
278
|
+
|
|
279
|
+
const action = config.onCompleted(data);
|
|
280
|
+
|
|
281
|
+
expect(action.templateType).toBeUndefined();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should work with different asset types', () => {
|
|
285
|
+
const videoConfig = createPollingConfig('video', 'asset-456', mockActionTypes, 1);
|
|
286
|
+
|
|
287
|
+
expect(videoConfig.type).toBe('video');
|
|
288
|
+
expect(videoConfig.assetId).toBe('asset-456');
|
|
289
|
+
expect(videoConfig.onCompleted({}).templateType).toBe(1);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
});
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
RCS,
|
|
11
11
|
LINE,
|
|
12
12
|
VIBER,
|
|
13
|
+
WEBPUSH,
|
|
13
14
|
EMF,
|
|
14
15
|
VENENO,
|
|
15
16
|
TEXT,
|
|
@@ -63,6 +64,8 @@ export const transformChannelPayload = (data, options = {}) => {
|
|
|
63
64
|
return transformLinePayload(data, options);
|
|
64
65
|
case VIBER:
|
|
65
66
|
return transformViberPayload(data, options);
|
|
67
|
+
case WEBPUSH:
|
|
68
|
+
return transformWebpushPayload(data, options);
|
|
66
69
|
default:
|
|
67
70
|
return data; // Return unchanged for unsupported channels
|
|
68
71
|
}
|
|
@@ -317,6 +320,45 @@ const transformViberPayload = (viberData, options = {}) => {
|
|
|
317
320
|
return payload;
|
|
318
321
|
};
|
|
319
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Transforms WebPush data to the required payload format
|
|
325
|
+
* @param {Object} webpushData - Current WebPush data
|
|
326
|
+
* @param {Object} options - Additional options (ouId, sourceEntityId, etc.)
|
|
327
|
+
* @returns {Object} - Transformed WebPush payload
|
|
328
|
+
*/
|
|
329
|
+
const transformWebpushPayload = (webpushData, options = {}) => {
|
|
330
|
+
const { loyaltyMetaData = {} } = options;
|
|
331
|
+
const { transformedMessageDetails = {} } = loyaltyMetaData;
|
|
332
|
+
const { webpushDeliverySettings = {} } = transformedMessageDetails || {};
|
|
333
|
+
|
|
334
|
+
// Get base payload structure
|
|
335
|
+
const payload = createBasePayload(WEBPUSH, loyaltyMetaData);
|
|
336
|
+
|
|
337
|
+
// Extract webpush content from messageContent.content.content structure
|
|
338
|
+
const webpushContent = webpushData?.messageContent?.content?.content || {};
|
|
339
|
+
const accountId = webpushData?.messageContent?.content?.accountId || 0;
|
|
340
|
+
|
|
341
|
+
// Add WebPush-specific properties
|
|
342
|
+
payload.centralCommsPayload.webpushMessageContent = {
|
|
343
|
+
channel: WEBPUSH,
|
|
344
|
+
accountId,
|
|
345
|
+
isDefault: webpushData?.messageContent?.content?.isDefault || false,
|
|
346
|
+
storeType: webpushData?.messageContent?.content?.storeType || 'REGISTERED_STORE',
|
|
347
|
+
content: {
|
|
348
|
+
title: webpushContent?.title || '',
|
|
349
|
+
message: webpushContent?.message || '',
|
|
350
|
+
...(webpushContent?.iconImageUrl && { iconImageUrl: webpushContent.iconImageUrl }),
|
|
351
|
+
...(webpushContent?.cta && { cta: webpushContent.cta }),
|
|
352
|
+
...(webpushContent?.expandableDetails && { expandableDetails: webpushContent.expandableDetails }),
|
|
353
|
+
},
|
|
354
|
+
messageSubject: webpushData?.messageSubject || "",
|
|
355
|
+
offers: webpushData?.messageContent?.content?.offers || [],
|
|
356
|
+
};
|
|
357
|
+
payload.centralCommsPayload.webpushDeliverySettings = webpushDeliverySettings;
|
|
358
|
+
|
|
359
|
+
return payload;
|
|
360
|
+
};
|
|
361
|
+
|
|
320
362
|
// Checks if the template has changed
|
|
321
363
|
export const getTemplateDiffState = (channel, oldData, newData) => {
|
|
322
364
|
switch (channel.toUpperCase()) {
|
|
@@ -17,17 +17,18 @@ import {
|
|
|
17
17
|
CapImage,
|
|
18
18
|
CapError,
|
|
19
19
|
} from '@capillarytech/cap-ui-library';
|
|
20
|
-
import { injectIntl, FormattedMessage, intlShape} from 'react-intl';
|
|
20
|
+
import { injectIntl, FormattedMessage, intlShape } from 'react-intl';
|
|
21
21
|
import { isEmpty, get } from 'lodash';
|
|
22
22
|
import './index.scss';
|
|
23
23
|
import Gallery from '../../v2Containers/Assets/Gallery';
|
|
24
24
|
import { MAX_SUPPORTED_IMAGE_SIZE } from './constants';
|
|
25
25
|
import {
|
|
26
|
-
FACEBOOK, INAPP, RCS, WHATSAPP, VIBER,
|
|
26
|
+
FACEBOOK, INAPP, RCS, WHATSAPP, VIBER, WEBPUSH, WEBPUSH_BRAND_ICON
|
|
27
27
|
} from "../../v2Containers/CreativesContainer/constants";
|
|
28
28
|
|
|
29
29
|
import messages from './messages';
|
|
30
30
|
import { MOBILEPUSH } from '../CapVideoUpload/constants';
|
|
31
|
+
import { CAP_SPACE_16 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
31
32
|
function CapImageUpload(props) {
|
|
32
33
|
const {
|
|
33
34
|
intl,
|
|
@@ -50,6 +51,7 @@ function CapImageUpload(props) {
|
|
|
50
51
|
channelSpecificStyle,
|
|
51
52
|
showReUploadButton = true,
|
|
52
53
|
disableAutoRestore = false, // New prop to disable automatic restoration
|
|
54
|
+
recommendedDimensions, // Array of {width, height} objects for recommended dimensions
|
|
53
55
|
} = props;
|
|
54
56
|
const {
|
|
55
57
|
formatMessage,
|
|
@@ -72,7 +74,7 @@ function CapImageUpload(props) {
|
|
|
72
74
|
const [isImageError, updateImageErrorMessage] = useState(false);
|
|
73
75
|
const [isDrawerRequired, updateDrawerRequirement] = useState(false);
|
|
74
76
|
|
|
75
|
-
const {CapHeadingSpan} = CapHeading;
|
|
77
|
+
const { CapHeadingSpan } = CapHeading;
|
|
76
78
|
const ImageComponent = useCallback(
|
|
77
79
|
() => (
|
|
78
80
|
<>
|
|
@@ -91,7 +93,7 @@ function CapImageUpload(props) {
|
|
|
91
93
|
|
|
92
94
|
const WithLabel = LabelHOC(ImageComponent);
|
|
93
95
|
|
|
94
|
-
const uploadImages = useCallback((e, {files}) => {
|
|
96
|
+
const uploadImages = useCallback((e, { files }) => {
|
|
95
97
|
if (e) {
|
|
96
98
|
e.preventDefault();
|
|
97
99
|
}
|
|
@@ -109,13 +111,13 @@ function CapImageUpload(props) {
|
|
|
109
111
|
height: img.height,
|
|
110
112
|
error: file && (file.size / (1e+6) > 5), // Checking if file exists and its size is greater than 5MB (5 * 10^6 bytes)
|
|
111
113
|
};
|
|
112
|
-
submitAction({file, type: 'image', fileParams}, incorrectFile);
|
|
114
|
+
submitAction({ file, type: 'image', fileParams }, incorrectFile);
|
|
113
115
|
};
|
|
114
116
|
img.onerror = () => {
|
|
115
117
|
const fileParams = {
|
|
116
118
|
error: true,
|
|
117
119
|
};
|
|
118
|
-
submitAction({fileParams}, incorrectFile);
|
|
120
|
+
submitAction({ fileParams }, incorrectFile);
|
|
119
121
|
};
|
|
120
122
|
if (e) {
|
|
121
123
|
const event = e;
|
|
@@ -123,7 +125,7 @@ function CapImageUpload(props) {
|
|
|
123
125
|
}
|
|
124
126
|
}, []);
|
|
125
127
|
|
|
126
|
-
const rcsValidation = useCallback((incorrectFile, data, size, height, width, error) => {
|
|
128
|
+
const rcsValidation = useCallback((incorrectFile, data, size, height, width, error) => {
|
|
127
129
|
if (incorrectFile || size < minImgSize || size > imgSize || height !== imgHeight || width !== imgWidth || error) {
|
|
128
130
|
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
129
131
|
} else {
|
|
@@ -146,6 +148,19 @@ function CapImageUpload(props) {
|
|
|
146
148
|
const { height, width, error } = fileParams || {};
|
|
147
149
|
if (channel === RCS) {
|
|
148
150
|
rcsValidation(incorrectFile, data, size, height, width, error);
|
|
151
|
+
} else if ([WEBPUSH, WEBPUSH_BRAND_ICON].includes(channel)) {
|
|
152
|
+
// For WEBPUSH, only validate file extension, size, and format - no dimension validation
|
|
153
|
+
if (incorrectFile || size > imgSize || error) {
|
|
154
|
+
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
155
|
+
} else {
|
|
156
|
+
updateImageErrorMessage('');
|
|
157
|
+
uploadAsset(
|
|
158
|
+
data.file,
|
|
159
|
+
data.type,
|
|
160
|
+
data.fileParams,
|
|
161
|
+
index,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
149
164
|
} else if (incorrectFile || size > imgSize || height > imgHeight || width > imgWidth || error) {
|
|
150
165
|
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
151
166
|
} else {
|
|
@@ -160,7 +175,7 @@ function CapImageUpload(props) {
|
|
|
160
175
|
}, [isImageError]);
|
|
161
176
|
|
|
162
177
|
const capUploaderCustomRequest = useCallback((uploadData) => {
|
|
163
|
-
uploadImages(undefined, {files: [uploadData.file]});
|
|
178
|
+
uploadImages(undefined, { files: [uploadData.file] });
|
|
164
179
|
}, [uploadImages]);
|
|
165
180
|
|
|
166
181
|
const setDrawerVisibility = useCallback((drawervisibleFlag) => updateDrawerRequirement(drawervisibleFlag), [isDrawerRequired]);
|
|
@@ -181,19 +196,27 @@ function CapImageUpload(props) {
|
|
|
181
196
|
secure_file_path: image, width, height, file_size: size,
|
|
182
197
|
} = get(imageTemplate, 'metaInfo', {});
|
|
183
198
|
updateDrawerRequirement(false);
|
|
184
|
-
|
|
199
|
+
// For WEBPUSH, skip dimension validation - only check extension, size
|
|
200
|
+
if ([WEBPUSH, WEBPUSH_BRAND_ICON].includes(channel)) {
|
|
201
|
+
if (!allowedExtensionsRegex.test(image) || size > imgSize) {
|
|
202
|
+
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
203
|
+
} else {
|
|
204
|
+
updateImageErrorMessage('');
|
|
205
|
+
updateImageSrc(image);
|
|
206
|
+
}
|
|
207
|
+
} else if (!allowedExtensionsRegex.test(image) || height > imgHeight || width > imgWidth || size > imgSize) {
|
|
185
208
|
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
186
209
|
} else {
|
|
187
210
|
updateImageErrorMessage('');
|
|
188
211
|
updateImageSrc(image);
|
|
189
212
|
}
|
|
190
|
-
}, [isImageError, isDrawerRequired]);
|
|
213
|
+
}, [isImageError, isDrawerRequired, channel, allowedExtensionsRegex, imgSize, formatMessage]);
|
|
191
214
|
|
|
192
215
|
const getGalleryDrawerContent = useCallback(() => {
|
|
193
216
|
const locationGallery = {
|
|
194
217
|
pathname: `/assets`,
|
|
195
218
|
search: '',
|
|
196
|
-
query: !isFullMode ? {type: 'embedded', module: 'library'} : {},
|
|
219
|
+
query: !isFullMode ? { type: 'embedded', module: 'library' } : {},
|
|
197
220
|
};
|
|
198
221
|
return (
|
|
199
222
|
<>
|
|
@@ -262,7 +285,7 @@ function CapImageUpload(props) {
|
|
|
262
285
|
className="dragger-button re-upload"
|
|
263
286
|
type="flat"
|
|
264
287
|
onClick={onReUpload}
|
|
265
|
-
style={channelSpecificStyle ? { marginTop:
|
|
288
|
+
style={channelSpecificStyle ? { marginTop: `-${CAP_SPACE_16}` } : {}}
|
|
266
289
|
>
|
|
267
290
|
<FormattedMessage {...messages.imageReUpload} />
|
|
268
291
|
</CapButton>
|
|
@@ -305,7 +328,18 @@ function CapImageUpload(props) {
|
|
|
305
328
|
)}
|
|
306
329
|
{![WHATSAPP, INAPP].includes(channel) && (
|
|
307
330
|
<CapHeadingSpan type="label2" className="image-dimension">
|
|
308
|
-
|
|
331
|
+
{[WEBPUSH, WEBPUSH_BRAND_ICON].includes(channel) && recommendedDimensions?.length ? (
|
|
332
|
+
<FormattedMessage
|
|
333
|
+
{...messages.recommendedDimensions}
|
|
334
|
+
values={{
|
|
335
|
+
dimensions: recommendedDimensions
|
|
336
|
+
.map((dim) => `${dim.width} x ${dim.height}px`)
|
|
337
|
+
.join(', '),
|
|
338
|
+
}}
|
|
339
|
+
/>
|
|
340
|
+
) : (
|
|
341
|
+
<FormattedMessage {...messages.imageDimenstionDescription} values={{ width: imgWidth, height: imgHeight }} />
|
|
342
|
+
)}
|
|
309
343
|
</CapHeadingSpan>
|
|
310
344
|
)}
|
|
311
345
|
{channel === FACEBOOK && (
|
|
@@ -328,7 +362,7 @@ function CapImageUpload(props) {
|
|
|
328
362
|
getImageSizeLabel()
|
|
329
363
|
)
|
|
330
364
|
)}
|
|
331
|
-
{[VIBER, INAPP, MOBILEPUSH].includes(channel) && getImageSizeLabel()}
|
|
365
|
+
{[VIBER, INAPP, MOBILEPUSH, WEBPUSH, WEBPUSH_BRAND_ICON].includes(channel) && getImageSizeLabel()}
|
|
332
366
|
<CapHeadingSpan type="label2" className="image-format">
|
|
333
367
|
{channel === INAPP ? <FormattedMessage {...messages.format2} /> : <FormattedMessage {...messages.format} />}
|
|
334
368
|
</CapHeadingSpan>
|
|
@@ -357,6 +391,12 @@ CapImageUpload.propTypes = {
|
|
|
357
391
|
channel: PropTypes.string,
|
|
358
392
|
channelSpecificStyle: PropTypes.bool,
|
|
359
393
|
disableAutoRestore: PropTypes.bool,
|
|
394
|
+
recommendedDimensions: PropTypes.arrayOf(
|
|
395
|
+
PropTypes.shape({
|
|
396
|
+
width: PropTypes.number.isRequired,
|
|
397
|
+
height: PropTypes.number.isRequired,
|
|
398
|
+
})
|
|
399
|
+
),
|
|
360
400
|
};
|
|
361
401
|
|
|
362
402
|
export default injectIntl(CapImageUpload);
|
|
@@ -34,6 +34,10 @@ export default defineMessages({
|
|
|
34
34
|
id: `${scope}.imageDimenstionDescription`,
|
|
35
35
|
defaultMessage: 'Dimensions upto: {width}px x {height}px',
|
|
36
36
|
},
|
|
37
|
+
recommendedDimensions: {
|
|
38
|
+
id: `${scope}.recommendedDimensions`,
|
|
39
|
+
defaultMessage: 'Recommended dimensions: {dimensions}',
|
|
40
|
+
},
|
|
37
41
|
format: {
|
|
38
42
|
id: `${scope}.format`,
|
|
39
43
|
defaultMessage: 'Format: JPEG, JPG, PNG',
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Default allowed content types for image URL validation
|
|
2
|
+
export const DEFAULT_ALLOWED_CONTENT_TYPES = ['image/jpeg', 'image/jpg', 'image/png'];
|
|
3
|
+
|
|
4
|
+
// Default maximum file size (5MB)
|
|
5
|
+
export const DEFAULT_MAX_SIZE = 5000000;
|
|
6
|
+
|
|
7
|
+
// Default allowed extensions regex
|
|
8
|
+
export const DEFAULT_ALLOWED_EXTENSIONS_REGEX = /\.(jpe?g|png)$/i;
|
|
9
|
+
|
|
10
|
+
// MIME type to file extension mapping
|
|
11
|
+
export const MIME_TYPE_TO_EXTENSION = {
|
|
12
|
+
'image/jpeg': 'jpg',
|
|
13
|
+
'image/jpg': 'jpg',
|
|
14
|
+
'image/png': 'png',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Default image extension fallback
|
|
18
|
+
export const DEFAULT_IMAGE_EXTENSION = 'png';
|
|
19
|
+
|