@ordergroove/offers 2.26.10 → 2.27.1-alpha-PR-634-2.3
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 +31 -0
- package/README.md +34 -0
- package/build.js +3 -1
- package/dist/bundle-report.html +185 -116
- package/dist/examples.js +1 -0
- package/dist/examples.js.map +1 -1
- package/dist/offers.js +65 -76
- package/dist/offers.js.map +3 -3
- package/examples/cart.js +105 -0
- package/examples/index.html +2 -2
- package/examples/products/cheap-watch.js +183 -0
- package/examples/shopify-cart.html +26 -0
- package/examples/shopify-pdp.html +34 -0
- package/karma.conf.js +2 -1
- package/package.json +5 -5
- package/src/__tests__/offers.spec.js +35 -10
- package/src/components/FrequencyStatus.js +14 -11
- package/src/components/IncentiveText.js +2 -1
- package/src/components/Offer.js +14 -7
- package/src/components/OptinButton.js +1 -1
- package/src/components/OptinSelect.js +2 -2
- package/src/components/OptinToggle.js +2 -2
- package/src/components/OptoutButton.js +1 -1
- package/src/components/Price.js +7 -3
- package/src/components/Select.js +3 -13
- package/src/components/SelectFrequency.js +24 -6
- package/src/components/TestWizard.js +1 -1
- package/src/components/__tests__/OG.fspec.js +24 -0
- package/src/components/__tests__/Offer.spec.js +4 -4
- package/src/components/__tests__/OptinButton.spec.js +2 -2
- package/src/components/__tests__/OptinToggle.spec.js +2 -2
- package/src/components/__tests__/OptoutButton.spec.js +1 -1
- package/src/components/__tests__/SelectFrequency.fspec.js +1 -0
- package/src/components/__tests__/SelectFrequency.spec.js +1 -1
- package/src/components/__tests__/TestWizard.spec.js +2 -2
- package/src/components/__tests__/Text.spec.js +5 -1
- package/src/core/__tests__/actions.spec.js +6 -6
- package/src/core/actions.js +22 -17
- package/src/core/constants.js +21 -0
- package/src/core/descriptors.js +2 -1
- package/src/core/middleware.js +41 -1
- package/src/core/reducer.js +22 -21
- package/src/core/resolveProperties.js +2 -7
- package/src/core/selectors.js +1 -1
- package/src/core/store.js +17 -9
- package/src/core/utils.ts +67 -0
- package/src/index.js +46 -203
- package/src/make-api.js +195 -0
- package/src/platform.ts +9 -0
- package/src/shopify/__tests__/shopifyMiddleware.spec.js +126 -0
- package/src/shopify/__tests__/shopifyReducer.spec.js +489 -0
- package/src/shopify/shopifyBootstrap.ts +136 -0
- package/src/shopify/shopifyMiddleware.ts +336 -0
- package/src/shopify/shopifyReducer.js +254 -0
- package/tsconfig.json +35 -0
- package/examples/5starnutrition-main.js +0 -3
- package/examples/single-offer.html +0 -9
- package/src/init-test.js +0 -3
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/* eslint-disable no-case-declarations */
|
|
2
|
+
import { combineReducers } from 'redux';
|
|
3
|
+
import * as constants from '../core/constants';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
autoshipByDefault,
|
|
7
|
+
auth,
|
|
8
|
+
authUrl,
|
|
9
|
+
defaultFrequencies,
|
|
10
|
+
eligibilityGroups,
|
|
11
|
+
environment,
|
|
12
|
+
firstOrderPlaceDate,
|
|
13
|
+
incentives,
|
|
14
|
+
locale,
|
|
15
|
+
merchantId,
|
|
16
|
+
nextUpcomingOrder,
|
|
17
|
+
optedin as coreOptedin,
|
|
18
|
+
optedout,
|
|
19
|
+
previewStandardOffer,
|
|
20
|
+
previewUpsellOffer,
|
|
21
|
+
productToSubscribe,
|
|
22
|
+
sessionId,
|
|
23
|
+
templates
|
|
24
|
+
} from '../core/reducer';
|
|
25
|
+
import { safeProductId } from '../core/utils';
|
|
26
|
+
|
|
27
|
+
const money = val => (val === null ? '' : `$${val.toString().replace(/(\d\d)$/, '.$1')}`);
|
|
28
|
+
|
|
29
|
+
const percentage = val => `${val}%`;
|
|
30
|
+
|
|
31
|
+
const mapSellingPlanToDiscount = allocation => {
|
|
32
|
+
let formatted_discount = '';
|
|
33
|
+
if (allocation.price_adjustments[0]?.value_type === 'percentage') {
|
|
34
|
+
formatted_discount = percentage(allocation.price_adjustments[0].value);
|
|
35
|
+
} else if (allocation.price_adjustments[0]?.value) {
|
|
36
|
+
formatted_discount = money(allocation.price_adjustments[0].value);
|
|
37
|
+
} else if (allocation.compare_at_price) {
|
|
38
|
+
formatted_discount = money(allocation.compare_at_price - allocation.price);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (formatted_discount) {
|
|
42
|
+
return [money(allocation.compare_at_price), formatted_discount, money(allocation.price)];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return [money(allocation.price), '', money(allocation.price)];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const overrideLineKey = (state, productId, newValue) => {
|
|
49
|
+
const keys = Object.keys(state).filter(it => it.startsWith(productId.toString()));
|
|
50
|
+
if (keys.length) {
|
|
51
|
+
return { ...state, ...keys.reduce((acc, cur) => ({ ...acc, [cur]: newValue }), {}) };
|
|
52
|
+
}
|
|
53
|
+
return state;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const getOGSellingPlanGroup = product => {
|
|
57
|
+
const sellingPlanGroup = product?.selling_plan_groups.find(group => {
|
|
58
|
+
return group.name === 'Subscribe and Save';
|
|
59
|
+
});
|
|
60
|
+
return sellingPlanGroup;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const productOrVariantInStockReducer = (acc, cur) => ({
|
|
64
|
+
...overrideLineKey(acc, cur.id, cur.available),
|
|
65
|
+
[cur.id]: cur.available
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const productTrue = (acc, [id]) => ({ ...acc, [id]: true });
|
|
69
|
+
|
|
70
|
+
const sellingPlanAllocationsReducer = (acc, cur) => ({
|
|
71
|
+
...acc,
|
|
72
|
+
// now frequency every_period will match with selling_plan_id so no need to convert it
|
|
73
|
+
[cur.selling_plan_id || cur.selling_plan?.id]: mapSellingPlanToDiscount(cur)
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const reduceProductCartLine = (acc, cur) => {
|
|
77
|
+
const productId = safeProductId(cur.key);
|
|
78
|
+
return { ...acc, [cur.key]: acc[productId] || null };
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const autoshipEligible = (state = {}, action) => {
|
|
82
|
+
if (constants.RECEIVE_PRODUCT_PLANS === action.type) {
|
|
83
|
+
return Object.entries(action.payload).reduce(productTrue, state);
|
|
84
|
+
}
|
|
85
|
+
if (constants.SETUP_CART === action.type) {
|
|
86
|
+
const { payload: cart } = action;
|
|
87
|
+
return cart.items.reduce(reduceProductCartLine, state);
|
|
88
|
+
}
|
|
89
|
+
if (constants.SETUP_PRODUCT === action.type) {
|
|
90
|
+
const { payload: product } = action;
|
|
91
|
+
return [product, ...(product?.variants || [])]?.reduce(
|
|
92
|
+
(acc, cur) => ({
|
|
93
|
+
...overrideLineKey(acc, cur.id, cur.selling_plan_allocations?.length > 0),
|
|
94
|
+
[cur.id]: cur.selling_plan_allocations?.length > 0
|
|
95
|
+
}),
|
|
96
|
+
state
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return state;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const config = (
|
|
103
|
+
state = {
|
|
104
|
+
frequencies: [],
|
|
105
|
+
offerType: 'radio'
|
|
106
|
+
},
|
|
107
|
+
action
|
|
108
|
+
) => {
|
|
109
|
+
if (constants.RECEIVE_PRODUCT_PLANS === action.type) {
|
|
110
|
+
const frequencies = [
|
|
111
|
+
...new Set(
|
|
112
|
+
Object.values(action.payload)
|
|
113
|
+
.map(Object.keys)
|
|
114
|
+
.flat()
|
|
115
|
+
)
|
|
116
|
+
];
|
|
117
|
+
return {
|
|
118
|
+
...state,
|
|
119
|
+
frequencies
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (constants.SETUP_PRODUCT === action.type) {
|
|
124
|
+
const product = action.payload;
|
|
125
|
+
const sellingPlanGroup = getOGSellingPlanGroup(product);
|
|
126
|
+
const frequencies = sellingPlanGroup?.selling_plans?.map(({ id }) => `${id}`);
|
|
127
|
+
if (frequencies?.length) {
|
|
128
|
+
const frequenciesText = sellingPlanGroup.options?.[0]?.values || frequencies;
|
|
129
|
+
return {
|
|
130
|
+
...state,
|
|
131
|
+
defaultFrequency: frequencies[0],
|
|
132
|
+
frequencies,
|
|
133
|
+
frequenciesText
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return state;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const inStock = (state = {}, action) => {
|
|
142
|
+
if (constants.RECEIVE_PRODUCT_PLANS === action.type) {
|
|
143
|
+
return Object.entries(action.payload).reduce(productTrue, state);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (constants.SETUP_CART === action.type) {
|
|
147
|
+
const cart = action.payload;
|
|
148
|
+
|
|
149
|
+
return cart.items.reduce(reduceProductCartLine, state);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (constants.SETUP_PRODUCT === action.type) {
|
|
153
|
+
const product = action.payload;
|
|
154
|
+
|
|
155
|
+
return [product, ...product?.variants]?.reduce(productOrVariantInStockReducer, state) || state;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return state;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const offer = (state = {}, action) => state;
|
|
162
|
+
|
|
163
|
+
export const offerId = (state = '', action) => 'native-shopify-offer';
|
|
164
|
+
|
|
165
|
+
export const optedin = (state = [], action) => {
|
|
166
|
+
if (constants.SETUP_CART === action.type) {
|
|
167
|
+
const cart = action.payload;
|
|
168
|
+
return cart.items.reduce(
|
|
169
|
+
(acc, cur) =>
|
|
170
|
+
cur.selling_plan_allocation
|
|
171
|
+
? [...acc, { id: cur.key, frequency: `${cur.selling_plan_allocation.selling_plan.id}` }]
|
|
172
|
+
: acc,
|
|
173
|
+
[]
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
if (constants.RECEIVE_OFFER === action.type) {
|
|
177
|
+
const { autoship, autoship_by_default, in_stock, offer: offerEl } = action.payload;
|
|
178
|
+
|
|
179
|
+
return Object.keys(autoship).reduce(
|
|
180
|
+
(acc, id) =>
|
|
181
|
+
acc.concat(
|
|
182
|
+
!acc.some(it => it.id === id) && autoship[id] && autoship_by_default[id] && in_stock[id]
|
|
183
|
+
? { id, frequency: offerEl.defaultFrequency }
|
|
184
|
+
: []
|
|
185
|
+
),
|
|
186
|
+
state
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return coreOptedin(state, action);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
export const productOffer = (state = {}, action) => state;
|
|
193
|
+
|
|
194
|
+
export const productPlans = (state = {}, action) => {
|
|
195
|
+
if (constants.SETUP_PRODUCT === action.type) {
|
|
196
|
+
const product = action.payload;
|
|
197
|
+
return (
|
|
198
|
+
[product, ...product?.variants]?.reduce(
|
|
199
|
+
(acc, cur) => ({
|
|
200
|
+
...acc,
|
|
201
|
+
[cur.id]: cur.selling_plan_allocations?.reduce(sellingPlanAllocationsReducer, {})
|
|
202
|
+
}),
|
|
203
|
+
state
|
|
204
|
+
) || state
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
if (constants.SETUP_CART === action.type) {
|
|
208
|
+
const cart = action.payload;
|
|
209
|
+
return (
|
|
210
|
+
cart.items.reduce(
|
|
211
|
+
(acc, cur) =>
|
|
212
|
+
cur.selling_plan_allocation
|
|
213
|
+
? {
|
|
214
|
+
...acc,
|
|
215
|
+
[cur.key]: sellingPlanAllocationsReducer({}, cur.selling_plan_allocation)
|
|
216
|
+
}
|
|
217
|
+
: acc,
|
|
218
|
+
state
|
|
219
|
+
) || state
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
if (constants.RECEIVE_PRODUCT_PLANS === action.type) {
|
|
223
|
+
return { ...action.payload };
|
|
224
|
+
}
|
|
225
|
+
return state;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export default combineReducers({
|
|
229
|
+
auth,
|
|
230
|
+
authUrl,
|
|
231
|
+
autoshipByDefault,
|
|
232
|
+
autoshipEligible,
|
|
233
|
+
config,
|
|
234
|
+
defaultFrequencies,
|
|
235
|
+
eligibilityGroups,
|
|
236
|
+
environment,
|
|
237
|
+
firstOrderPlaceDate,
|
|
238
|
+
incentives,
|
|
239
|
+
inStock,
|
|
240
|
+
locale,
|
|
241
|
+
merchantId,
|
|
242
|
+
nextUpcomingOrder,
|
|
243
|
+
offer,
|
|
244
|
+
offerId,
|
|
245
|
+
optedin,
|
|
246
|
+
optedout,
|
|
247
|
+
previewStandardOffer,
|
|
248
|
+
previewUpsellOffer,
|
|
249
|
+
productOffer,
|
|
250
|
+
productPlans,
|
|
251
|
+
productToSubscribe,
|
|
252
|
+
sessionId,
|
|
253
|
+
templates
|
|
254
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"noEmit": true,
|
|
4
|
+
"composite": true,
|
|
5
|
+
"target": "es2019",
|
|
6
|
+
"module": "es2020",
|
|
7
|
+
"lib": ["es2020", "DOM", "DOM.Iterable"],
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"moduleResolution": "node",
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"stripInternal": true,
|
|
12
|
+
"noImplicitOverride": true,
|
|
13
|
+
"allowJs": true
|
|
14
|
+
},
|
|
15
|
+
"include": [
|
|
16
|
+
"node_modules/lit-html/lit-html.d.ts",
|
|
17
|
+
"node_modules/dayjs-es/index.d.ts",
|
|
18
|
+
"node_modules/lodash-es/index.d.ts",
|
|
19
|
+
"src/**/*.ts",
|
|
20
|
+
"src/**/*.js"
|
|
21
|
+
],
|
|
22
|
+
"typedocOptions": {
|
|
23
|
+
"name": "SMI",
|
|
24
|
+
"entryPoints": [
|
|
25
|
+
"./src/index.ts",
|
|
26
|
+
"./src/shopify.ts",
|
|
27
|
+
],
|
|
28
|
+
"out": "docs/",
|
|
29
|
+
"readme": "none",
|
|
30
|
+
"disableSources": true,
|
|
31
|
+
|
|
32
|
+
"categoryOrder": ["Type aliases", "*"],
|
|
33
|
+
"validation": { "invalidLink": true }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>Ordergroove Offers</title>
|
|
5
|
-
</head>
|
|
6
|
-
<body id="single-offer" onload="og.offers('0e5de2bedc5e11e3a2e4bc764e106cf4', 'staging')">
|
|
7
|
-
<og-offer product="UD729" id="regular1" preview-standard-offer></og-offer>
|
|
8
|
-
</body>
|
|
9
|
-
</html>
|
package/src/init-test.js
DELETED