@ordergroove/offers 2.44.0 → 2.44.1-alpha-PR-1166-3.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/bundle-report.html +52 -49
  2. package/dist/offers.js +38 -38
  3. package/dist/offers.js.map +4 -4
  4. package/package.json +2 -2
  5. package/src/components/FrequencyStatus.js +13 -10
  6. package/src/components/Offer.js +33 -14
  7. package/src/components/OptinButton.js +2 -2
  8. package/src/components/OptinSelect.js +5 -5
  9. package/src/components/OptinStatus.js +15 -9
  10. package/src/components/Price.js +3 -3
  11. package/src/components/SelectFrequency.js +11 -6
  12. package/src/components/TestWizard.js +45 -41
  13. package/src/components/UpsellModal.js +9 -3
  14. package/src/components/__tests__/Offer.spec.js +0 -19
  15. package/src/components/__tests__/OptinStatus.spec.js +17 -4
  16. package/src/core/__tests__/actions.spec.js +47 -1
  17. package/src/core/__tests__/base.spec.js +0 -77
  18. package/src/core/__tests__/offerRequest.spec.js +2 -1
  19. package/src/core/__tests__/selectors.spec.js +7 -7
  20. package/src/core/actions-preview.js +6 -3
  21. package/src/core/actions.js +22 -13
  22. package/src/core/base.js +0 -23
  23. package/src/core/offerRequest.js +1 -1
  24. package/src/core/{reducer.js → reducer.ts} +30 -10
  25. package/src/core/{selectors.js → selectors.ts} +73 -57
  26. package/src/core/types/api.ts +71 -0
  27. package/src/core/types/reducer.ts +95 -0
  28. package/src/core/types/utility.ts +1 -0
  29. package/src/core/utils.ts +32 -15
  30. package/src/make-api.js +1 -1
  31. package/src/shopify/__tests__/reducers/config.spec.js +497 -0
  32. package/src/shopify/__tests__/shopifyReducer.spec.js +65 -610
  33. package/src/shopify/__tests__/utils.spec.js +24 -1
  34. package/src/shopify/reducers/config.ts +223 -0
  35. package/src/shopify/shopifyMiddleware.ts +2 -9
  36. package/src/shopify/{shopifyReducer.js → shopifyReducer.ts} +45 -177
  37. package/src/shopify/utils.ts +25 -0
  38. package/src/types.ts +0 -16
package/src/core/utils.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import platform from '../platform';
2
2
  import { ENV_PROD, ENV_STAGING, STAGING_STATIC_HOST, STATIC_HOST } from './constants';
3
3
  import { isSameProduct } from './selectors';
4
+ import { ConfigState } from './types/reducer';
4
5
 
