@ordergroove/offers 2.46.0 → 2.46.1-alpha-PR-1285-2.53
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/dist/bundle-report.html +31 -31
- package/dist/offers.js +72 -72
- package/dist/offers.js.map +4 -4
- package/package.json +2 -2
- package/src/components/Offer.js +3 -1
- package/src/components/Price.js +31 -11
- package/src/components/__tests__/Price.spec.js +74 -1
- package/src/core/__tests__/experiments.spec.js +16 -3
- package/src/core/__tests__/reducer.spec.js +152 -1
- package/src/core/__tests__/selectors.spec.js +405 -1
- package/src/core/adapters.js +2 -0
- package/src/core/constants.js +7 -0
- package/src/core/experiments.js +3 -2
- package/src/core/reducer.ts +41 -9
- package/src/core/selectors.ts +66 -1
- package/src/core/types/api.ts +19 -1
- package/src/core/types/reducer.ts +14 -1
- package/src/shopify/__tests__/productPlan.spec.js +3 -3
- package/src/shopify/__tests__/shopifyMiddleware.spec.js +227 -6
- package/src/shopify/__tests__/shopifyReducer.spec.js +90 -17
- package/src/shopify/reducers/productPlans.ts +2 -1
- package/src/shopify/shopifyMiddleware.ts +45 -7
- package/src/shopify/shopifyReducer.ts +21 -0
- package/src/shopify/types/productPlan.ts +1 -0
|
@@ -14,16 +14,18 @@ import {
|
|
|
14
14
|
SETUP_PRODUCT
|
|
15
15
|
} from '../core/constants';
|
|
16
16
|
|
|
17
|
-
import { makeSubscribedSelector } from '../core/selectors';
|
|
17
|
+
import { isShopifyDiscountFunctionInUseSelector, makeSubscribedSelector } from '../core/selectors';
|
|
18
18
|
import { getOrCreateHidden, safeProductId } from '../core/utils';
|
|
19
19
|
import { getTrackingKey } from './shopifyTrackingMiddleware';
|
|
20
20
|
import { ShopifyCart, ShopifyProductEntity } from './types/shopify';
|
|
21
|
-
import { SetupProductPayload, SetupCartPayload, OfferElement } from '../core/types/reducer';
|
|
21
|
+
import { SetupProductPayload, SetupCartPayload, OfferElement, State } from '../core/types/reducer';
|
|
22
|
+
import { type Store } from 'redux';
|
|
22
23
|
|
|
23
24
|
const SHOPIFY_ROOT = window.Shopify?.routes?.root || '/';
|
|
24
25
|
const CART_PAGE_URL = '/cart';
|
|
25
26
|
const CART_JS_URL = `${SHOPIFY_ROOT}cart.js`;
|
|
26
27
|
const CART_CHANGE_URL = `${SHOPIFY_ROOT}cart/change.js`;
|
|
28
|
+
const CART_UPDATE_URL = `${SHOPIFY_ROOT}cart/update.js`;
|
|
27
29
|
const PRODUCTS_URL = `${SHOPIFY_ROOT}products/`;
|
|
28
30
|
|
|
29
31
|
/**
|
|
@@ -189,23 +191,42 @@ export async function synchronizeCartOptin(action: any, store: any) {
|
|
|
189
191
|
const qty = item.quantity;
|
|
190
192
|
const productId = safeProductId(key);
|
|
191
193
|
|
|
192
|
-
const
|
|
194
|
+
const changeRes = await fetch(CART_CHANGE_URL, {
|
|
193
195
|
method: 'POST',
|
|
194
196
|
credentials: 'same-origin',
|
|
195
197
|
headers: { 'Content-Type': 'application/json' },
|
|
196
198
|
body: JSON.stringify({
|
|
197
199
|
id: key,
|
|
198
200
|
quantity: qty,
|
|
199
|
-
attributes: Object.fromEntries([trackingEvent]),
|
|
200
201
|
properties: item.properties,
|
|
201
202
|
selling_plan: selling_plan || null,
|
|
202
203
|
sections: sectionsToUpdate.map((el: HTMLElement) => el.id.replace(/^shopify-section-/, ''))
|
|
203
204
|
})
|
|
204
205
|
});
|
|
205
206
|
|
|
206
|
-
if (
|
|
207
|
+
if (changeRes.status !== 200) throw new Error('Cart not updated');
|
|
208
|
+
|
|
209
|
+
const offerIdAttribute = getOfferIdAttribute(store);
|
|
210
|
+
const attributes = {
|
|
211
|
+
...Object.fromEntries([trackingEvent]),
|
|
212
|
+
...(offerIdAttribute ? { [OFFER_ATTRIBUTE_NAME]: offerIdAttribute } : {})
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
if (Object.keys(attributes).length > 0) {
|
|
216
|
+
// update the cart attributes
|
|
217
|
+
const updateRes = await fetch(CART_UPDATE_URL, {
|
|
218
|
+
method: 'POST',
|
|
219
|
+
credentials: 'same-origin',
|
|
220
|
+
headers: { 'Content-Type': 'application/json' },
|
|
221
|
+
body: JSON.stringify({
|
|
222
|
+
attributes
|
|
223
|
+
})
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (updateRes.status !== 200) throw new Error('Cart attributes not updated');
|
|
227
|
+
}
|
|
207
228
|
|
|
208
|
-
const newCart: ShopifyCart = await
|
|
229
|
+
const newCart: ShopifyCart = await changeRes.json();
|
|
209
230
|
|
|
210
231
|
// If both carts have same length we can update the item.key
|
|
211
232
|
// to the original offer element, at least provide
|
|
@@ -332,12 +353,23 @@ export function getSubscribedFrequency(productId, store) {
|
|
|
332
353
|
return sellingPlanId;
|
|
333
354
|
}
|
|
334
355
|
|
|
356
|
+
const OFFER_ATTRIBUTE_NAME = '__ordergroove_offer_id';
|
|
357
|
+
|
|
358
|
+
function getOfferIdAttribute(store: Store<State>) {
|
|
359
|
+
const state = store.getState();
|
|
360
|
+
// if the Shopify Discount Function is being used, we need to pass along the offer ID as a cart attribute so the discount is calculated correctly
|
|
361
|
+
if (isShopifyDiscountFunctionInUseSelector(state)) {
|
|
362
|
+
return state.offerId;
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
335
367
|
/**
|
|
336
368
|
* // update <input type="hidden" name="selling_plan"/> if available
|
|
337
369
|
*
|
|
338
370
|
* @param store
|
|
339
371
|
*/
|
|
340
|
-
function synchronizeSellingPlan(store: any, offerElement?: OfferElement) {
|
|
372
|
+
export function synchronizeSellingPlan(store: any, offerElement?: OfferElement) {
|
|
341
373
|
if (offerElement?.isCart) return; // hidden inputs are used when product page, not cart.
|
|
342
374
|
if (!offerElement?.shouldEnableOffer) return; // do not set a selling plan if we're hiding the offer
|
|
343
375
|
|
|
@@ -348,6 +380,12 @@ function synchronizeSellingPlan(store: any, offerElement?: OfferElement) {
|
|
|
348
380
|
|
|
349
381
|
getOrCreateHidden(productIdInput.form, 'selling_plan', sellingPlanId);
|
|
350
382
|
getOrCreateHidden(productIdInput.form, `attributes[og__session]`, store.getState().sessionId);
|
|
383
|
+
|
|
384
|
+
const offerIdAttribute = getOfferIdAttribute(store);
|
|
385
|
+
if (offerIdAttribute) {
|
|
386
|
+
getOrCreateHidden(productIdInput.form, `attributes[${OFFER_ATTRIBUTE_NAME}]`, offerIdAttribute);
|
|
387
|
+
}
|
|
388
|
+
|
|
351
389
|
if (offerElement) {
|
|
352
390
|
// use this to update the product attributes in future
|
|
353
391
|
}
|
|
@@ -36,6 +36,7 @@ import type {
|
|
|
36
36
|
OfferElement,
|
|
37
37
|
OptedInState,
|
|
38
38
|
OptInItem,
|
|
39
|
+
PriceState,
|
|
39
40
|
ReceiveOfferPayload,
|
|
40
41
|
SetupProductPayload
|
|
41
42
|
} from '../core/types/reducer';
|
|
@@ -289,6 +290,25 @@ export const optedin = (state: OptedInState = [], action): OptedInState => {
|
|
|
289
290
|
return coreOptedin(state, action);
|
|
290
291
|
};
|
|
291
292
|
|
|
293
|
+
export const price = (state: PriceState = {}, action): PriceState => {
|
|
294
|
+
if (constants.SETUP_PRODUCT === action.type) {
|
|
295
|
+
const {
|
|
296
|
+
payload: { product }
|
|
297
|
+
} = action as { payload: SetupProductPayload };
|
|
298
|
+
return (
|
|
299
|
+
product.variants?.reduce(
|
|
300
|
+
(acc, cur) => ({
|
|
301
|
+
...acc,
|
|
302
|
+
[cur.id]: { value: cur.price }
|
|
303
|
+
}),
|
|
304
|
+
state
|
|
305
|
+
) || state
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return state;
|
|
310
|
+
};
|
|
311
|
+
|
|
292
312
|
export const productOffer = (state = {}, _action) => state;
|
|
293
313
|
|
|
294
314
|
export const productPlans = (state = {}, action) => {
|
|
@@ -352,6 +372,7 @@ const reducer = combineReducers({
|
|
|
352
372
|
optedout,
|
|
353
373
|
previewStandardOffer,
|
|
354
374
|
previewUpsellOffer,
|
|
375
|
+
price,
|
|
355
376
|
productOffer,
|
|
356
377
|
productPlans,
|
|
357
378
|
productToSubscribe,
|