@ordergroove/offers 2.47.2 → 2.48.1-alpha-PR-1357-7.8
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/CHANGELOG.md +11 -0
- package/dist/bundle-report.html +20 -20
- package/dist/offers.js +38 -38
- package/dist/offers.js.map +3 -3
- package/package.json +2 -2
- package/src/components/PrepaidStatus.js +2 -1
- package/src/core/actions.js +9 -3
- package/src/core/constants.js +4 -0
- package/src/core/descriptors.js +2 -1
- package/src/core/selectors.ts +6 -0
- package/src/core/types/reducer.ts +4 -1
- package/src/shopify/__tests__/reducers/optedin.spec.js +347 -0
- package/src/shopify/reducers/config.ts +12 -5
- package/src/shopify/shopifyReducer.ts +99 -44
- package/src/shopify/utils.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ordergroove/offers",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.48.1-alpha-PR-1357-7.8+4d0ab39c0",
|
|
4
4
|
"description": "offer state component",
|
|
5
5
|
"author": "Eugenio Lattanzio <eugenio63@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/ordergroove/plush-toys#readme",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"@ordergroove/offers-templates": "^0.10.0",
|
|
50
50
|
"@types/lodash.memoize": "^4.1.9"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "4d0ab39c0427f98fdf5165d98d7b00299c4d2a34"
|
|
53
53
|
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '../core/selectors';
|
|
8
8
|
import { productChangePrepaidShipments } from '../core/actions';
|
|
9
9
|
import { withProduct } from '../core/resolveProperties';
|
|
10
|
+
import { getDefaultPrepaidOption } from '../shopify/utils';
|
|
10
11
|
|
|
11
12
|
export class PrepaidStatus extends withProduct(LitElement) {
|
|
12
13
|
static get properties() {
|
|
@@ -29,7 +30,7 @@ export class PrepaidStatus extends withProduct(LitElement) {
|
|
|
29
30
|
getDefaultPrepaidShipments() {
|
|
30
31
|
return this.options.includes(this.defaultPrepaidShipments)
|
|
31
32
|
? this.defaultPrepaidShipments
|
|
32
|
-
: this.options
|
|
33
|
+
: getDefaultPrepaidOption(this.options);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
handleSelect({ target: { value } }) {
|
package/src/core/actions.js
CHANGED
|
@@ -2,7 +2,11 @@ import { resolveAuth } from '@ordergroove/auth';
|
|
|
2
2
|
import * as constants from './constants';
|
|
3
3
|
import { api } from './api';
|
|
4
4
|
import { safeOgFrequency } from './utils';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
makeFrequencyForPrepaidShipmentsSelector,
|
|
7
|
+
makePrepaidSellingPlansSelector,
|
|
8
|
+
makeProductFrequenciesSelector
|
|
9
|
+
} from './selectors';
|
|
6
10
|
|
|
7
11
|
export const optinProduct = (product, frequency, offer) => ({
|
|
8
12
|
type: constants.OPTIN_PRODUCT,
|
|
@@ -190,10 +194,12 @@ export const requestSessionId = () => (dispatch, getState) => {
|
|
|
190
194
|
|
|
191
195
|
export const receiveOffer = (response, offer, productId) => (dispatch, getState) => {
|
|
192
196
|
// this is a thunk so that we access the state for the selector
|
|
193
|
-
const
|
|
197
|
+
const state = getState();
|
|
198
|
+
const frequencyConfig = makeProductFrequenciesSelector(productId)(state);
|
|
199
|
+
const prepaidSellingPlans = makePrepaidSellingPlansSelector(productId)(state);
|
|
194
200
|
dispatch({
|
|
195
201
|
type: constants.RECEIVE_OFFER,
|
|
196
|
-
payload: { ...response, offer, frequencyConfig }
|
|
202
|
+
payload: { ...response, offer, frequencyConfig, prepaidSellingPlans }
|
|
197
203
|
});
|
|
198
204
|
};
|
|
199
205
|
|
package/src/core/constants.js
CHANGED
package/src/core/descriptors.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ELIGIBILITY_GROUPS } from './constants';
|
|
1
2
|
import {
|
|
2
3
|
makeSubscribedSelector,
|
|
3
4
|
makeOptedoutSelector,
|
|
@@ -25,7 +26,7 @@ export const hasUpsellGroup = (state, ownProps) => {
|
|
|
25
26
|
|
|
26
27
|
export const prepaidEligible = (state, ownProps) => {
|
|
27
28
|
const groups = eligibilityGroups(state, ownProps);
|
|
28
|
-
return groups?.some(it => it ===
|
|
29
|
+
return groups?.some(it => it === ELIGIBILITY_GROUPS.PREPAID) || false;
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
export const subscribed = (state, ownProps) => makeSubscribedSelector(ownProps.product)(state);
|
package/src/core/selectors.ts
CHANGED
|
@@ -232,6 +232,12 @@ export const makeFrequencyForPrepaidShipmentsSelector = (product: BaseProduct, p
|
|
|
232
232
|
}
|
|
233
233
|
);
|
|
234
234
|
|
|
235
|
+
export const makePrepaidSellingPlansSelector = (product: string) =>
|
|
236
|
+
createSelector(prepaidSellingPlansSelector, prepaidSellingPlans => {
|
|
237
|
+
const productId = safeProductId(product);
|
|
238
|
+
return prepaidSellingPlans[productId] || [];
|
|
239
|
+
});
|
|
240
|
+
|
|
235
241
|
/** Determine the discounted price of the product, based on the incentives returned from the Offers endpoint. This assumes a pay-as-you-go subscription. */
|
|
236
242
|
export const makeDiscountedProductPriceSelector = memoize((productId: string) =>
|
|
237
243
|
createSelector(
|
|
@@ -55,11 +55,13 @@ export type ConfigState = Partial<{
|
|
|
55
55
|
* @deprecated use productFrequencies instead
|
|
56
56
|
*/
|
|
57
57
|
frequenciesText: string[];
|
|
58
|
-
prepaidSellingPlans: Record<string,
|
|
58
|
+
prepaidSellingPlans: Record<string, PrepaidSellingPlan[]>;
|
|
59
59
|
storeCurrency: string;
|
|
60
60
|
productFrequencies: Record<string, ProductFrequencyConfig>;
|
|
61
61
|
}>;
|
|
62
62
|
|
|
63
|
+
export type PrepaidSellingPlan = { numberShipments: number; sellingPlan: string };
|
|
64
|
+
|
|
63
65
|
export type ProductFrequencyConfig = {
|
|
64
66
|
frequencies?: string[];
|
|
65
67
|
frequenciesEveryPeriod?: string[];
|
|
@@ -92,6 +94,7 @@ export type ReceiveOfferPayload = OfferResponse & {
|
|
|
92
94
|
frequenciesEveryPeriod?: string[];
|
|
93
95
|
frequenciesText?: string[];
|
|
94
96
|
};
|
|
97
|
+
prepaidSellingPlans: PrepaidSellingPlan[];
|
|
95
98
|
};
|
|
96
99
|
|
|
97
100
|
export type OfferElement = InstanceType<typeof Offer> & { config: ConfigState };
|
|
@@ -2,6 +2,45 @@ import * as constants from '../../../core/constants';
|
|
|
2
2
|
import { optedin } from '../../shopifyReducer';
|
|
3
3
|
import { DEFAULT_PAY_AS_YOU_GO_GROUP_NAME } from '../../utils';
|
|
4
4
|
|
|
5
|
+
const PREPAID_PRODUCT_ID = '43017264201944';
|
|
6
|
+
const BOTH_ELIGIBLE_PRODUCT_ID = '43017264201946';
|
|
7
|
+
|
|
8
|
+
const PREPAID_PLAN_3_SHIPMENTS = 'prepaid-plan-3-shipments';
|
|
9
|
+
const PREPAID_PLAN_6_SHIPMENTS = 'prepaid-plan-6-shipments';
|
|
10
|
+
|
|
11
|
+
const prepaidPlanWith3Shipments = { sellingPlan: PREPAID_PLAN_3_SHIPMENTS, numberShipments: 3 };
|
|
12
|
+
const prepaidPlanWith6Shipments = { sellingPlan: PREPAID_PLAN_6_SHIPMENTS, numberShipments: 6 };
|
|
13
|
+
|
|
14
|
+
function buildReceiveOfferPayload(overrides = {}) {
|
|
15
|
+
return {
|
|
16
|
+
autoship: {},
|
|
17
|
+
autoship_by_default: {},
|
|
18
|
+
default_frequencies: {},
|
|
19
|
+
in_stock: {},
|
|
20
|
+
eligibility_groups: {},
|
|
21
|
+
offer: {},
|
|
22
|
+
frequencyConfig: {
|
|
23
|
+
frequencies: [],
|
|
24
|
+
frequenciesEveryPeriod: []
|
|
25
|
+
},
|
|
26
|
+
prepaidSellingPlans: [],
|
|
27
|
+
...overrides
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function buildPrepaidSellingPlanGroup(variantId, plans) {
|
|
32
|
+
return {
|
|
33
|
+
name: `Prepaid-${variantId}`,
|
|
34
|
+
selling_plans: plans.map((plan, index) => ({
|
|
35
|
+
id: plan.sellingPlan,
|
|
36
|
+
options: [
|
|
37
|
+
{ name: 'Delivery every', value: `PREPAID-${index + 1} months` },
|
|
38
|
+
{ name: 'Shipment amount', value: `${plan.numberShipments} shipments` }
|
|
39
|
+
]
|
|
40
|
+
}))
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
5
44
|
describe('optedin', () => {
|
|
6
45
|
it('should return optins given action SETUP_CART', () => {
|
|
7
46
|
const actual = optedin([], {
|
|
@@ -583,6 +622,208 @@ describe('optedin', () => {
|
|
|
583
622
|
]);
|
|
584
623
|
});
|
|
585
624
|
});
|
|
625
|
+
|
|
626
|
+
describe('given product is prepaid eligible but NOT autoship eligible', () => {
|
|
627
|
+
describe('given prepaidSellingPlans are populated', () => {
|
|
628
|
+
it('should opt into 2nd prepaid plan and set prepaidShipments when multiple plans available', () => {
|
|
629
|
+
const actual = optedin([], {
|
|
630
|
+
type: constants.RECEIVE_OFFER,
|
|
631
|
+
payload: buildReceiveOfferPayload({
|
|
632
|
+
autoship: {
|
|
633
|
+
[PREPAID_PRODUCT_ID]: false
|
|
634
|
+
},
|
|
635
|
+
autoship_by_default: {
|
|
636
|
+
[PREPAID_PRODUCT_ID]: true
|
|
637
|
+
},
|
|
638
|
+
in_stock: {
|
|
639
|
+
[PREPAID_PRODUCT_ID]: true
|
|
640
|
+
},
|
|
641
|
+
eligibility_groups: {
|
|
642
|
+
[PREPAID_PRODUCT_ID]: [constants.ELIGIBILITY_GROUPS.PREPAID]
|
|
643
|
+
},
|
|
644
|
+
prepaidSellingPlans: [prepaidPlanWith3Shipments, prepaidPlanWith6Shipments]
|
|
645
|
+
})
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
expect(actual).toEqual([
|
|
649
|
+
{
|
|
650
|
+
id: PREPAID_PRODUCT_ID,
|
|
651
|
+
frequency: PREPAID_PLAN_6_SHIPMENTS,
|
|
652
|
+
prepaidShipments: 6
|
|
653
|
+
}
|
|
654
|
+
]);
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
it('should opt into 1st prepaid plan and set prepaidShipments when only one plan available', () => {
|
|
658
|
+
const actual = optedin([], {
|
|
659
|
+
type: constants.RECEIVE_OFFER,
|
|
660
|
+
payload: buildReceiveOfferPayload({
|
|
661
|
+
autoship: {
|
|
662
|
+
[PREPAID_PRODUCT_ID]: false
|
|
663
|
+
},
|
|
664
|
+
autoship_by_default: {
|
|
665
|
+
[PREPAID_PRODUCT_ID]: true
|
|
666
|
+
},
|
|
667
|
+
in_stock: {
|
|
668
|
+
[PREPAID_PRODUCT_ID]: true
|
|
669
|
+
},
|
|
670
|
+
eligibility_groups: {
|
|
671
|
+
[PREPAID_PRODUCT_ID]: [constants.ELIGIBILITY_GROUPS.PREPAID]
|
|
672
|
+
},
|
|
673
|
+
prepaidSellingPlans: [prepaidPlanWith3Shipments]
|
|
674
|
+
})
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
expect(actual).toEqual([
|
|
678
|
+
{
|
|
679
|
+
id: PREPAID_PRODUCT_ID,
|
|
680
|
+
frequency: PREPAID_PLAN_3_SHIPMENTS,
|
|
681
|
+
prepaidShipments: 3
|
|
682
|
+
}
|
|
683
|
+
]);
|
|
684
|
+
});
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
describe('given prepaidSellingPlans are NOT populated', () => {
|
|
688
|
+
it('should opt into prepaid with PREPAID_PLACEHOLDER and prepaidShipments null', () => {
|
|
689
|
+
const actual = optedin([], {
|
|
690
|
+
type: constants.RECEIVE_OFFER,
|
|
691
|
+
payload: buildReceiveOfferPayload({
|
|
692
|
+
autoship: {
|
|
693
|
+
[PREPAID_PRODUCT_ID]: false
|
|
694
|
+
},
|
|
695
|
+
autoship_by_default: {
|
|
696
|
+
[PREPAID_PRODUCT_ID]: true
|
|
697
|
+
},
|
|
698
|
+
in_stock: {
|
|
699
|
+
[PREPAID_PRODUCT_ID]: true
|
|
700
|
+
},
|
|
701
|
+
eligibility_groups: {
|
|
702
|
+
[PREPAID_PRODUCT_ID]: [constants.ELIGIBILITY_GROUPS.PREPAID]
|
|
703
|
+
},
|
|
704
|
+
prepaidSellingPlans: []
|
|
705
|
+
})
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
expect(actual).toEqual([
|
|
709
|
+
{
|
|
710
|
+
id: PREPAID_PRODUCT_ID,
|
|
711
|
+
frequency: 'prepaid-replace-me',
|
|
712
|
+
prepaidShipments: null
|
|
713
|
+
}
|
|
714
|
+
]);
|
|
715
|
+
});
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
describe('edge cases', () => {
|
|
719
|
+
it('should not create optin when product not in stock, not autoship_by_default, or not in eligibility_groups', () => {
|
|
720
|
+
// Product not in stock
|
|
721
|
+
const notInStock = optedin([], {
|
|
722
|
+
type: constants.RECEIVE_OFFER,
|
|
723
|
+
payload: buildReceiveOfferPayload({
|
|
724
|
+
autoship: {
|
|
725
|
+
[PREPAID_PRODUCT_ID]: false
|
|
726
|
+
},
|
|
727
|
+
autoship_by_default: {
|
|
728
|
+
[PREPAID_PRODUCT_ID]: true
|
|
729
|
+
},
|
|
730
|
+
in_stock: {
|
|
731
|
+
[PREPAID_PRODUCT_ID]: false
|
|
732
|
+
},
|
|
733
|
+
eligibility_groups: {
|
|
734
|
+
[PREPAID_PRODUCT_ID]: [constants.ELIGIBILITY_GROUPS.PREPAID]
|
|
735
|
+
},
|
|
736
|
+
prepaidSellingPlans: [prepaidPlanWith3Shipments]
|
|
737
|
+
})
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
// Product not autoship_by_default
|
|
741
|
+
const notAutoshipByDefault = optedin([], {
|
|
742
|
+
type: constants.RECEIVE_OFFER,
|
|
743
|
+
payload: buildReceiveOfferPayload({
|
|
744
|
+
autoship: {
|
|
745
|
+
[PREPAID_PRODUCT_ID]: false
|
|
746
|
+
},
|
|
747
|
+
autoship_by_default: {
|
|
748
|
+
[PREPAID_PRODUCT_ID]: false
|
|
749
|
+
},
|
|
750
|
+
in_stock: {
|
|
751
|
+
[PREPAID_PRODUCT_ID]: true
|
|
752
|
+
},
|
|
753
|
+
eligibility_groups: {
|
|
754
|
+
[PREPAID_PRODUCT_ID]: [constants.ELIGIBILITY_GROUPS.PREPAID]
|
|
755
|
+
},
|
|
756
|
+
prepaidSellingPlans: [prepaidPlanWith3Shipments]
|
|
757
|
+
})
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
// Product not in eligibility_groups
|
|
761
|
+
const notInEligibilityGroups = optedin([], {
|
|
762
|
+
type: constants.RECEIVE_OFFER,
|
|
763
|
+
payload: buildReceiveOfferPayload({
|
|
764
|
+
autoship: {
|
|
765
|
+
[PREPAID_PRODUCT_ID]: false
|
|
766
|
+
},
|
|
767
|
+
autoship_by_default: {
|
|
768
|
+
[PREPAID_PRODUCT_ID]: true
|
|
769
|
+
},
|
|
770
|
+
in_stock: {
|
|
771
|
+
[PREPAID_PRODUCT_ID]: true
|
|
772
|
+
},
|
|
773
|
+
eligibility_groups: {
|
|
774
|
+
[PREPAID_PRODUCT_ID]: []
|
|
775
|
+
},
|
|
776
|
+
prepaidSellingPlans: [prepaidPlanWith3Shipments]
|
|
777
|
+
})
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
expect(notInStock).toEqual([]);
|
|
781
|
+
expect(notAutoshipByDefault).toEqual([]);
|
|
782
|
+
expect(notInEligibilityGroups).toEqual([]);
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
describe('given product is BOTH prepaid eligible AND autoship eligible', () => {
|
|
788
|
+
it('should opt into regular subscription with PSDF frequency, not prepaid', () => {
|
|
789
|
+
const actual = optedin([], {
|
|
790
|
+
type: constants.RECEIVE_OFFER,
|
|
791
|
+
payload: buildReceiveOfferPayload({
|
|
792
|
+
autoship: {
|
|
793
|
+
[BOTH_ELIGIBLE_PRODUCT_ID]: true
|
|
794
|
+
},
|
|
795
|
+
autoship_by_default: {
|
|
796
|
+
[BOTH_ELIGIBLE_PRODUCT_ID]: true
|
|
797
|
+
},
|
|
798
|
+
default_frequencies: {
|
|
799
|
+
[BOTH_ELIGIBLE_PRODUCT_ID]: {
|
|
800
|
+
every: 1,
|
|
801
|
+
every_period: 2
|
|
802
|
+
}
|
|
803
|
+
},
|
|
804
|
+
in_stock: {
|
|
805
|
+
[BOTH_ELIGIBLE_PRODUCT_ID]: true
|
|
806
|
+
},
|
|
807
|
+
eligibility_groups: {
|
|
808
|
+
[BOTH_ELIGIBLE_PRODUCT_ID]: [constants.ELIGIBILITY_GROUPS.PREPAID]
|
|
809
|
+
},
|
|
810
|
+
frequencyConfig: {
|
|
811
|
+
frequencies: ['yum selling plan id 1', 'yum selling plan id 2'],
|
|
812
|
+
frequenciesEveryPeriod: ['1_1', '1_2']
|
|
813
|
+
},
|
|
814
|
+
prepaidSellingPlans: [prepaidPlanWith3Shipments, prepaidPlanWith6Shipments]
|
|
815
|
+
})
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
expect(actual).toEqual([
|
|
819
|
+
{
|
|
820
|
+
id: BOTH_ELIGIBLE_PRODUCT_ID,
|
|
821
|
+
frequency: 'yum selling plan id 2'
|
|
822
|
+
}
|
|
823
|
+
]);
|
|
824
|
+
expect(actual[0].prepaidShipments).toBeUndefined();
|
|
825
|
+
});
|
|
826
|
+
});
|
|
586
827
|
});
|
|
587
828
|
});
|
|
588
829
|
|
|
@@ -756,6 +997,69 @@ describe('optedin', () => {
|
|
|
756
997
|
}
|
|
757
998
|
]);
|
|
758
999
|
});
|
|
1000
|
+
|
|
1001
|
+
describe('given frequency is PREPAID_PLACEHOLDER', () => {
|
|
1002
|
+
describe('given prepaidSellingPlans exist for variant', () => {
|
|
1003
|
+
it('should replace prepaid placeholder optin', () => {
|
|
1004
|
+
const actual = optedin(
|
|
1005
|
+
[
|
|
1006
|
+
{
|
|
1007
|
+
id: PREPAID_PRODUCT_ID,
|
|
1008
|
+
frequency: 'prepaid-replace-me',
|
|
1009
|
+
prepaidShipments: null
|
|
1010
|
+
}
|
|
1011
|
+
],
|
|
1012
|
+
{
|
|
1013
|
+
type: constants.SETUP_PRODUCT,
|
|
1014
|
+
payload: {
|
|
1015
|
+
product: {
|
|
1016
|
+
variants: [{ id: PREPAID_PRODUCT_ID }],
|
|
1017
|
+
selling_plan_groups: [
|
|
1018
|
+
buildPrepaidSellingPlanGroup(PREPAID_PRODUCT_ID, [
|
|
1019
|
+
prepaidPlanWith3Shipments,
|
|
1020
|
+
prepaidPlanWith6Shipments
|
|
1021
|
+
])
|
|
1022
|
+
]
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
);
|
|
1027
|
+
|
|
1028
|
+
expect(actual).toEqual([
|
|
1029
|
+
{
|
|
1030
|
+
id: PREPAID_PRODUCT_ID,
|
|
1031
|
+
frequency: PREPAID_PLAN_6_SHIPMENTS,
|
|
1032
|
+
prepaidShipments: 6
|
|
1033
|
+
}
|
|
1034
|
+
]);
|
|
1035
|
+
});
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
describe('given prepaidSellingPlans do NOT exist for variant', () => {
|
|
1039
|
+
it('should remove placeholder optin', () => {
|
|
1040
|
+
const actual = optedin(
|
|
1041
|
+
[
|
|
1042
|
+
{
|
|
1043
|
+
id: PREPAID_PRODUCT_ID,
|
|
1044
|
+
frequency: 'prepaid-replace-me',
|
|
1045
|
+
prepaidShipments: null
|
|
1046
|
+
}
|
|
1047
|
+
],
|
|
1048
|
+
{
|
|
1049
|
+
type: constants.SETUP_PRODUCT,
|
|
1050
|
+
payload: {
|
|
1051
|
+
product: {
|
|
1052
|
+
variants: [{ id: PREPAID_PRODUCT_ID }],
|
|
1053
|
+
selling_plan_groups: []
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
);
|
|
1058
|
+
|
|
1059
|
+
expect(actual).toEqual([]);
|
|
1060
|
+
});
|
|
1061
|
+
});
|
|
1062
|
+
});
|
|
759
1063
|
});
|
|
760
1064
|
|
|
761
1065
|
describe('given action is PRODUCT_CHANGE_PREPAID_SHIPMENTS', () => {
|
|
@@ -807,6 +1111,49 @@ describe('optedin', () => {
|
|
|
807
1111
|
});
|
|
808
1112
|
});
|
|
809
1113
|
|
|
1114
|
+
it('integration: SETUP_PRODUCT after RECEIVE_OFFER should handle default prepaid optin', () => {
|
|
1115
|
+
// Step 1: RECEIVE_OFFER creates optin with placeholder (no prepaidSellingPlans available yet)
|
|
1116
|
+
const afterReceiveOffer = optedin([], {
|
|
1117
|
+
type: constants.RECEIVE_OFFER,
|
|
1118
|
+
payload: buildReceiveOfferPayload({
|
|
1119
|
+
autoship: {
|
|
1120
|
+
[PREPAID_PRODUCT_ID]: false
|
|
1121
|
+
},
|
|
1122
|
+
autoship_by_default: {
|
|
1123
|
+
[PREPAID_PRODUCT_ID]: true
|
|
1124
|
+
},
|
|
1125
|
+
in_stock: {
|
|
1126
|
+
[PREPAID_PRODUCT_ID]: true
|
|
1127
|
+
},
|
|
1128
|
+
eligibility_groups: {
|
|
1129
|
+
[PREPAID_PRODUCT_ID]: [constants.ELIGIBILITY_GROUPS.PREPAID]
|
|
1130
|
+
},
|
|
1131
|
+
prepaidSellingPlans: []
|
|
1132
|
+
})
|
|
1133
|
+
});
|
|
1134
|
+
|
|
1135
|
+
// Step 2: SETUP_PRODUCT replaces placeholder with actual selling plan
|
|
1136
|
+
const afterSetupProduct = optedin(afterReceiveOffer, {
|
|
1137
|
+
type: constants.SETUP_PRODUCT,
|
|
1138
|
+
payload: {
|
|
1139
|
+
product: {
|
|
1140
|
+
variants: [{ id: PREPAID_PRODUCT_ID }],
|
|
1141
|
+
selling_plan_groups: [
|
|
1142
|
+
buildPrepaidSellingPlanGroup(PREPAID_PRODUCT_ID, [prepaidPlanWith3Shipments, prepaidPlanWith6Shipments])
|
|
1143
|
+
]
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
|
|
1148
|
+
expect(afterSetupProduct).toEqual([
|
|
1149
|
+
{
|
|
1150
|
+
id: PREPAID_PRODUCT_ID,
|
|
1151
|
+
frequency: PREPAID_PLAN_6_SHIPMENTS,
|
|
1152
|
+
prepaidShipments: 6
|
|
1153
|
+
}
|
|
1154
|
+
]);
|
|
1155
|
+
});
|
|
1156
|
+
|
|
810
1157
|
it('should return unmodified state given unsupported action', () => {
|
|
811
1158
|
const actual = optedin(
|
|
812
1159
|
{ 'yum existing key': 'yum existing value' },
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
sellingPlansToFrequencies,
|
|
14
14
|
getPrepaidShipments
|
|
15
15
|
} from '../utils';
|
|
16
|
-
import { ShopifySellingPlanGroupsEntity, ShopifyVariantsEntity } from '../types/shopify';
|
|
16
|
+
import { ShopifyProductEntity, ShopifySellingPlanGroupsEntity, ShopifyVariantsEntity } from '../types/shopify';
|
|
17
17
|
|
|
18
18
|
const config = (
|
|
19
19
|
state: ConfigState = {
|
|
@@ -48,11 +48,11 @@ const config = (
|
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
// prepaid selling plans
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
51
|
+
const prepaidSellingPlans = getPrepaidSellingPlans(product);
|
|
52
|
+
if (Object.keys(prepaidSellingPlans).length) {
|
|
53
53
|
configToAdd = {
|
|
54
54
|
...configToAdd,
|
|
55
|
-
prepaidSellingPlans: { ...state.prepaidSellingPlans, ...
|
|
55
|
+
prepaidSellingPlans: { ...state.prepaidSellingPlans, ...prepaidSellingPlans }
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
return {
|
|
@@ -177,7 +177,14 @@ function getUpdatedDefaultFrequency(
|
|
|
177
177
|
);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
function getPrepaidSellingPlans(
|
|
180
|
+
export function getPrepaidSellingPlans(
|
|
181
|
+
product: ShopifyProductEntity
|
|
182
|
+
): Record<string, { numberShipments: number; sellingPlan: string }[]> {
|
|
183
|
+
const prepaidSellingPlanGroups = product?.selling_plan_groups.filter(group => /^Prepaid-.*/.test(group.name));
|
|
184
|
+
if (!prepaidSellingPlanGroups.length) {
|
|
185
|
+
return {};
|
|
186
|
+
}
|
|
187
|
+
|
|
181
188
|
return prepaidSellingPlanGroups.reduce((acc, cur) => {
|
|
182
189
|
const variant = cur.name.split('-')[1];
|
|
183
190
|
|