@ordergroove/offers 2.34.8-alpha-PR-793-2.0 → 2.34.9
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 +19 -0
- package/dist/bundle-report.html +1 -1
- package/dist/offers.js +36 -36
- package/dist/offers.js.map +3 -3
- package/package.json +4 -3
- package/src/shopify/reducers/productPlans.ts +6 -5
- package/src/shopify/shopifyMiddleware.ts +27 -8
- package/src/shopify/types/shopify.ts +133 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ordergroove/offers",
|
|
3
|
-
"version": "2.34.
|
|
3
|
+
"version": "2.34.9",
|
|
4
4
|
"description": "offer state component",
|
|
5
5
|
"author": "Eugenio Lattanzio <eugenio63@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/ordergroove/plush-toys#readme",
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
"throttle-debounce": "^2.1.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@ordergroove/offers-templates": "^0.9.2"
|
|
48
|
+
"@ordergroove/offers-templates": "^0.9.2",
|
|
49
|
+
"@types/lodash.memoize": "^4.1.9"
|
|
49
50
|
},
|
|
50
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "a191165538ff5f2855d0a10a218eca99669602b5"
|
|
51
52
|
}
|
|
@@ -119,13 +119,14 @@ export const mapSellingPlanToDiscount = (
|
|
|
119
119
|
return productPlan;
|
|
120
120
|
};
|
|
121
121
|
|
|
122
|
-
export const sellingPlanAllocationsReducer = (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
]
|
|
122
|
+
export const sellingPlanAllocationsReducer = (
|
|
123
|
+
acc: ProductPlanEntity[],
|
|
124
|
+
cur: ShopifySellingPlanAllocationsEntity,
|
|
125
|
+
sellingPlans: ShopifySellingPlansEntity[] = []
|
|
126
|
+
) => [...acc, mapSellingPlanToDiscount(cur, sellingPlans)];
|
|
126
127
|
|
|
127
128
|
export const getSellingPlans = (product: ShopifyProductEntity) =>
|
|
128
|
-
product.selling_plan_groups.reduce(
|
|
129
|
+
product.selling_plan_groups.reduce<ShopifySellingPlansEntity[]>(
|
|
129
130
|
(allGroups, group) => [
|
|
130
131
|
...allGroups,
|
|
131
132
|
...group.selling_plans.map(selling_plan => ({ ...selling_plan, group_name: group.name }))
|
|
@@ -17,12 +17,21 @@ import {
|
|
|
17
17
|
import { makeSubscribedSelector } from '../core/selectors';
|
|
18
18
|
import { getOrCreateHidden, safeProductId } from '../core/utils';
|
|
19
19
|
import { getTrackingKey } from './shopifyTrackingMiddleware';
|
|
20
|
+
import { ShopifyCart, ShopifyProductEntity } from './types/shopify';
|
|
20
21
|
|
|
21
22
|
const SHOPIFY_ROOT = window.Shopify?.routes?.root || '/';
|
|
22
23
|
const CART_PAGE_URL = '/cart';
|
|
23
24
|
const CART_JS_URL = `${SHOPIFY_ROOT}cart.js`;
|
|
25
|
+
const CART_CHANGE_URL = `${SHOPIFY_ROOT}cart/change.js`;
|
|
24
26
|
const PRODUCTS_URL = `${SHOPIFY_ROOT}products/`;
|
|
25
27
|
|
|
28
|
+
type SetupProductPayload = {
|
|
29
|
+
product: ShopifyProductEntity;
|
|
30
|
+
offer: any;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type SetupCartPayload = ShopifyCart;
|
|
34
|
+
|
|
26
35
|
/**
|
|
27
36
|
* List of section DOM elements to update via section-rendering api https://shopify.dev/api/section-rendering
|
|
28
37
|
*/
|
|
@@ -43,7 +52,8 @@ async function setupPdp(store, offer) {
|
|
|
43
52
|
if (handle) {
|
|
44
53
|
try {
|
|
45
54
|
const product = await getProduct(handle);
|
|
46
|
-
|
|
55
|
+
const payload: SetupProductPayload = { product, offer };
|
|
56
|
+
store.dispatch({ type: SETUP_PRODUCT, payload });
|
|
47
57
|
} catch (err) {
|
|
48
58
|
console.warn('OG: Unable to fetch product details for PDP', err);
|
|
49
59
|
}
|
|
@@ -79,7 +89,9 @@ async function setupPdp(store, offer) {
|
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
|
|
82
|
-
|
|
92
|
+
async function getCart(): Promise<ShopifyCart> {
|
|
93
|
+
return (await fetch(CART_JS_URL)).json();
|
|
94
|
+
}
|
|
83
95
|
|
|
84
96
|
/**
|
|
85
97
|
* Attemps to guess the product handle o
|
|
@@ -120,12 +132,15 @@ export function guessProductHandle(offer): string {
|
|
|
120
132
|
);
|
|
121
133
|
}
|
|
122
134
|
|
|
123
|
-
const getProduct = memoize(async handle
|
|
135
|
+
const getProduct = memoize(async function(handle: string): Promise<ShopifyProductEntity> {
|
|
136
|
+
return (await fetch(`${PRODUCTS_URL}${handle}.js`)).json();
|
|
137
|
+
});
|
|
124
138
|
|
|
125
139
|
async function setupCart(store, offer) {
|
|
126
140
|
const cart = await getCart();
|
|
127
141
|
const { items } = cart;
|
|
128
|
-
|
|
142
|
+
const cartPayload: SetupCartPayload = cart;
|
|
143
|
+
store.dispatch({ type: SETUP_CART, payload: cartPayload });
|
|
129
144
|
|
|
130
145
|
// some minicart templates does not contains line.key but contains line which corresponds to
|
|
131
146
|
// the index on the cart items (Vedge)
|
|
@@ -136,7 +151,10 @@ async function setupCart(store, offer) {
|
|
|
136
151
|
}
|
|
137
152
|
|
|
138
153
|
const products = await Promise.all(Array.from(new Set(items.map(({ handle }) => handle))).map(getProduct));
|
|
139
|
-
products.forEach(product =>
|
|
154
|
+
products.forEach(product => {
|
|
155
|
+
const payload: SetupProductPayload = { product, offer };
|
|
156
|
+
store.dispatch({ type: SETUP_PRODUCT, payload });
|
|
157
|
+
});
|
|
140
158
|
}
|
|
141
159
|
|
|
142
160
|
/**
|
|
@@ -168,7 +186,7 @@ export async function synchronizeCartOptin(action: any, store: any) {
|
|
|
168
186
|
const qty = item.quantity;
|
|
169
187
|
const productId = safeProductId(key);
|
|
170
188
|
|
|
171
|
-
const res = await fetch(
|
|
189
|
+
const res = await fetch(CART_CHANGE_URL, {
|
|
172
190
|
method: 'POST',
|
|
173
191
|
credentials: 'same-origin',
|
|
174
192
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -184,7 +202,7 @@ export async function synchronizeCartOptin(action: any, store: any) {
|
|
|
184
202
|
|
|
185
203
|
if (res.status !== 200) throw new Error('Cart not updated');
|
|
186
204
|
|
|
187
|
-
const newCart = await res.json();
|
|
205
|
+
const newCart: ShopifyCart = await res.json();
|
|
188
206
|
|
|
189
207
|
// If both carts have same length we can update the item.key
|
|
190
208
|
// to the original offer element, at least provide
|
|
@@ -213,7 +231,8 @@ export async function synchronizeCartOptin(action: any, store: any) {
|
|
|
213
231
|
}
|
|
214
232
|
|
|
215
233
|
// dispatch SETUP_CART so offer does not flip the state
|
|
216
|
-
|
|
234
|
+
const newCartPayload: SetupCartPayload = newCart;
|
|
235
|
+
store.dispatch({ type: SETUP_CART, payload: newCartPayload });
|
|
217
236
|
|
|
218
237
|
// Use a custom event to hook custom cart updates.
|
|
219
238
|
const cartUpdateEvent = new CustomEvent(CART_UPDATED_EVENT, { bubbles: true, cancelable: true });
|
|
@@ -96,3 +96,136 @@ export interface ShopifyProductEntity {
|
|
|
96
96
|
requires_selling_plan: boolean;
|
|
97
97
|
selling_plan_groups?: ShopifySellingPlanGroupsEntity[] | null;
|
|
98
98
|
}
|
|
99
|
+
|
|
100
|
+
export interface ShopifyCart {
|
|
101
|
+
token: string;
|
|
102
|
+
note: string;
|
|
103
|
+
attributes: Record<string, string>;
|
|
104
|
+
original_total_price: number;
|
|
105
|
+
total_price: number;
|
|
106
|
+
total_discount: number;
|
|
107
|
+
total_weight: number;
|
|
108
|
+
item_count: number;
|
|
109
|
+
items: CartItem[];
|
|
110
|
+
requires_shipping: boolean;
|
|
111
|
+
currency: string;
|
|
112
|
+
items_subtotal_price: number;
|
|
113
|
+
cart_level_discount_applications: CartLevelDiscountApplication[];
|
|
114
|
+
sections?: Record<string, string>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
interface CartItem {
|
|
118
|
+
id: number;
|
|
119
|
+
properties: Record<string, string>;
|
|
120
|
+
quantity: number;
|
|
121
|
+
variant_id: number;
|
|
122
|
+
key: string;
|
|
123
|
+
title: string;
|
|
124
|
+
price: number;
|
|
125
|
+
original_price: number;
|
|
126
|
+
discounted_price: number;
|
|
127
|
+
line_price: number;
|
|
128
|
+
original_line_price: number;
|
|
129
|
+
total_discount: number;
|
|
130
|
+
discounts: Discount[];
|
|
131
|
+
sku: string;
|
|
132
|
+
grams: number;
|
|
133
|
+
vendor: string;
|
|
134
|
+
taxable: boolean;
|
|
135
|
+
product_id: number;
|
|
136
|
+
product_has_only_default_variant: boolean;
|
|
137
|
+
gift_card: boolean;
|
|
138
|
+
final_price: number;
|
|
139
|
+
final_line_price: number;
|
|
140
|
+
url: string;
|
|
141
|
+
featured_image: FeaturedImage;
|
|
142
|
+
image: string;
|
|
143
|
+
handle: string;
|
|
144
|
+
requires_shipping: boolean;
|
|
145
|
+
product_type: string;
|
|
146
|
+
product_title: string;
|
|
147
|
+
product_description: string;
|
|
148
|
+
variant_title?: string;
|
|
149
|
+
variant_options: string[];
|
|
150
|
+
options_with_values: OptionsWithValue[];
|
|
151
|
+
line_level_discount_allocations: LineLevelDiscountAllocation[];
|
|
152
|
+
line_level_total_discount: number;
|
|
153
|
+
quantity_rule: QuantityRule;
|
|
154
|
+
has_components: boolean;
|
|
155
|
+
selling_plan_allocation?: SellingPlanAllocation;
|
|
156
|
+
unit_price?: number;
|
|
157
|
+
unit_price_measurement?: UnitPriceMeasurement;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface Discount {
|
|
161
|
+
amount: number;
|
|
162
|
+
title: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
interface FeaturedImage {
|
|
166
|
+
aspect_ratio: number;
|
|
167
|
+
alt: string;
|
|
168
|
+
height: number;
|
|
169
|
+
url: string;
|
|
170
|
+
width: number;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
interface OptionsWithValue {
|
|
174
|
+
name: string;
|
|
175
|
+
value: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
interface LineLevelDiscountAllocation {
|
|
179
|
+
amount: number;
|
|
180
|
+
discount_application: DiscountApplication;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
interface DiscountApplication {
|
|
184
|
+
type: string;
|
|
185
|
+
key: string;
|
|
186
|
+
title: string;
|
|
187
|
+
description: string;
|
|
188
|
+
value: string;
|
|
189
|
+
created_at: string;
|
|
190
|
+
value_type: string;
|
|
191
|
+
allocation_method: string;
|
|
192
|
+
target_selection: string;
|
|
193
|
+
target_type: string;
|
|
194
|
+
total_allocated_amount: number;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface QuantityRule {
|
|
198
|
+
min: number;
|
|
199
|
+
max?: number;
|
|
200
|
+
increment: number;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
interface SellingPlanAllocation {
|
|
204
|
+
price_adjustments: ShopifyPriceAdjustmentsEntity[];
|
|
205
|
+
price: number;
|
|
206
|
+
compare_at_price: number;
|
|
207
|
+
per_delivery_price: number;
|
|
208
|
+
selling_plan: ShopifySellingPlansEntity;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface UnitPriceMeasurement {
|
|
212
|
+
measured_type: string;
|
|
213
|
+
quantity_value: string;
|
|
214
|
+
quantity_unit: string;
|
|
215
|
+
reference_value: number;
|
|
216
|
+
reference_unit: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
interface CartLevelDiscountApplication {
|
|
220
|
+
type: string;
|
|
221
|
+
key: string;
|
|
222
|
+
title: string;
|
|
223
|
+
description: string;
|
|
224
|
+
value: string;
|
|
225
|
+
created_at: string;
|
|
226
|
+
value_type: string;
|
|
227
|
+
allocation_method: string;
|
|
228
|
+
target_selection: string;
|
|
229
|
+
target_type: string;
|
|
230
|
+
total_allocated_amount: number;
|
|
231
|
+
}
|