@ordergroove/offers 2.29.0 → 2.29.1-alpha-PR-707-2.113
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/README.md +22 -1
- package/dist/bundle-report.html +72 -59
- package/dist/examples.js +262 -105
- package/dist/examples.js.map +2 -2
- package/dist/offers.js +82 -32
- package/dist/offers.js.map +3 -3
- package/examples/index.js +230 -218
- package/package.json +2 -2
- package/src/components/PrepaidData.js +110 -0
- package/src/components/PrepaidToggle.js +108 -0
- package/src/components/Price.js +6 -6
- package/src/components/Select.js +6 -1
- package/src/components/__tests__/PrepaidData.spec.js +173 -0
- package/src/components/__tests__/PrepaidToggle.spec.js +115 -0
- package/src/components/__tests__/Price.spec.js +96 -0
- package/src/core/__tests__/adapters.spec.js +232 -1
- package/src/core/__tests__/descriptors.spec.js +56 -0
- package/src/core/__tests__/reducer.spec.js +153 -1
- package/src/core/__tests__/selectors.spec.js +34 -1
- package/src/core/actions.js +5 -0
- package/src/core/adapters.js +48 -2
- package/src/core/constants.js +1 -0
- package/src/core/descriptors.js +7 -1
- package/src/core/reducer.js +35 -14
- package/src/core/selectors.js +32 -0
- package/src/core/utils.ts +16 -0
- package/src/make-api.js +4 -0
- package/src/shopify/__tests__/productPlan.spec.js +513 -0
- package/src/shopify/__tests__/shopifyReducer.spec.js +630 -19
- package/src/shopify/__tests__/utils.spec.js +25 -0
- package/src/shopify/reducers/productPlans.ts +134 -0
- package/src/shopify/shopifyMiddleware.ts +3 -0
- package/src/shopify/shopifyReducer.js +96 -47
- package/src/shopify/shopifyTrackingMiddleware.ts +1 -1
- package/src/shopify/types/productPlan.ts +11 -0
- package/src/shopify/types/shopify.ts +98 -0
- package/src/shopify/utils.ts +3 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getProductsForPurchasePost } from '../adapters';
|
|
1
|
+
import { getProductsForPurchasePost, getObjectStructuredProductPlans } from '../adapters';
|
|
2
2
|
|
|
3
3
|
describe('adapters', () => {
|
|
4
4
|
describe('getProductsForPurchasePost', () => {
|
|
@@ -249,4 +249,235 @@ describe('adapters', () => {
|
|
|
249
249
|
expect(actual).toEqual(expected);
|
|
250
250
|
});
|
|
251
251
|
});
|
|
252
|
+
|
|
253
|
+
describe('getObjectStructuredProductPlans', () => {
|
|
254
|
+
it('Should return empty objects if no variants are present on productPlan', () => {
|
|
255
|
+
const productPlans = {};
|
|
256
|
+
const expected = {};
|
|
257
|
+
|
|
258
|
+
const actual = getObjectStructuredProductPlans(productPlans);
|
|
259
|
+
expect(actual).toEqual(expected);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('Should return object structured productPlans if receives array structured variants', () => {
|
|
263
|
+
const productPlans = {
|
|
264
|
+
'variant-1': {
|
|
265
|
+
'1_3': ['$15.00', '10%', '$13.50'],
|
|
266
|
+
'2_3': ['$15.00', '10%', '$13.50'],
|
|
267
|
+
'3_3': ['$15.00', '20%', '$12.00']
|
|
268
|
+
},
|
|
269
|
+
'variant-2': {
|
|
270
|
+
'1_3': ['$30.00', '10%', '$27.00'],
|
|
271
|
+
'2_3': ['$30.00', '10%', '$27.00'],
|
|
272
|
+
'3_3': ['$30.00', '20%', '$24.00']
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const expected = {
|
|
277
|
+
'variant-1': [
|
|
278
|
+
{
|
|
279
|
+
frequency: '1_3',
|
|
280
|
+
prepaidShipments: null,
|
|
281
|
+
regularPrice: '$15.00',
|
|
282
|
+
subscriptionPrice: '$13.50',
|
|
283
|
+
discountRate: '10%'
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
frequency: '2_3',
|
|
287
|
+
prepaidShipments: null,
|
|
288
|
+
regularPrice: '$15.00',
|
|
289
|
+
subscriptionPrice: '$13.50',
|
|
290
|
+
discountRate: '10%'
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
frequency: '3_3',
|
|
294
|
+
prepaidShipments: null,
|
|
295
|
+
regularPrice: '$15.00',
|
|
296
|
+
subscriptionPrice: '$12.00',
|
|
297
|
+
discountRate: '20%'
|
|
298
|
+
}
|
|
299
|
+
],
|
|
300
|
+
|
|
301
|
+
'variant-2': [
|
|
302
|
+
{
|
|
303
|
+
frequency: '1_3',
|
|
304
|
+
prepaidShipments: null,
|
|
305
|
+
regularPrice: '$30.00',
|
|
306
|
+
subscriptionPrice: '$27.00',
|
|
307
|
+
discountRate: '10%'
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
frequency: '2_3',
|
|
311
|
+
prepaidShipments: null,
|
|
312
|
+
regularPrice: '$30.00',
|
|
313
|
+
subscriptionPrice: '$27.00',
|
|
314
|
+
discountRate: '10%'
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
frequency: '3_3',
|
|
318
|
+
prepaidShipments: null,
|
|
319
|
+
regularPrice: '$30.00',
|
|
320
|
+
subscriptionPrice: '$24.00',
|
|
321
|
+
discountRate: '20%'
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const actual = getObjectStructuredProductPlans(productPlans);
|
|
327
|
+
expect(actual).toEqual(expected);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('Should return object structured productPlans if receives object structured variants', () => {
|
|
331
|
+
const productPlans = {
|
|
332
|
+
'variant-1': [
|
|
333
|
+
{
|
|
334
|
+
frequency: '1_3',
|
|
335
|
+
prepaidShipments: null,
|
|
336
|
+
regularPrice: '$15.00',
|
|
337
|
+
subscriptionPrice: '$13.50',
|
|
338
|
+
discountRate: '10%'
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
frequency: '2_3',
|
|
342
|
+
prepaidShipments: null,
|
|
343
|
+
regularPrice: '$15.00',
|
|
344
|
+
subscriptionPrice: '$13.50',
|
|
345
|
+
discountRate: '10%'
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
frequency: '3_3',
|
|
349
|
+
prepaidShipments: null,
|
|
350
|
+
regularPrice: '$15.00',
|
|
351
|
+
subscriptionPrice: '$12.00',
|
|
352
|
+
discountRate: '20%'
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
frequency: '1_3',
|
|
356
|
+
prepaidShipments: 3,
|
|
357
|
+
regularPrice: '$15.00',
|
|
358
|
+
subscriptionPrice: '$12.00',
|
|
359
|
+
discountRate: '20%'
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
'variant-2': [
|
|
363
|
+
{
|
|
364
|
+
frequency: '1_3',
|
|
365
|
+
prepaidShipments: null,
|
|
366
|
+
regularPrice: '$30.00',
|
|
367
|
+
subscriptionPrice: '$27.00',
|
|
368
|
+
discountRate: '10%'
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
frequency: '2_3',
|
|
372
|
+
prepaidShipments: null,
|
|
373
|
+
regularPrice: '$30.00',
|
|
374
|
+
subscriptionPrice: '$27.00',
|
|
375
|
+
discountRate: '10%'
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
frequency: '3_3',
|
|
379
|
+
prepaidShipments: null,
|
|
380
|
+
regularPrice: '$30.00',
|
|
381
|
+
subscriptionPrice: '$24.00',
|
|
382
|
+
discountRate: '20%'
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
frequency: '1_3',
|
|
386
|
+
prepaidShipments: 6,
|
|
387
|
+
regularPrice: '$15.00',
|
|
388
|
+
subscriptionPrice: '$12.00',
|
|
389
|
+
discountRate: '20%'
|
|
390
|
+
}
|
|
391
|
+
]
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const actual = getObjectStructuredProductPlans(productPlans);
|
|
395
|
+
expect(actual).toEqual(productPlans);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it('Should return object structured productPlans if receives payload with mixed structures', () => {
|
|
399
|
+
const productPlans = {
|
|
400
|
+
'variant-1': {
|
|
401
|
+
'1_3': ['$15.00', '10%', '$13.50'],
|
|
402
|
+
'2_3': ['$15.00', '10%', '$13.50'],
|
|
403
|
+
'3_3': ['$15.00', '20%', '$12.00']
|
|
404
|
+
},
|
|
405
|
+
'variant-2': [
|
|
406
|
+
{
|
|
407
|
+
frequency: '1_3',
|
|
408
|
+
prepaidShipments: null,
|
|
409
|
+
regularPrice: '$30.00',
|
|
410
|
+
subscriptionPrice: '$27.00',
|
|
411
|
+
discountRate: '10%'
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
frequency: '2_3',
|
|
415
|
+
prepaidShipments: null,
|
|
416
|
+
regularPrice: '$30.00',
|
|
417
|
+
subscriptionPrice: '$27.00',
|
|
418
|
+
discountRate: '10%'
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
frequency: '3_3',
|
|
422
|
+
prepaidShipments: 3,
|
|
423
|
+
regularPrice: '$30.00',
|
|
424
|
+
subscriptionPrice: '$24.00',
|
|
425
|
+
discountRate: '20%'
|
|
426
|
+
}
|
|
427
|
+
]
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
const expected = {
|
|
431
|
+
'variant-1': [
|
|
432
|
+
{
|
|
433
|
+
frequency: '1_3',
|
|
434
|
+
prepaidShipments: null,
|
|
435
|
+
regularPrice: '$15.00',
|
|
436
|
+
subscriptionPrice: '$13.50',
|
|
437
|
+
discountRate: '10%'
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
frequency: '2_3',
|
|
441
|
+
prepaidShipments: null,
|
|
442
|
+
regularPrice: '$15.00',
|
|
443
|
+
subscriptionPrice: '$13.50',
|
|
444
|
+
discountRate: '10%'
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
frequency: '3_3',
|
|
448
|
+
prepaidShipments: null,
|
|
449
|
+
regularPrice: '$15.00',
|
|
450
|
+
subscriptionPrice: '$12.00',
|
|
451
|
+
discountRate: '20%'
|
|
452
|
+
}
|
|
453
|
+
],
|
|
454
|
+
'variant-2': [
|
|
455
|
+
{
|
|
456
|
+
frequency: '1_3',
|
|
457
|
+
prepaidShipments: null,
|
|
458
|
+
regularPrice: '$30.00',
|
|
459
|
+
subscriptionPrice: '$27.00',
|
|
460
|
+
discountRate: '10%'
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
frequency: '2_3',
|
|
464
|
+
prepaidShipments: null,
|
|
465
|
+
regularPrice: '$30.00',
|
|
466
|
+
subscriptionPrice: '$27.00',
|
|
467
|
+
discountRate: '10%'
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
frequency: '3_3',
|
|
471
|
+
prepaidShipments: 3,
|
|
472
|
+
regularPrice: '$30.00',
|
|
473
|
+
subscriptionPrice: '$24.00',
|
|
474
|
+
discountRate: '20%'
|
|
475
|
+
}
|
|
476
|
+
]
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const actual = getObjectStructuredProductPlans(productPlans);
|
|
480
|
+
expect(actual).toEqual(expected);
|
|
481
|
+
});
|
|
482
|
+
});
|
|
252
483
|
});
|
|
@@ -228,3 +228,59 @@ describe('upcomingOrderContainsProduct', () => {
|
|
|
228
228
|
).toEqual(false);
|
|
229
229
|
});
|
|
230
230
|
});
|
|
231
|
+
|
|
232
|
+
describe('prepaidEligible', () => {
|
|
233
|
+
it('should return false if no eligibilityGroups at all', () => {
|
|
234
|
+
expect(descriptors.prepaidEligible({}, ownProps)).toBe(false);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should return true if it has the prepaid group', () => {
|
|
238
|
+
expect(
|
|
239
|
+
descriptors.prepaidEligible(
|
|
240
|
+
{
|
|
241
|
+
eligibilityGroups: {
|
|
242
|
+
[productId]: ['prepaid']
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
ownProps
|
|
246
|
+
)
|
|
247
|
+
).toBe(true);
|
|
248
|
+
expect(
|
|
249
|
+
descriptors.prepaidEligible(
|
|
250
|
+
{
|
|
251
|
+
eligibilityGroups: {
|
|
252
|
+
[productId]: []
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
ownProps
|
|
256
|
+
)
|
|
257
|
+
).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
function getPrepaidOptedinState(id, prepaidShipments) {
|
|
262
|
+
const frequency = '1_3';
|
|
263
|
+
return {
|
|
264
|
+
optedin: [
|
|
265
|
+
{
|
|
266
|
+
id,
|
|
267
|
+
frequency,
|
|
268
|
+
prepaidShipments
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
describe('prepaidSubscribed', () => {
|
|
275
|
+
it('returns false when prepaidShipments is not set', () => {
|
|
276
|
+
expect(descriptors.prepaidSubscribed(getPrepaidOptedinState(productId, undefined), ownProps)).toBe(false);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('returns true when prepaidShipments is set', () => {
|
|
280
|
+
expect(descriptors.prepaidSubscribed(getPrepaidOptedinState(productId, 3), ownProps)).toBe(true);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('returns false when prepaidShipments is set for another product', () => {
|
|
284
|
+
expect(descriptors.prepaidSubscribed(getPrepaidOptedinState('otherProduct', 3), ownProps)).toBe(false);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
@@ -9,9 +9,12 @@ import {
|
|
|
9
9
|
nextUpcomingOrder,
|
|
10
10
|
productOffer,
|
|
11
11
|
eligibilityGroups,
|
|
12
|
-
defaultFrequencies
|
|
12
|
+
defaultFrequencies,
|
|
13
|
+
productPlans,
|
|
14
|
+
prepaidShipmentsSelected
|
|
13
15
|
} from '../reducer';
|
|
14
16
|
import * as constants from '../constants';
|
|
17
|
+
import { getObjectStructuredProductPlans } from '../adapters';
|
|
15
18
|
|
|
16
19
|
describe('reducers', () => {
|
|
17
20
|
function testMergeReducerWithActionAndPayload(reducerFn, actionType, payload) {
|
|
@@ -60,6 +63,85 @@ describe('reducers', () => {
|
|
|
60
63
|
expect(actual).toEqual([{ id: 'product 3', frequency: '1_2' }]);
|
|
61
64
|
});
|
|
62
65
|
|
|
66
|
+
it('should remove existing prepaidShipments given action PRODUCT_CHANGE_FREQUENCY', () => {
|
|
67
|
+
const actual = optedin(
|
|
68
|
+
[
|
|
69
|
+
{
|
|
70
|
+
id: productToTest.id,
|
|
71
|
+
frequency: '1_3',
|
|
72
|
+
prepaidShipments: 2
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
{
|
|
76
|
+
type: constants.PRODUCT_CHANGE_FREQUENCY,
|
|
77
|
+
payload: {
|
|
78
|
+
product: productToTest,
|
|
79
|
+
frequency: '1_2'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
expect(actual).toEqual([{ id: 'product 3', frequency: '1_2' }]);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should remove existing prepaidShipments given action OPTIN_PRODUCT', () => {
|
|
87
|
+
const actual = optedin(
|
|
88
|
+
[
|
|
89
|
+
{
|
|
90
|
+
id: productToTest.id,
|
|
91
|
+
frequency: '1_3',
|
|
92
|
+
prepaidShipments: 2
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
{
|
|
96
|
+
type: constants.OPTIN_PRODUCT,
|
|
97
|
+
payload: {
|
|
98
|
+
product: productToTest,
|
|
99
|
+
frequency: '1_2'
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
expect(actual).toEqual([{ id: 'product 3', frequency: '1_2' }]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should set prepaidShipments given action PRODUCT_CHANGE_PREPAID_SHIPMENTS', () => {
|
|
107
|
+
const actual = optedin(
|
|
108
|
+
[
|
|
109
|
+
{
|
|
110
|
+
id: productToTest.id,
|
|
111
|
+
frequency: '1_3'
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
{
|
|
115
|
+
type: constants.PRODUCT_CHANGE_PREPAID_SHIPMENTS,
|
|
116
|
+
payload: {
|
|
117
|
+
product: productToTest,
|
|
118
|
+
prepaidShipments: 3
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
expect(actual).toEqual([{ id: 'product 3', frequency: '1_3', prepaidShipments: 3 }]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should remove prepaidShipments given action PRODUCT_CHANGE_PREPAID_SHIPMENTS with null', () => {
|
|
126
|
+
const actual = optedin(
|
|
127
|
+
[
|
|
128
|
+
{
|
|
129
|
+
id: productToTest.id,
|
|
130
|
+
frequency: '1_3',
|
|
131
|
+
prepaidShipments: 3
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
{
|
|
135
|
+
type: constants.PRODUCT_CHANGE_PREPAID_SHIPMENTS,
|
|
136
|
+
payload: {
|
|
137
|
+
product: productToTest,
|
|
138
|
+
prepaidShipments: null
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
expect(actual).toEqual([{ id: 'product 3', frequency: '1_3' }]);
|
|
143
|
+
});
|
|
144
|
+
|
|
63
145
|
it('should return empty array given OPTOUT_PRODUCT', () => {
|
|
64
146
|
const actual = optedin([], {
|
|
65
147
|
type: constants.OPTOUT_PRODUCT,
|
|
@@ -829,4 +911,74 @@ describe('reducers', () => {
|
|
|
829
911
|
).toEqual({ foo: '1_w', bar: '2_w' });
|
|
830
912
|
});
|
|
831
913
|
});
|
|
914
|
+
|
|
915
|
+
describe('productPlans', () => {
|
|
916
|
+
it('should return object structure payload given action RECEIVE_PRODUCT_PLANS using getObjectStructuredProductPlans', () => {
|
|
917
|
+
const payload = {
|
|
918
|
+
'variant-1': {
|
|
919
|
+
'1_3': ['$15.00', '10%', '$13.50'],
|
|
920
|
+
'2_3': ['$15.00', '10%', '$13.50'],
|
|
921
|
+
'3_3': ['$15.00', '20%', '$12.00']
|
|
922
|
+
},
|
|
923
|
+
'variant-2': [
|
|
924
|
+
{
|
|
925
|
+
frequency: '1_3',
|
|
926
|
+
prepaidShipments: null,
|
|
927
|
+
regularPrice: '$30.00',
|
|
928
|
+
subscriptionPrice: '$27.00',
|
|
929
|
+
discountRate: '10%'
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
frequency: '2_3',
|
|
933
|
+
prepaidShipments: null,
|
|
934
|
+
regularPrice: '$30.00',
|
|
935
|
+
subscriptionPrice: '$27.00',
|
|
936
|
+
discountRate: '10%'
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
frequency: '3_3',
|
|
940
|
+
prepaidShipments: 3,
|
|
941
|
+
regularPrice: '$30.00',
|
|
942
|
+
subscriptionPrice: '$24.00',
|
|
943
|
+
discountRate: '20%'
|
|
944
|
+
}
|
|
945
|
+
]
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
const actual = productPlans(
|
|
949
|
+
{},
|
|
950
|
+
{
|
|
951
|
+
type: constants.RECEIVE_PRODUCT_PLANS,
|
|
952
|
+
payload: payload
|
|
953
|
+
}
|
|
954
|
+
);
|
|
955
|
+
|
|
956
|
+
expect(actual).toEqual(getObjectStructuredProductPlans(payload));
|
|
957
|
+
});
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
describe('prepaidShipmentsSelected', () => {
|
|
961
|
+
const productToTest = {
|
|
962
|
+
id: 'product 3'
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
it('should set prepaidShipmentsSelected for product given action PRODUCT_CHANGE_PREPAID_SHIPMENTS', () => {
|
|
966
|
+
const actual = prepaidShipmentsSelected(
|
|
967
|
+
{
|
|
968
|
+
'other-product-id': 3
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
type: constants.PRODUCT_CHANGE_PREPAID_SHIPMENTS,
|
|
972
|
+
payload: {
|
|
973
|
+
product: productToTest,
|
|
974
|
+
prepaidShipments: 6
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
);
|
|
978
|
+
expect(actual).toEqual({
|
|
979
|
+
'other-product-id': 3,
|
|
980
|
+
[productToTest.id]: 6
|
|
981
|
+
});
|
|
982
|
+
});
|
|
983
|
+
});
|
|
832
984
|
});
|
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
makeOptedinSelector,
|
|
4
4
|
isSameProduct,
|
|
5
5
|
templatesSelector,
|
|
6
|
-
makeProductDefaultFrequencySelector
|
|
6
|
+
makeProductDefaultFrequencySelector,
|
|
7
|
+
makeProductPrepaidShipmentOptionsSelector
|
|
7
8
|
} from '../selectors';
|
|
8
9
|
import { stringifyFrequency } from '../api';
|
|
9
10
|
|
|
@@ -85,3 +86,35 @@ describe('makeProductDefaultFrequencySelector', () => {
|
|
|
85
86
|
);
|
|
86
87
|
});
|
|
87
88
|
});
|
|
89
|
+
|
|
90
|
+
describe('makeProductPrepaidShipmentOptionsSelector', () => {
|
|
91
|
+
it('should retrieve product prepaid shipment options', () => {
|
|
92
|
+
const selector = makeProductPrepaidShipmentOptionsSelector(123);
|
|
93
|
+
expect(
|
|
94
|
+
selector({
|
|
95
|
+
config: {
|
|
96
|
+
prepaidSellingPlans: {
|
|
97
|
+
123: [
|
|
98
|
+
{
|
|
99
|
+
numberShipments: 3
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
numberShipments: 6
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
).toEqual([3, 6]);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should handle missing prepaidSellingPlans', () => {
|
|
112
|
+
const selector = makeProductPrepaidShipmentOptionsSelector(123);
|
|
113
|
+
expect(selector({ config: {} })).toEqual([]);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should handle missing product', () => {
|
|
117
|
+
const selector = makeProductPrepaidShipmentOptionsSelector(123);
|
|
118
|
+
expect(selector({ config: { prepaidSellingPlans: { 456: [{ numberShipments: 3 }] } } })).toEqual([]);
|
|
119
|
+
});
|
|
120
|
+
});
|
package/src/core/actions.js
CHANGED
|
@@ -23,6 +23,11 @@ export const productChangeFrequency = (product, frequency, offer) => ({
|
|
|
23
23
|
payload: { product, frequency, offer }
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
+
export const productChangePrepaidShipments = (product, prepaidShipments, offer) => ({
|
|
27
|
+
type: constants.PRODUCT_CHANGE_PREPAID_SHIPMENTS,
|
|
28
|
+
payload: { product, prepaidShipments, offer }
|
|
29
|
+
});
|
|
30
|
+
|
|
26
31
|
export const concludeUpsell = product => ({
|
|
27
32
|
type: constants.CONCLUDE_UPSELL,
|
|
28
33
|
payload: { product }
|
package/src/core/adapters.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { parseFrequency } from './api';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Convert the current redux state to purchase
|
|
6
6
|
* post compatible json
|
|
7
7
|
*/
|
|
8
8
|
export const getProductsForPurchasePost = (state = {}, productIds = []) =>
|
|
@@ -29,4 +29,50 @@ export const getProductsForPurchasePost = (state = {}, productIds = []) =>
|
|
|
29
29
|
.filter(optin => optin.tracking_override.offer)
|
|
30
30
|
.filter(optin => (productIds.length ? productIds.includes(optin.product) : optin));
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Convert the old redux state from productPlans that was array structured:
|
|
34
|
+
* {
|
|
35
|
+
* '1_2': ['$15.00', '10%', '$13.50'],
|
|
36
|
+
* '2_2': ['$15.00', '10%', '$13.50']
|
|
37
|
+
* }
|
|
38
|
+
* to a object structured one that can hold more information with keys:
|
|
39
|
+
* [
|
|
40
|
+
* {
|
|
41
|
+
* frequency: '1_2',
|
|
42
|
+
* prepaidShipments: '3' or null,
|
|
43
|
+
* regularPrice: '$15.00',
|
|
44
|
+
* subscriptionPrice: '$13.50',
|
|
45
|
+
* discountRate: '10%'
|
|
46
|
+
* },
|
|
47
|
+
* ]
|
|
48
|
+
*/
|
|
49
|
+
export const getObjectStructuredProductPlans = (productPlans = {}) => {
|
|
50
|
+
const adaptedProductPlans = {};
|
|
51
|
+
|
|
52
|
+
Object.entries(productPlans).forEach(([productVariant, productPlanOnArrayStructure]) => {
|
|
53
|
+
Object.entries(productPlanOnArrayStructure).forEach(([frequencyAsKey, arrayPrices]) => {
|
|
54
|
+
let newProductPlanStructure = {};
|
|
55
|
+
if (arrayPrices && !Array.isArray(arrayPrices)) {
|
|
56
|
+
newProductPlanStructure = arrayPrices;
|
|
57
|
+
} else {
|
|
58
|
+
newProductPlanStructure = {
|
|
59
|
+
frequency: frequencyAsKey,
|
|
60
|
+
prepaidShipments: null,
|
|
61
|
+
regularPrice: arrayPrices[0],
|
|
62
|
+
subscriptionPrice: arrayPrices[2],
|
|
63
|
+
discountRate: arrayPrices[1]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (adaptedProductPlans[productVariant]) {
|
|
68
|
+
adaptedProductPlans[productVariant].push(newProductPlanStructure);
|
|
69
|
+
} else {
|
|
70
|
+
adaptedProductPlans[productVariant] = [newProductPlanStructure];
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return adaptedProductPlans;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export default { getProductsForPurchasePost, getObjectStructuredProductPlans };
|
package/src/core/constants.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export const OPTIN_PRODUCT = 'OPTIN_PRODUCT';
|
|
2
2
|
export const OPTOUT_PRODUCT = 'OPTOUT_PRODUCT';
|
|
3
3
|
export const PRODUCT_CHANGE_FREQUENCY = 'PRODUCT_CHANGE_FREQUENCY';
|
|
4
|
+
export const PRODUCT_CHANGE_PREPAID_SHIPMENTS = 'PRODUCT_CHANGE_PREPAID_SHIPMENTS';
|
|
4
5
|
export const SET_MERCHANT_ID = 'SET_MERCHANT_ID';
|
|
5
6
|
export const REQUEST_OFFER = 'REQUEST_OFFER';
|
|
6
7
|
export const RECEIVE_OFFER = 'RECEIVE_OFFER';
|
package/src/core/descriptors.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { makeSubscribedSelector, makeOptedoutSelector } from './selectors';
|
|
1
|
+
import { makeSubscribedSelector, makeOptedoutSelector, makePrepaidSubscribedSelector } from './selectors';
|
|
2
2
|
|
|
3
3
|
export const inStock = (state, ownProps) => (state.inStock || {})[(ownProps.product || {}).id];
|
|
4
4
|
export const eligible = (state, ownProps) => (state.autoshipEligible || {})[(ownProps.product || {}).id] || false;
|
|
@@ -15,8 +15,14 @@ export const hasUpsellGroup = (state, ownProps) => {
|
|
|
15
15
|
return groups === null || !!groups.find(it => it === 'upsell' || it === 'impulse_upsell');
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
export const prepaidEligible = (state, ownProps) => {
|
|
19
|
+
const groups = eligibilityGroups(state, ownProps);
|
|
20
|
+
return groups?.some(it => it === 'prepaid') || false;
|
|
21
|
+
};
|
|
22
|
+
|
|
18
23
|
export const subscribed = (state, ownProps) => makeSubscribedSelector(ownProps.product)(state);
|
|
19
24
|
export const optedout = (state, ownProps) => makeOptedoutSelector(ownProps.product)(state);
|
|
25
|
+
export const prepaidSubscribed = (state, ownProps) => makePrepaidSubscribedSelector(ownProps.product)(state);
|
|
20
26
|
|
|
21
27
|
export const hasUpcomingOrder = state => !!(state.nextUpcomingOrder && state.nextUpcomingOrder.public_id);
|
|
22
28
|
|