5
6
  export function onReady(fn) {
6
7
  if (document.readyState === 'loading') {
@@ -47,33 +48,45 @@ export const safeProductId = product => {
47
48
  return productId;
48
49
  };
49
50
 
51
+ type Frequencies = ConfigState['frequencies'];
52
+ type FrequenciesEveryPeriod = ConfigState['frequenciesEveryPeriod'];
53
+
50
54
  /**
51
55
  * Returns the OG frequency if platform is running on selling plans
52
- * @param initialFrequency
53
- * @param config
54
56
  */
55
- export const safeOgFrequency = (initialFrequency, config) => {
57
+ export const safeOgFrequency = (
58
+ initialFrequency: string | null,
59
+ frequencies: Frequencies,
60
+ frequenciesEveryPeriod: FrequenciesEveryPeriod
61
+ ) => {
56
62
  if (platform.shopify_selling_plans) {
57
- const ix = config.frequencies?.indexOf(initialFrequency);
58
- if (ix >= 0 && config.frequenciesEveryPeriod[ix]) {
59
- return config.frequenciesEveryPeriod[ix];
63
+ const ix = frequencies?.indexOf(initialFrequency);
64
+ if (ix >= 0 && frequenciesEveryPeriod[ix]) {
65
+ return frequenciesEveryPeriod[ix];
60
66
  }
61
67
  }
62
68
  return initialFrequency;
63
69
  };
64
70
 
65
- export const frequencyToSellingPlan = (ogFrequency, config) => {
71
+ export const frequencyToSellingPlan = (
72
+ ogFrequency: string,
73
+ frequencyConfig: {
74
+ frequencies: Frequencies;
75
+ frequenciesEveryPeriod: FrequenciesEveryPeriod;
76
+ }
77
+ ) => {
66
78
  // og frequency contains underscore
67
79
  if (!`${ogFrequency}`.includes('_')) return ogFrequency;
68
- const ix = config.frequenciesEveryPeriod?.indexOf(ogFrequency);
69
- if (ix >= 0 && config.frequenciesEveryPeriod[ix]) {
70
- return config.frequencies[ix];
80
+ const { frequencies, frequenciesEveryPeriod } = frequencyConfig;
81
+ const ix = frequenciesEveryPeriod?.indexOf(ogFrequency);
82
+ if (ix >= 0 && frequenciesEveryPeriod[ix]) {
83
+ return frequencies[ix];
71
84
  }
72
85
 
73
86
  // if we can't find the OG frequency, but we have selling plans, return the first selling plan
74
- if (config.frequencies?.length > 0 && config.frequenciesEveryPeriod?.length > 0) {
87
+ if (frequencies?.length > 0 && frequenciesEveryPeriod?.length > 0) {
75
88
  console.warn(`Unable to find selling plan match for frequency ${ogFrequency}; falling back to first selling plan`);
76
- return config.frequencies[0];
89
+ return frequencies[0];
77
90
  }
78
91
 
79
92
  return ogFrequency;
@@ -110,14 +123,18 @@ export function getCookieValue(cookieId) {
110
123
  const cookie = document.cookie.match(`(^|;) ?${cookieId}=([^;]*)(;|$)`);
111
124
  return cookie ? cookie[2] : null;
112
125
  }
113
- export const isOgFrequency = frequency => !!(frequency && frequency?.includes('_'));
126
+ export const isOgFrequency = (frequency: string) => !!(frequency && frequency?.includes('_'));
114
127
 
115
- export const getFirstSellingPlan = (frequencies = []) => frequencies?.[0] || null;
128
+ export const getFirstSellingPlan = (frequencies: string[] = []) => frequencies?.[0] || null;
116
129
 
117
130
  export const hasShopifySellingPlans = (sellingPlans = [], frequenciesEveryPeriod = []) =>
118
131
  !!(platform?.shopify_selling_plans && sellingPlans.length && frequenciesEveryPeriod.length);
119
132
 
120
- export const mapFrequencyToSellingPlan = (sellingPlans, frequenciesEveryPeriod, frequency) => {
133
+ export const mapFrequencyToSellingPlan = (
134
+ sellingPlans: string[],
135
+ frequenciesEveryPeriod: string[],
136
+ frequency: string
137
+ ) => {
121
138
  if (sellingPlans.length !== frequenciesEveryPeriod.length) {
122
139
  return null;
123
140
  }
package/src/make-api.js CHANGED
@@ -164,7 +164,7 @@ export default function makeApi(store) {
164
164
  * @param {*} merchantId
165
165
  * @param {*} env
166
166
  * @param {*} authUrl
167
- * @param {import('./types').MerchantSettings} merchantSettings
167
+ * @param {import('./core/types/api').MerchantSettings} merchantSettings
168
168
  */
169
169
  initialize(merchantId, env, authUrl, merchantSettings = {}) {
170
170
  // settings resolves once, before anything.
@@ -0,0 +1,497 @@
1
+ import config from '../../reducers/config';
2
+ import * as constants from '../../../core/constants';
3
+ import { DEFAULT_PAY_AS_YOU_GO_GROUP_NAME } from '../../utils';
4
+
5
+ describe('config', () => {
6
+ it('should return unique frequencies given action RECEIVE_PRODUCT_PLANS', () => {
7
+ const actual = config(
8
+ {},
9
+ {
10
+ type: constants.RECEIVE_PRODUCT_PLANS,
11
+ payload: {
12
+ 'product plan id': { '1_1': {}, '3_1': {} }
13
+ }
14
+ }
15
+ );
16
+
17
+ expect(actual).toEqual(
18
+ jasmine.objectContaining({
19
+ frequencies: ['1_1', '3_1']
20
+ })
21
+ );
22
+ });
23
+
24
+ it('should set defaultFrequency to selling plan given selling plan exists for frequency given action SETUP_PRODUCT', () => {
25
+ const actual = config(
26
+ {
27
+ defaultFrequency: '1_2'
28
+ },
29
+ {
30
+ type: constants.SETUP_PRODUCT,
31
+ payload: {
32
+ offer: {
33
+ config: {
34
+ frequencies: ['yum selling plan id 1', 'yum selling plan id 2'],
35
+ frequenciesEveryPeriod: ['1_1', '1_2']
36
+ }
37
+ },
38
+ product: {
39
+ selling_plan_groups: [
40
+ {
41
+ name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
42
+ selling_plans: [
43
+ {
44
+ id: 'yum selling plan id 1',
45
+ options: [
46
+ {
47
+ value: '1 day'
48
+ }
49
+ ]
50
+ },
51
+ {
52
+ id: 'yum selling plan id 2',
53
+ options: [
54
+ {
55
+ value: '1 week'
56
+ }
57
+ ]
58
+ }
59
+ ]
60
+ }
61
+ ]
62
+ }
63
+ }
64
+ }
65
+ );
66
+
67
+ expect(actual).toEqual(
68
+ jasmine.objectContaining({
69
+ defaultFrequency: 'yum selling plan id 2'
70
+ })
71
+ );
72
+ });
73
+
74
+ it('should set defaultFrequency to first selling plan given selling plan does not exist for frequency given action SETUP_PRODUCT', () => {
75
+ const actual = config(
76
+ {
77
+ defaultFrequency: '1_3'
78
+ },
79
+ {
80
+ type: constants.SETUP_PRODUCT,
81
+ payload: {
82
+ offer: {
83
+ config: {
84
+ frequencies: ['yum selling plan id 1', 'yum selling plan id 2'],
85
+ frequenciesEveryPeriod: ['1_1', '1_2']
86
+ }
87
+ },
88
+ product: {
89
+ selling_plan_groups: [
90
+ {
91
+ name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
92
+ selling_plans: [
93
+ {
94
+ id: 'yum selling plan id 1',
95
+ options: [
96
+ {
97
+ value: '1 day'
98
+ }
99
+ ]
100
+ },
101
+ {
102
+ id: 'yum selling plan id 2',
103
+ options: [
104
+ {
105
+ value: '1 week'
106
+ }
107
+ ]
108
+ }
109
+ ]
110
+ }
111
+ ]
112
+ }
113
+ }
114
+ }
115
+ );
116
+
117
+ expect(actual).toEqual(
118
+ jasmine.objectContaining({
119
+ defaultFrequency: 'yum selling plan id 1'
120
+ })
121
+ );
122
+ });
123
+
124
+ it('should not change default frequency if is already a selling plan given action SETUP_PRODUCT', () => {
125
+ const actual = config(
126
+ {
127
+ defaultFrequency: 'yum selling plan id 5'
128
+ },
129
+ {
130
+ type: constants.SETUP_PRODUCT,
131
+ payload: {
132
+ offer: {
133
+ config: {
134
+ frequencies: ['yum selling plan id 1', 'yum selling plan id 2'],
135
+ frequenciesEveryPeriod: ['1_1', '1_2']
136
+ }
137
+ },
138
+ product: {
139
+ selling_plan_groups: [
140
+ {
141
+ name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
142
+ selling_plans: [
143
+ {
144
+ id: 'yum selling plan id 1',
145
+ options: [
146
+ {
147
+ value: '1 day'
148
+ }
149
+ ]
150
+ },
151
+ {
152
+ id: 'yum selling plan id 2',
153
+ options: [
154
+ {
155
+ value: '1 week'
156
+ }
157
+ ]
158
+ }
159
+ ]
160
+ }
161
+ ]
162
+ }
163
+ }
164
+ }
165
+ );
166
+
167
+ expect(actual).toEqual(
168
+ jasmine.objectContaining({
169
+ defaultFrequency: 'yum selling plan id 5'
170
+ })
171
+ );
172
+ });
173
+
174
+ const defaultSellingPlanPayload = {
175
+ product: {
176
+ selling_plan_groups: [
177
+ {
178
+ name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
179
+ selling_plans: [
180
+ {
181
+ id: 'yum selling plan id 1'
182
+ },
183
+ {
184
+ id: 'yum selling plan id 2'
185
+ }
186
+ ]
187
+ }
188
+ ]
189
+ }
190
+ };
191
+
192
+ it('should return selling plan ids as frequencies given action SETUP_PRODUCT', () => {
193
+ const actual = config(
194
+ {},
195
+ {
196
+ type: constants.SETUP_PRODUCT,
197
+ payload: defaultSellingPlanPayload
198
+ }
199
+ );
200
+
201
+ expect(actual).toEqual(
202
+ jasmine.objectContaining({
203
+ frequencies: ['yum selling plan id 1', 'yum selling plan id 2'],
204
+ hasProductSpecificFrequencies: false
205
+ })
206
+ );
207
+ });
208
+
209
+ it('should return values of first OG selling plan group as frequencies text given action SETUP_PRODUCT', () => {
210
+ const actual = config(
211
+ {},
212
+ {
213
+ type: constants.SETUP_PRODUCT,
214
+ payload: {
215
+ product: {
216
+ selling_plan_groups: [
217
+ {
218
+ name: 'Old Selling Plan Group',
219
+ options: [{ values: 'old yum values' }],
220
+ selling_plans: [
221
+ {
222
+ id: 'old yum selling plan id'
223
+ }
224
+ ]
225
+ },
226
+ {
227
+ name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
228
+ options: [{ values: 'yum values' }],
229
+ selling_plans: [
230
+ {
231
+ id: 'yum selling plan id'
232
+ }
233
+ ]
234
+ }
235
+ ]
236
+ }
237
+ }
238
+ }
239
+ );
240
+
241
+ expect(actual).toEqual(
242
+ jasmine.objectContaining({
243
+ frequenciesText: 'yum values'
244
+ })
245
+ );
246
+ });
247
+
248
+ it('should use product-specific frequency selling plan groups if present', () => {
249
+ const actual = config(
250
+ {},
251
+ {
252
+ type: constants.SETUP_PRODUCT,
253
+ payload: {
254
+ product: {
255
+ selling_plan_groups: [
256
+ {
257
+ name: 'og_psfl_2m4m6m',
258
+ options: [
259
+ {
260
+ values: ['2 months', '4 months', '6 months']
261
+ }
262
+ ],
263
+ selling_plans: [
264
+ {
265
+ id: 'psfl-id-1'
266
+ },
267
+ {
268
+ id: 'psfl-id-2'
269
+ },
270
+ {
271
+ id: 'psfl-id-3'
272
+ }
273
+ ]
274
+ },
275
+ {
276
+ name: 'Subscribe and Save',
277
+ options: [
278
+ {
279
+ values: ['month', '2 months', '3 months']
280
+ }
281
+ ],
282
+ selling_plans: [
283
+ {
284
+ id: 'regular-id-1'
285
+ },
286
+ {
287
+ id: 'regular-id-2'
288
+ },
289
+ {
290
+ id: 'regular-id-3'
291
+ }
292
+ ]
293
+ }
294
+ ]
295
+ }
296
+ }
297
+ }
298
+ );
299
+
300
+ expect(actual).toEqual(
301
+ jasmine.objectContaining({
302
+ frequencies: ['psfl-id-1', 'psfl-id-2', 'psfl-id-3'],
303
+ hasProductSpecificFrequencies: true
304
+ })
305
+ );
306
+ });
307
+
308
+ it('does not overwrite hasProductSpecificFrequencies on subsequent calls', () => {
309
+ const actual = config(
310
+ {
311
+ hasProductSpecificFrequencies: true
312
+ },
313
+ {
314
+ type: constants.SETUP_PRODUCT,
315
+ payload: defaultSellingPlanPayload
316
+ }
317
+ );
318
+
319
+ expect(actual).toEqual(
320
+ jasmine.objectContaining({
321
+ hasProductSpecificFrequencies: true
322
+ })
323
+ );
324
+ });
325
+
326
+ it('should set prepaidSellingPlans', () => {
327
+ const sellingPlanGroups = [
328
+ {
329
+ name: 'Prepaid-43017264201944',
330
+ selling_plans: [
331
+ {
332
+ id: 2146042072,
333
+ name: 'Delivered every 2 months, prepaid for 4 shipments',
334
+ options: [
335
+ { name: 'Delivery every', position: 1, value: 'PREPAID-2 months' },
336
+ { name: 'Shipment amount', position: 2, value: '4 shipments' }
337
+ ]
338
+ }
339
+ ]
340
+ }
341
+ ];
342
+ const actual = config(
343
+ {},
344
+ {
345
+ type: constants.SETUP_PRODUCT,
346
+ payload: {
347
+ product: {
348
+ selling_plan_groups: sellingPlanGroups
349
+ }
350
+ }
351
+ }
352
+ );
353
+ expect(actual).toEqual(
354
+ jasmine.objectContaining({
355
+ prepaidSellingPlans: {
356
+ 43017264201944: [
357
+ {
358
+ numberShipments: 4,
359
+ sellingPlan: '2146042072'
360
+ }
361
+ ]
362
+ }
363
+ })
364
+ );
365
+ });
366
+
367
+ it('should add prepaidSellingPlans on top of old ones', () => {
368
+ const sellingPlanGroups = [
369
+ {
370
+ name: 'Prepaid-43017264201946',
371
+ selling_plans: [
372
+ {
373
+ id: 2146042072,
374
+ name: 'Delivered every 1 months, prepaid for 3 shipments',
375
+ options: [
376
+ { name: 'Delivery every', position: 1, value: 'PREPAID-1 months' },
377
+ { name: 'Shipment amount', position: 2, value: '3 shipments' }
378
+ ]
379
+ }
380
+ ]
381
+ },
382
+ {
383
+ name: 'Prepaid-43017264201945',
384
+ selling_plans: [
385
+ {
386
+ id: 2146042073,
387
+ name: 'Delivered every 3 months, prepaid for 5 shipments',
388
+ options: [
389
+ { name: 'Delivery every', position: 1, value: 'PREPAID-3 months' },
390
+ { name: 'Shipment amount', position: 2, value: '5 shipments' }
391
+ ]
392
+ }
393
+ ]
394
+ }
395
+ ];
396
+ const actual = config(
397
+ {
398
+ prepaidSellingPlans: {
399
+ 43017264201946: [
400
+ {
401
+ numberShipments: 1,
402
+ sellingPlan: '2146042072'
403
+ }
404
+ ],
405
+ 43017264201944: [
406
+ {
407
+ numberShipments: 4,
408
+ sellingPlan: '2146042071'
409
+ }
410
+ ]
411
+ }
412
+ },
413
+ {
414
+ type: constants.SETUP_PRODUCT,
415
+ payload: {
416
+ product: {
417
+ selling_plan_groups: sellingPlanGroups
418
+ }
419
+ }
420
+ }
421
+ );
422
+ expect(actual).toEqual(
423
+ jasmine.objectContaining({
424
+ prepaidSellingPlans: {
425
+ 43017264201944: [
426
+ {
427
+ numberShipments: 4,
428
+ sellingPlan: '2146042071'
429
+ }
430
+ ],
431
+ 43017264201946: [
432
+ {
433
+ numberShipments: 3,
434
+ sellingPlan: '2146042072'
435
+ }
436
+ ],
437
+ 43017264201945: [
438
+ {
439
+ numberShipments: 5,
440
+ sellingPlan: '2146042073'
441
+ }
442
+ ]
443
+ }
444
+ })
445
+ );
446
+ });
447
+
448
+ it('should return unmodified state given unsupported action', () => {
449
+ const actual = config(
450
+ { 'yum existing key': 'yum existing value' },
451
+ {
452
+ type: 'yum unsupported action',
453
+ payload: {}
454
+ }
455
+ );
456
+
457
+ expect(actual).toEqual({ 'yum existing key': 'yum existing value' });
458
+ });
459
+
460
+ it('should not set prepaid selling plan as a defaultFrequency', () => {
461
+ const initial = {
462
+ frequencies: ['yum selling plan id 1', 'yum selling plan id 4'],
463
+ frequenciesEveryPeriod: ['1_1', '1_4'],
464
+ prepaidSellingPlans: {
465
+ 123: [
466
+ {
467
+ sellingPlan: 'prepaid selling plan'
468
+ }
469
+ ]
470
+ },
471
+ productFrequencies: {
472
+ 123: {
473
+ frequencies: ['yum selling plan id 1', 'yum selling plan id 4'],
474
+ frequenciesEveryPeriod: ['1_1', '1_4']
475
+ }
476
+ }
477
+ };
478
+ const actual = config(initial, {
479
+ type: constants.RECEIVE_OFFER,
480
+ payload: {
481
+ offer: {
482
+ product: { id: 123 },
483
+ defaultFrequency: 'prepaid selling plan'
484
+ }
485
+ }
486
+ });
487
+ expect(actual).toEqual({
488
+ ...initial,
489
+ defaultFrequency: 'yum selling plan id 1',
490
+ productFrequencies: {
491
+ 123: jasmine.objectContaining({
492
+ defaultFrequency: 'yum selling plan id 1'
493
+ })
494
+ }
495
+ });
496
+ });
497
+ });