@anker-in/shopify-react 0.1.1-beta.0
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/adapters/index.d.mts +16 -0
- package/dist/adapters/index.d.ts +16 -0
- package/dist/adapters/index.js +49 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/index.mjs +42 -0
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/hooks/index.d.mts +9 -0
- package/dist/hooks/index.d.ts +9 -0
- package/dist/hooks/index.js +2890 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/index.mjs +2801 -0
- package/dist/hooks/index.mjs.map +1 -0
- package/dist/index-BUWkkUdh.d.ts +1936 -0
- package/dist/index-DenyuVGJ.d.mts +1936 -0
- package/dist/index.d.mts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +3220 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3095 -0
- package/dist/index.mjs.map +1 -0
- package/dist/provider/index.d.mts +161 -0
- package/dist/provider/index.d.ts +161 -0
- package/dist/provider/index.js +1130 -0
- package/dist/provider/index.js.map +1 -0
- package/dist/provider/index.mjs +1117 -0
- package/dist/provider/index.mjs.map +1 -0
- package/dist/types-BLMoxbOk.d.mts +54 -0
- package/dist/types-BLMoxbOk.d.ts +54 -0
- package/dist/types-CMA6_FML.d.mts +550 -0
- package/dist/types-CMA6_FML.d.ts +550 -0
- package/package.json +71 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3220 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var shopifySdk = require('@anker-in/shopify-sdk');
|
|
5
|
+
var Cookies5 = require('js-cookie');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var Decimal2 = require('decimal.js');
|
|
8
|
+
var useSWR = require('swr');
|
|
9
|
+
var useSWRMutation = require('swr/mutation');
|
|
10
|
+
var ahooks = require('ahooks');
|
|
11
|
+
|
|
12
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
|
|
14
|
+
var Cookies5__default = /*#__PURE__*/_interopDefault(Cookies5);
|
|
15
|
+
var Decimal2__default = /*#__PURE__*/_interopDefault(Decimal2);
|
|
16
|
+
var useSWR__default = /*#__PURE__*/_interopDefault(useSWR);
|
|
17
|
+
var useSWRMutation__default = /*#__PURE__*/_interopDefault(useSWRMutation);
|
|
18
|
+
|
|
19
|
+
// src/provider/context.ts
|
|
20
|
+
var ShopifyContext = react.createContext(null);
|
|
21
|
+
var browserCookieAdapter = {
|
|
22
|
+
get(key) {
|
|
23
|
+
return Cookies5__default.default.get(key);
|
|
24
|
+
},
|
|
25
|
+
set(key, value, options) {
|
|
26
|
+
Cookies5__default.default.set(key, value, {
|
|
27
|
+
domain: options?.domain,
|
|
28
|
+
path: options?.path || "/",
|
|
29
|
+
expires: options?.expires,
|
|
30
|
+
secure: options?.secure,
|
|
31
|
+
sameSite: options?.sameSite
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
remove(key) {
|
|
35
|
+
Cookies5__default.default.remove(key);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function getCartCookieName(locale) {
|
|
39
|
+
return `${locale}-shopify-cart-id`;
|
|
40
|
+
}
|
|
41
|
+
var browserCartCookieAdapter = {
|
|
42
|
+
getCartId(locale) {
|
|
43
|
+
return Cookies5__default.default.get(getCartCookieName(locale));
|
|
44
|
+
},
|
|
45
|
+
setCartId(locale, cartId) {
|
|
46
|
+
Cookies5__default.default.set(getCartCookieName(locale), cartId, {
|
|
47
|
+
path: "/",
|
|
48
|
+
expires: 30
|
|
49
|
+
// 30 days
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
removeCartId(locale) {
|
|
53
|
+
Cookies5__default.default.remove(getCartCookieName(locale));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
function ShopifyProvider({
|
|
57
|
+
config,
|
|
58
|
+
locale,
|
|
59
|
+
locales,
|
|
60
|
+
cookieAdapter = browserCookieAdapter,
|
|
61
|
+
cartCookieAdapter = browserCartCookieAdapter,
|
|
62
|
+
routerAdapter,
|
|
63
|
+
userAdapter,
|
|
64
|
+
children
|
|
65
|
+
}) {
|
|
66
|
+
const client = react.useMemo(() => {
|
|
67
|
+
return shopifySdk.createShopifyClient(config, locale);
|
|
68
|
+
}, [config, locale]);
|
|
69
|
+
const value = react.useMemo(() => {
|
|
70
|
+
return {
|
|
71
|
+
client,
|
|
72
|
+
config,
|
|
73
|
+
locale,
|
|
74
|
+
locales: locales || config.getLocales(),
|
|
75
|
+
cookieAdapter,
|
|
76
|
+
cartCookieAdapter,
|
|
77
|
+
routerAdapter,
|
|
78
|
+
userAdapter
|
|
79
|
+
};
|
|
80
|
+
}, [
|
|
81
|
+
client,
|
|
82
|
+
config,
|
|
83
|
+
locale,
|
|
84
|
+
locales,
|
|
85
|
+
cookieAdapter,
|
|
86
|
+
cartCookieAdapter,
|
|
87
|
+
routerAdapter,
|
|
88
|
+
userAdapter
|
|
89
|
+
]);
|
|
90
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ShopifyContext.Provider, { value, children });
|
|
91
|
+
}
|
|
92
|
+
function useShopify() {
|
|
93
|
+
const context = react.useContext(ShopifyContext);
|
|
94
|
+
if (!context) {
|
|
95
|
+
throw new Error("useShopify must be used within a ShopifyProvider");
|
|
96
|
+
}
|
|
97
|
+
return context;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/hooks/cart/types/auto-free-gift.ts
|
|
101
|
+
var RuleType = /* @__PURE__ */ ((RuleType2) => {
|
|
102
|
+
RuleType2[RuleType2["AUTO_FREE_GIFT"] = 1] = "AUTO_FREE_GIFT";
|
|
103
|
+
RuleType2[RuleType2["BUNDLE"] = 2] = "BUNDLE";
|
|
104
|
+
RuleType2[RuleType2["VOLUME_DISCOUNT"] = 3] = "VOLUME_DISCOUNT";
|
|
105
|
+
RuleType2[RuleType2["ORDER_DISCOUNT"] = 4] = "ORDER_DISCOUNT";
|
|
106
|
+
RuleType2[RuleType2["PRICE_DISCOUNT"] = 5] = "PRICE_DISCOUNT";
|
|
107
|
+
return RuleType2;
|
|
108
|
+
})(RuleType || {});
|
|
109
|
+
var BuyRuleType = /* @__PURE__ */ ((BuyRuleType2) => {
|
|
110
|
+
BuyRuleType2[BuyRuleType2["BUY_GET_GIFT"] = 1] = "BUY_GET_GIFT";
|
|
111
|
+
BuyRuleType2[BuyRuleType2["SPEND_GET_GIFT"] = 2] = "SPEND_GET_GIFT";
|
|
112
|
+
return BuyRuleType2;
|
|
113
|
+
})(BuyRuleType || {});
|
|
114
|
+
var SpendMoneyType = /* @__PURE__ */ ((SpendMoneyType2) => {
|
|
115
|
+
SpendMoneyType2[SpendMoneyType2["ORIGIN_PRICE"] = 1] = "ORIGIN_PRICE";
|
|
116
|
+
SpendMoneyType2[SpendMoneyType2["DISCOUNT_PRICE"] = 2] = "DISCOUNT_PRICE";
|
|
117
|
+
return SpendMoneyType2;
|
|
118
|
+
})(SpendMoneyType || {});
|
|
119
|
+
|
|
120
|
+
// src/hooks/cart/const.ts
|
|
121
|
+
var currencyCodeMapping = {
|
|
122
|
+
us: "USD",
|
|
123
|
+
ca: "CAD",
|
|
124
|
+
gb: "GBP",
|
|
125
|
+
eu: "EUR",
|
|
126
|
+
au: "AUD",
|
|
127
|
+
nz: "NZD",
|
|
128
|
+
de: "EUR",
|
|
129
|
+
fr: "EUR",
|
|
130
|
+
es: "EUR",
|
|
131
|
+
it: "EUR",
|
|
132
|
+
nl: "EUR",
|
|
133
|
+
pl: "EUR",
|
|
134
|
+
ro: "EUR"
|
|
135
|
+
};
|
|
136
|
+
var defaultSWRMutationConfiguration = {
|
|
137
|
+
throwOnError: false
|
|
138
|
+
};
|
|
139
|
+
var CUSTOMER_ATTRIBUTE_KEY = "_discounts_function_env";
|
|
140
|
+
var CUSTOMER_SCRIPT_GIFT_KEY = "_giveaway_gradient_gifts";
|
|
141
|
+
var CODE_AMOUNT_KEY = "_sku_code_money";
|
|
142
|
+
var SCRIPT_CODE_AMOUNT_KEY = "_code_money";
|
|
143
|
+
var MAIN_PRODUCT_CODE = ["WS24", "WSTD", "WS7D", "WSCP", "WSPE", "WSPD"];
|
|
144
|
+
|
|
145
|
+
// src/hooks/cart/utils/index.ts
|
|
146
|
+
var getQuery = () => {
|
|
147
|
+
const url = typeof window !== "undefined" ? window.location.search : "";
|
|
148
|
+
const theRequest = {};
|
|
149
|
+
if (url.indexOf("?") != -1) {
|
|
150
|
+
const str = url.substr(1), strs = str.split("&");
|
|
151
|
+
for (let i = 0; i < strs.length; i++) {
|
|
152
|
+
const parts = strs[i]?.split("=");
|
|
153
|
+
const key = parts?.[0];
|
|
154
|
+
const value = parts?.[1];
|
|
155
|
+
if (key && value) {
|
|
156
|
+
theRequest[key] = decodeURIComponent(value);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return theRequest;
|
|
161
|
+
};
|
|
162
|
+
function atobID(id) {
|
|
163
|
+
if (id && typeof id === "string" && id.includes("/")) {
|
|
164
|
+
return id.split("/").pop()?.split("?")?.shift();
|
|
165
|
+
} else {
|
|
166
|
+
return id;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function btoaID(id, type = "ProductVariant") {
|
|
170
|
+
return `gid://shopify/${type}/${id}`;
|
|
171
|
+
}
|
|
172
|
+
var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
|
|
173
|
+
const isAllStoreVariant = main_product?.all_store_variant ?? false;
|
|
174
|
+
const matchedList = cartData?.lineItems?.filter((line) => {
|
|
175
|
+
const { is_gift } = getDiscountEnvAttributeValue(line.customAttributes);
|
|
176
|
+
return isAllStoreVariant ? !is_gift : variant_list?.find((item) => {
|
|
177
|
+
return !is_gift && atobID(line.variantId) === item;
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
return matchedList?.reduce((acc, line) => {
|
|
181
|
+
return acc + (main_product?.spend_money_type === 1 /* ORIGIN_PRICE */ ? Number(line.subtotalAmount) || 0 : Number(line.totalAmount) || 0);
|
|
182
|
+
}, 0) || 0;
|
|
183
|
+
};
|
|
184
|
+
var getDiscountEnvAttributeValue = (attributes = []) => {
|
|
185
|
+
const attr = attributes.find((attr2) => attr2.key === CUSTOMER_ATTRIBUTE_KEY);
|
|
186
|
+
return safeParseJson(attr?.value ?? "") ?? {};
|
|
187
|
+
};
|
|
188
|
+
var isAttributesEqual = (attrs1 = [], attrs2 = []) => {
|
|
189
|
+
if (attrs1.length !== attrs2.length) return false;
|
|
190
|
+
const sorted1 = [...attrs1].sort((a, b) => a.key.localeCompare(b.key));
|
|
191
|
+
const sorted2 = [...attrs2].sort((a, b) => a.key.localeCompare(b.key));
|
|
192
|
+
return sorted1.every(
|
|
193
|
+
(attr, i) => attr.key === sorted2[i]?.key && attr.value === sorted2[i]?.value
|
|
194
|
+
);
|
|
195
|
+
};
|
|
196
|
+
var safeParseJson = (str) => {
|
|
197
|
+
try {
|
|
198
|
+
return JSON.parse(str);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
return {};
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
var containsAll = (source, requiredItems = []) => {
|
|
204
|
+
if (!requiredItems?.length) return true;
|
|
205
|
+
const sourceSet = new Set(source);
|
|
206
|
+
return requiredItems.every((item) => sourceSet.has(item));
|
|
207
|
+
};
|
|
208
|
+
var containsNone = (source, forbiddenItems = []) => {
|
|
209
|
+
if (!forbiddenItems?.length) return true;
|
|
210
|
+
const sourceSet = new Set(source);
|
|
211
|
+
return !forbiddenItems.some((item) => sourceSet.has(item));
|
|
212
|
+
};
|
|
213
|
+
function preCheck(rule_conditions, userTags, currentDealsTypes) {
|
|
214
|
+
if (!Array.isArray(rule_conditions)) return false;
|
|
215
|
+
if (rule_conditions.length === 0) return true;
|
|
216
|
+
return rule_conditions.some((rule) => {
|
|
217
|
+
const tagsAreValid = containsAll(userTags, rule.with_user_tags) && containsNone(userTags, rule.without_user_tags);
|
|
218
|
+
const paramsAreValid = containsAll(currentDealsTypes, rule.with_special_url_params) && containsNone(currentDealsTypes, rule.without_special_url_params);
|
|
219
|
+
return tagsAreValid && paramsAreValid;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
var formatScriptAutoFreeGiftCache = null;
|
|
223
|
+
var formatScriptAutoFreeGift = ({
|
|
224
|
+
scriptAutoFreeGiftResult,
|
|
225
|
+
gradient_gifts,
|
|
226
|
+
locale
|
|
227
|
+
}) => {
|
|
228
|
+
const cacheKey = JSON.stringify({
|
|
229
|
+
freeGiftLevel: scriptAutoFreeGiftResult?.freeGiftLevel ? {
|
|
230
|
+
items: scriptAutoFreeGiftResult.freeGiftLevel.giveawayProducts?.map((item) => ({
|
|
231
|
+
handle: item.handle,
|
|
232
|
+
sku: item.sku,
|
|
233
|
+
quantity: 1
|
|
234
|
+
})) || []
|
|
235
|
+
} : null,
|
|
236
|
+
giftProductsLength: scriptAutoFreeGiftResult?.giftProductsResult?.length || 0,
|
|
237
|
+
giftProductsIds: scriptAutoFreeGiftResult?.giftProductsResult?.map((p) => p.id).sort() || [],
|
|
238
|
+
gradientGiftsId: gradient_gifts?.id || gradient_gifts?.name || "",
|
|
239
|
+
locale
|
|
240
|
+
});
|
|
241
|
+
if (formatScriptAutoFreeGiftCache && formatScriptAutoFreeGiftCache.key === cacheKey) {
|
|
242
|
+
return formatScriptAutoFreeGiftCache.result;
|
|
243
|
+
}
|
|
244
|
+
const result = scriptAutoFreeGiftResult?.freeGiftLevel?.giveawayProducts?.filter(
|
|
245
|
+
(item) => scriptAutoFreeGiftResult?.giftProductsResult?.some(
|
|
246
|
+
(product) => product.handle === item.handle
|
|
247
|
+
)
|
|
248
|
+
).map((item, index) => {
|
|
249
|
+
const product = scriptAutoFreeGiftResult?.giftProductsResult?.find(
|
|
250
|
+
(product2) => product2.handle === item.handle
|
|
251
|
+
);
|
|
252
|
+
const variants = product?.variants;
|
|
253
|
+
const variant = Array.isArray(variants) ? variants.find((v) => v.sku === item.sku) : void 0;
|
|
254
|
+
const query = getQuery();
|
|
255
|
+
const utmCampaign = Cookies5__default.default.get("utm_campaign") || query?.utm_campaign;
|
|
256
|
+
const addUTMFreeItem = gradient_gifts.activityAvailableQuery && utmCampaign?.includes(gradient_gifts.activityAvailableQuery);
|
|
257
|
+
let points_subscribe = false;
|
|
258
|
+
if (locale === "au") {
|
|
259
|
+
const isPointsSubscribe = Cookies5__default.default.get("points_subscribe");
|
|
260
|
+
points_subscribe = !!isPointsSubscribe;
|
|
261
|
+
}
|
|
262
|
+
const customAttributes = [
|
|
263
|
+
{
|
|
264
|
+
key: "_giveaway_gradient_gifts",
|
|
265
|
+
value: "_giveaway_gradient_gifts"
|
|
266
|
+
},
|
|
267
|
+
...points_subscribe ? [
|
|
268
|
+
{ key: "_amount_upgrade_multiple", value: "1.2" },
|
|
269
|
+
{ key: "_amount_upgrade_value", value: "40" }
|
|
270
|
+
] : [],
|
|
271
|
+
...addUTMFreeItem && gradient_gifts?.activityQroperty ? [
|
|
272
|
+
{
|
|
273
|
+
key: gradient_gifts.activityQroperty,
|
|
274
|
+
value: gradient_gifts.activityQroperty
|
|
275
|
+
}
|
|
276
|
+
] : []
|
|
277
|
+
];
|
|
278
|
+
const line = {
|
|
279
|
+
id: product?.id + "_" + index,
|
|
280
|
+
variantId: String(variant?.id),
|
|
281
|
+
productId: String(product?.id),
|
|
282
|
+
name: product?.name || product?.title || "",
|
|
283
|
+
quantity: 1,
|
|
284
|
+
discounts: [],
|
|
285
|
+
path: product?.handle || "",
|
|
286
|
+
variant,
|
|
287
|
+
totalAmount: 0,
|
|
288
|
+
subtotalAmount: new Decimal2__default.default(
|
|
289
|
+
typeof variant?.price === "object" ? variant?.price?.amount || 0 : variant?.price || 0
|
|
290
|
+
).toNumber(),
|
|
291
|
+
options: [],
|
|
292
|
+
discountAllocations: [],
|
|
293
|
+
product,
|
|
294
|
+
customAttributes,
|
|
295
|
+
freeGiftVariant: void 0,
|
|
296
|
+
relatedVariant: void 0
|
|
297
|
+
};
|
|
298
|
+
return {
|
|
299
|
+
line,
|
|
300
|
+
isSoldOut: !variant?.availableForSale
|
|
301
|
+
};
|
|
302
|
+
}) || [];
|
|
303
|
+
formatScriptAutoFreeGiftCache = {
|
|
304
|
+
key: cacheKey,
|
|
305
|
+
result
|
|
306
|
+
};
|
|
307
|
+
return result;
|
|
308
|
+
};
|
|
309
|
+
var formatFunctionAutoFreeGiftCache = null;
|
|
310
|
+
var formatFunctionAutoFreeGift = ({
|
|
311
|
+
qualifyingGift,
|
|
312
|
+
giftProductsResult,
|
|
313
|
+
locale
|
|
314
|
+
}) => {
|
|
315
|
+
const cacheKey = JSON.stringify({
|
|
316
|
+
qualifyingGift: qualifyingGift ? {
|
|
317
|
+
spend: qualifyingGift.tier?.spend_sum_money,
|
|
318
|
+
items: qualifyingGift.itemsToAdd?.map((item) => ({
|
|
319
|
+
variantId: item.variant.id,
|
|
320
|
+
handle: item.variant.handle,
|
|
321
|
+
sku: item.variant.sku,
|
|
322
|
+
quantity: item.quantity ?? 1,
|
|
323
|
+
attributes: item.attributes
|
|
324
|
+
})) || []
|
|
325
|
+
} : null,
|
|
326
|
+
giftProductsLength: giftProductsResult?.length || 0,
|
|
327
|
+
giftProductsIds: giftProductsResult?.map((p) => p.id).sort() || [],
|
|
328
|
+
locale
|
|
329
|
+
});
|
|
330
|
+
if (formatFunctionAutoFreeGiftCache && formatFunctionAutoFreeGiftCache.key === cacheKey) {
|
|
331
|
+
return formatFunctionAutoFreeGiftCache.result;
|
|
332
|
+
}
|
|
333
|
+
const result = qualifyingGift?.itemsToAdd?.map((item, index) => {
|
|
334
|
+
const product = giftProductsResult?.find((product2) => product2.handle === item.variant.handle);
|
|
335
|
+
const variants = product?.variants;
|
|
336
|
+
const variant = Array.isArray(variants) ? variants.find((v) => v.sku === item.variant.sku) : void 0;
|
|
337
|
+
console.log("qualifyingGift variant", product, variant);
|
|
338
|
+
const line = {
|
|
339
|
+
id: product?.id + "_" + index,
|
|
340
|
+
variantId: String(variant?.id),
|
|
341
|
+
productId: String(product?.id),
|
|
342
|
+
name: product?.name || product?.title || "",
|
|
343
|
+
quantity: 1,
|
|
344
|
+
discounts: [],
|
|
345
|
+
path: product?.handle || "",
|
|
346
|
+
variant,
|
|
347
|
+
totalAmount: 0,
|
|
348
|
+
subtotalAmount: new Decimal2__default.default(
|
|
349
|
+
typeof variant?.price === "object" ? variant?.price?.amount || 0 : variant?.price || 0
|
|
350
|
+
).toNumber(),
|
|
351
|
+
options: [],
|
|
352
|
+
discountAllocations: [],
|
|
353
|
+
product,
|
|
354
|
+
customAttributes: item.attributes,
|
|
355
|
+
freeGiftVariant: void 0,
|
|
356
|
+
relatedVariant: void 0
|
|
357
|
+
};
|
|
358
|
+
return {
|
|
359
|
+
line,
|
|
360
|
+
isSoldOut: !variant?.availableForSale
|
|
361
|
+
};
|
|
362
|
+
}) || [];
|
|
363
|
+
formatFunctionAutoFreeGiftCache = {
|
|
364
|
+
key: cacheKey,
|
|
365
|
+
result
|
|
366
|
+
};
|
|
367
|
+
return result;
|
|
368
|
+
};
|
|
369
|
+
var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
|
|
370
|
+
const tags = react.useMemo(() => customer?.tags || [], [customer?.tags]);
|
|
371
|
+
const isCustomerLoading = react.useMemo(() => !customer ? true : false, [customer]);
|
|
372
|
+
const dealsType = "";
|
|
373
|
+
const { client, locale } = useShopify();
|
|
374
|
+
const giftProductsCache = react.useRef(null);
|
|
375
|
+
const { activeCampaign, subtotal } = react.useMemo(() => {
|
|
376
|
+
for (const campaign of autoFreeGiftConfig) {
|
|
377
|
+
const { rule_conditions = [], rule_result } = campaign;
|
|
378
|
+
const { spend_get_reward } = rule_result || {};
|
|
379
|
+
const isPreCheckPassed = preCheck(rule_conditions, tags, []);
|
|
380
|
+
if (isPreCheckPassed && spend_get_reward) {
|
|
381
|
+
const matchedSubtotal = getMatchedMainProductSubTotal(
|
|
382
|
+
cart,
|
|
383
|
+
spend_get_reward.main_product?.variant_list?.map((v) => v.variant_id) || [],
|
|
384
|
+
{
|
|
385
|
+
spend_money_type: spend_get_reward.main_product?.spend_money_type || 1,
|
|
386
|
+
variant_id_list: spend_get_reward.main_product?.variant_list?.map((v) => v.variant_id) || [],
|
|
387
|
+
all_store_variant: spend_get_reward.main_product?.all_store_variant || false
|
|
388
|
+
}
|
|
389
|
+
);
|
|
390
|
+
if (matchedSubtotal > 0) {
|
|
391
|
+
return { activeCampaign: campaign, subtotal: matchedSubtotal };
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return { activeCampaign: null, subtotal: 0 };
|
|
396
|
+
}, [autoFreeGiftConfig, cart, tags, dealsType]);
|
|
397
|
+
const { qualifyingGift, nextTierGoal } = react.useMemo(() => {
|
|
398
|
+
if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
|
|
399
|
+
return { qualifyingGift: null, nextTierGoal: null };
|
|
400
|
+
}
|
|
401
|
+
const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
|
|
402
|
+
const qualifyingTier = [...giftTiers].reverse().find((tier) => subtotal >= Number(tier.spend_sum_money));
|
|
403
|
+
const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
|
|
404
|
+
if (!qualifyingTier) {
|
|
405
|
+
return { qualifyingGift: null, nextTierGoal: nextGoal || null };
|
|
406
|
+
}
|
|
407
|
+
const formattedGift = {
|
|
408
|
+
tier: qualifyingTier,
|
|
409
|
+
itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
|
|
410
|
+
const giftProduct = reward?.variant_list?.[0];
|
|
411
|
+
if (!giftProduct) return null;
|
|
412
|
+
return {
|
|
413
|
+
variant: {
|
|
414
|
+
id: btoaID(giftProduct.variant_id),
|
|
415
|
+
handle: giftProduct.handle,
|
|
416
|
+
sku: giftProduct.sku
|
|
417
|
+
},
|
|
418
|
+
quantity: reward?.get_unit || 1,
|
|
419
|
+
attributes: [
|
|
420
|
+
{
|
|
421
|
+
key: CUSTOMER_ATTRIBUTE_KEY,
|
|
422
|
+
value: JSON.stringify({
|
|
423
|
+
is_gift: true,
|
|
424
|
+
rule_id: activeCampaign.rule_id,
|
|
425
|
+
spend_sum_money: qualifyingTier.spend_sum_money
|
|
426
|
+
})
|
|
427
|
+
}
|
|
428
|
+
]
|
|
429
|
+
};
|
|
430
|
+
}).filter((item) => item !== null)
|
|
431
|
+
};
|
|
432
|
+
return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
|
|
433
|
+
}, [activeCampaign, subtotal]);
|
|
434
|
+
const giftHandles = react.useMemo(() => {
|
|
435
|
+
const giftVariant = autoFreeGiftConfig.map(
|
|
436
|
+
(item) => item.rule_result?.spend_get_reward?.gift_product?.map(
|
|
437
|
+
(v) => v.reward_list.map((reward) => reward.variant_list.map((variant) => variant.handle))
|
|
438
|
+
).flat()
|
|
439
|
+
).flat();
|
|
440
|
+
return giftVariant.flat(2).filter(Boolean);
|
|
441
|
+
}, [autoFreeGiftConfig]);
|
|
442
|
+
const shouldFetch = react.useMemo(() => {
|
|
443
|
+
if (!giftHandles.length) return false;
|
|
444
|
+
if (giftProductsCache.current && JSON.stringify(giftProductsCache.current.giftHandles) === JSON.stringify(giftHandles)) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
return true;
|
|
448
|
+
}, [giftHandles]);
|
|
449
|
+
const { data: giftProductsResult } = useSWR__default.default(shouldFetch ? giftHandles : null, async () => {
|
|
450
|
+
const res = await shopifySdk.getProductsByHandles(client, {
|
|
451
|
+
handles: giftHandles,
|
|
452
|
+
locale
|
|
453
|
+
});
|
|
454
|
+
const result = Array.isArray(res) ? res : [];
|
|
455
|
+
giftProductsCache.current = {
|
|
456
|
+
data: result,
|
|
457
|
+
giftHandles: [...giftHandles]
|
|
458
|
+
};
|
|
459
|
+
return result;
|
|
460
|
+
});
|
|
461
|
+
const finalGiftProductsResult = react.useMemo(() => {
|
|
462
|
+
if (giftProductsCache.current && !shouldFetch) {
|
|
463
|
+
return giftProductsCache.current.data || void 0;
|
|
464
|
+
}
|
|
465
|
+
return giftProductsResult;
|
|
466
|
+
}, [giftProductsResult, shouldFetch]);
|
|
467
|
+
return {
|
|
468
|
+
qualifyingGift,
|
|
469
|
+
nextTierGoal,
|
|
470
|
+
activeCampaign,
|
|
471
|
+
isLoading: isCustomerLoading,
|
|
472
|
+
giftProductsResult: finalGiftProductsResult
|
|
473
|
+
};
|
|
474
|
+
};
|
|
475
|
+
var useScriptAutoFreeGift = ({
|
|
476
|
+
campaign,
|
|
477
|
+
_giveaway,
|
|
478
|
+
cart,
|
|
479
|
+
locale: providedLocale
|
|
480
|
+
}) => {
|
|
481
|
+
const { client, locale: contextLocale } = useShopify();
|
|
482
|
+
const locale = providedLocale || contextLocale;
|
|
483
|
+
const [points_subscribe, set_points_subscribe] = react.useState(false);
|
|
484
|
+
const giftProductsCache = react.useRef(null);
|
|
485
|
+
react.useEffect(() => {
|
|
486
|
+
if (locale === "au") {
|
|
487
|
+
const isPointsSubscribe = Cookies5__default.default.get("points_subscribe");
|
|
488
|
+
set_points_subscribe(!!isPointsSubscribe);
|
|
489
|
+
}
|
|
490
|
+
}, [locale]);
|
|
491
|
+
const [upgrade_multiple, upgrade_value] = react.useMemo(() => {
|
|
492
|
+
let upgrade_multiple2 = 1;
|
|
493
|
+
let upgrade_value2 = 0;
|
|
494
|
+
if (points_subscribe) {
|
|
495
|
+
upgrade_multiple2 = 1.2;
|
|
496
|
+
upgrade_value2 = 40;
|
|
497
|
+
}
|
|
498
|
+
cart?.lineItems?.forEach(({ customAttributes }) => {
|
|
499
|
+
customAttributes?.forEach(({ key, value }) => {
|
|
500
|
+
if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
|
|
501
|
+
if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
return [upgrade_multiple2, upgrade_value2];
|
|
505
|
+
}, [cart?.lineItems, points_subscribe]);
|
|
506
|
+
const breakpoints = react.useMemo(() => {
|
|
507
|
+
if (!campaign) return [];
|
|
508
|
+
return (campaign.breakpoints || []).map((item) => ({
|
|
509
|
+
breakpoint: new Decimal2__default.default(item.breakpoint).minus(new Decimal2__default.default(upgrade_value)).dividedBy(new Decimal2__default.default(upgrade_multiple)).toFixed(2, Decimal2__default.default.ROUND_DOWN),
|
|
510
|
+
giveawayProducts: item.giveawayProducts || []
|
|
511
|
+
}));
|
|
512
|
+
}, [campaign, upgrade_multiple, upgrade_value]);
|
|
513
|
+
const giftHandles = react.useMemo(
|
|
514
|
+
() => (
|
|
515
|
+
// 使用 Set 去重,然后拼接字符串
|
|
516
|
+
[
|
|
517
|
+
...new Set(
|
|
518
|
+
breakpoints.flatMap((b) => b.giveawayProducts.map((p) => p.handle)).filter(Boolean)
|
|
519
|
+
)
|
|
520
|
+
]
|
|
521
|
+
),
|
|
522
|
+
[breakpoints]
|
|
523
|
+
);
|
|
524
|
+
const shouldFetch = react.useMemo(() => {
|
|
525
|
+
if (!giftHandles.length) return false;
|
|
526
|
+
if (giftProductsCache.current && JSON.stringify(giftProductsCache.current.giftHandles) === JSON.stringify(giftHandles)) {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
return true;
|
|
530
|
+
}, [giftHandles]);
|
|
531
|
+
const involvedLines = react.useMemo(() => {
|
|
532
|
+
if (!campaign) return [];
|
|
533
|
+
return (cart?.lineItems || []).filter((line) => {
|
|
534
|
+
const isNotGift = line?.totalAmount && Number(line.totalAmount) > 0 && line.customAttributes?.every(
|
|
535
|
+
(item) => item.key !== _giveaway
|
|
536
|
+
);
|
|
537
|
+
const hasCampaignTag = line.product?.tags?.some(
|
|
538
|
+
(tag) => campaign.includeTags?.includes(tag.trim()) && line.variant?.availableForSale
|
|
539
|
+
);
|
|
540
|
+
return isNotGift && hasCampaignTag;
|
|
541
|
+
});
|
|
542
|
+
}, [cart?.lineItems, campaign, _giveaway]);
|
|
543
|
+
const involvedSubTotal = react.useMemo(() => {
|
|
544
|
+
if (!campaign) return new Decimal2__default.default(0);
|
|
545
|
+
return involvedLines.reduce((prev, item) => {
|
|
546
|
+
const amount = campaign.useTotalAmount ? item.totalAmount : item.subtotalAmount;
|
|
547
|
+
return new Decimal2__default.default(prev).plus(new Decimal2__default.default(amount || 0));
|
|
548
|
+
}, new Decimal2__default.default(0));
|
|
549
|
+
}, [involvedLines, campaign]);
|
|
550
|
+
const [freeGiftLevel, nextFreeGiftLevel] = react.useMemo(() => {
|
|
551
|
+
const sortedLevels = [...breakpoints].sort(
|
|
552
|
+
(a, b) => Number(b.breakpoint) - Number(a.breakpoint)
|
|
553
|
+
);
|
|
554
|
+
const levelIndex = sortedLevels.findIndex(
|
|
555
|
+
(level) => involvedSubTotal.gte(new Decimal2__default.default(level.breakpoint)) && involvedLines.length > 0
|
|
556
|
+
);
|
|
557
|
+
if (levelIndex === -1) {
|
|
558
|
+
return [
|
|
559
|
+
null,
|
|
560
|
+
sortedLevels.length > 0 ? sortedLevels[sortedLevels.length - 1] ?? null : null
|
|
561
|
+
];
|
|
562
|
+
}
|
|
563
|
+
const currentLevel = sortedLevels[levelIndex] ?? null;
|
|
564
|
+
const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
|
|
565
|
+
return [currentLevel, nextLevel];
|
|
566
|
+
}, [breakpoints, involvedSubTotal, involvedLines.length]);
|
|
567
|
+
const { data: giftProductsResult } = useSWR__default.default(shouldFetch ? giftHandles : null, async () => {
|
|
568
|
+
const res = await shopifySdk.getProductsByHandles(client, {
|
|
569
|
+
handles: giftHandles,
|
|
570
|
+
locale
|
|
571
|
+
});
|
|
572
|
+
const result = Array.isArray(res) ? res : [];
|
|
573
|
+
giftProductsCache.current = {
|
|
574
|
+
data: result,
|
|
575
|
+
giftHandles: [...giftHandles]
|
|
576
|
+
};
|
|
577
|
+
return result;
|
|
578
|
+
});
|
|
579
|
+
const finalGiftProductsResult = react.useMemo(() => {
|
|
580
|
+
if (giftProductsCache.current && !shouldFetch) {
|
|
581
|
+
return giftProductsCache.current.data || void 0;
|
|
582
|
+
}
|
|
583
|
+
return giftProductsResult;
|
|
584
|
+
}, [giftProductsResult, shouldFetch]);
|
|
585
|
+
const reorder = react.useCallback(
|
|
586
|
+
(a, b) => {
|
|
587
|
+
const getPriority = (item) => {
|
|
588
|
+
if (item.customAttributes?.some(
|
|
589
|
+
(attribute) => attribute.key === _giveaway
|
|
590
|
+
))
|
|
591
|
+
return 0;
|
|
592
|
+
if (item.product?.tags?.some((tag) => campaign?.includeTags?.includes(tag)))
|
|
593
|
+
return 1;
|
|
594
|
+
return 2;
|
|
595
|
+
};
|
|
596
|
+
return getPriority(b) - getPriority(a);
|
|
597
|
+
},
|
|
598
|
+
[campaign?.includeTags, _giveaway]
|
|
599
|
+
);
|
|
600
|
+
return {
|
|
601
|
+
involvedLines,
|
|
602
|
+
reorder,
|
|
603
|
+
disableCodeRemove: involvedLines.length > 0,
|
|
604
|
+
nextFreeGiftLevel,
|
|
605
|
+
freeGiftLevel,
|
|
606
|
+
involvedSubTotal,
|
|
607
|
+
giftProductsResult: finalGiftProductsResult
|
|
608
|
+
};
|
|
609
|
+
};
|
|
610
|
+
function useCreateCart(options) {
|
|
611
|
+
const { client, locale, cartCookieAdapter } = useShopify();
|
|
612
|
+
const { mutateCart, metafieldIdentifiers } = useCartContext();
|
|
613
|
+
const createNewCart = react.useCallback(
|
|
614
|
+
async (_key, { arg }) => {
|
|
615
|
+
let newCart = await shopifySdk.createCart(client, {
|
|
616
|
+
...arg,
|
|
617
|
+
metafieldIdentifiers,
|
|
618
|
+
cookieAdapter: cartCookieAdapter
|
|
619
|
+
});
|
|
620
|
+
if (newCart) {
|
|
621
|
+
const unApplicableCodes = newCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
|
|
622
|
+
if (unApplicableCodes.length > 0) {
|
|
623
|
+
newCart = await shopifySdk.updateCartCodes(client, {
|
|
624
|
+
cartId: newCart.id,
|
|
625
|
+
discountCodes: newCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
|
|
626
|
+
metafieldIdentifiers,
|
|
627
|
+
cookieAdapter: cartCookieAdapter
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (newCart) {
|
|
632
|
+
mutateCart(newCart);
|
|
633
|
+
}
|
|
634
|
+
return newCart;
|
|
635
|
+
},
|
|
636
|
+
[client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
|
|
637
|
+
);
|
|
638
|
+
return useSWRMutation__default.default("create-cart", createNewCart, options);
|
|
639
|
+
}
|
|
640
|
+
function useAddCartLines(options) {
|
|
641
|
+
const { client, locale, cartCookieAdapter } = useShopify();
|
|
642
|
+
const { mutateCart, metafieldIdentifiers } = useCartContext();
|
|
643
|
+
const addLines = react.useCallback(
|
|
644
|
+
async (_key, { arg }) => {
|
|
645
|
+
let updatedCart = await shopifySdk.addCartLines(client, {
|
|
646
|
+
...arg,
|
|
647
|
+
metafieldIdentifiers,
|
|
648
|
+
cookieAdapter: cartCookieAdapter
|
|
649
|
+
});
|
|
650
|
+
if (updatedCart) {
|
|
651
|
+
const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
|
|
652
|
+
if (unApplicableCodes.length > 0) {
|
|
653
|
+
updatedCart = await shopifySdk.updateCartCodes(client, {
|
|
654
|
+
cartId: updatedCart.id,
|
|
655
|
+
discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
|
|
656
|
+
metafieldIdentifiers,
|
|
657
|
+
cookieAdapter: cartCookieAdapter
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (updatedCart) {
|
|
662
|
+
mutateCart(updatedCart);
|
|
663
|
+
}
|
|
664
|
+
return updatedCart;
|
|
665
|
+
},
|
|
666
|
+
[client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
|
|
667
|
+
);
|
|
668
|
+
return useSWRMutation__default.default("add-cart-lines", addLines, options);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// src/tracking/ga.ts
|
|
672
|
+
var gaTrack = (data) => {
|
|
673
|
+
if (typeof window === "undefined") {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
window.dataLayer = window?.dataLayer || [];
|
|
677
|
+
if (!Array.isArray(window.dataLayer)) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
try {
|
|
681
|
+
window?.dataLayer?.push({ event_parameters: null });
|
|
682
|
+
window?.dataLayer?.push(data || {});
|
|
683
|
+
} catch (error) {
|
|
684
|
+
console.error("GA tracking error:", error);
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
var trackAddToCartGA = ({
|
|
688
|
+
lineItems = [],
|
|
689
|
+
gtmParams = {},
|
|
690
|
+
brand
|
|
691
|
+
}) => {
|
|
692
|
+
if (!lineItems.length || !lineItems[0]?.variant) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
const { variant } = lineItems[0];
|
|
696
|
+
const currencyCode = variant?.price?.currencyCode;
|
|
697
|
+
const totalPrice = lineItems.reduce((sum, item) => {
|
|
698
|
+
const price = parseFloat(item.variant?.price?.amount || "0");
|
|
699
|
+
return sum + price;
|
|
700
|
+
}, 0);
|
|
701
|
+
gaTrack({
|
|
702
|
+
event: "ga4Event",
|
|
703
|
+
event_name: "add_to_cart",
|
|
704
|
+
event_parameters: {
|
|
705
|
+
page_group: gtmParams?.pageGroup,
|
|
706
|
+
currency: currencyCode,
|
|
707
|
+
value: totalPrice,
|
|
708
|
+
position: gtmParams?.position || "",
|
|
709
|
+
items: lineItems.map(({ variant: variant2, quantity }) => ({
|
|
710
|
+
item_id: variant2?.sku,
|
|
711
|
+
item_name: variant2?.product?.title || variant2?.product?.name,
|
|
712
|
+
item_brand: brand || gtmParams?.brand || "",
|
|
713
|
+
item_category: variant2?.product?.productType || "",
|
|
714
|
+
item_variant: variant2?.title || variant2?.name,
|
|
715
|
+
price: variant2?.finalPrice?.amount ?? variant2?.price?.amount,
|
|
716
|
+
quantity: quantity || 1
|
|
717
|
+
})),
|
|
718
|
+
...gtmParams?.ga4Params
|
|
719
|
+
}
|
|
720
|
+
});
|
|
721
|
+
};
|
|
722
|
+
var trackBeginCheckoutGA = ({
|
|
723
|
+
lineItems = [],
|
|
724
|
+
currencyCode,
|
|
725
|
+
totalPrice,
|
|
726
|
+
gtmParams = {},
|
|
727
|
+
brand
|
|
728
|
+
}) => {
|
|
729
|
+
if (!lineItems.length) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
gaTrack({
|
|
733
|
+
event: "ga4Event",
|
|
734
|
+
event_name: "begin_checkout",
|
|
735
|
+
event_parameters: {
|
|
736
|
+
page_group: gtmParams?.pageGroup,
|
|
737
|
+
position: gtmParams?.position,
|
|
738
|
+
currency: currencyCode,
|
|
739
|
+
value: totalPrice,
|
|
740
|
+
items: lineItems.map((item) => ({
|
|
741
|
+
item_id: item.variant?.sku,
|
|
742
|
+
item_name: item.variant?.product?.title,
|
|
743
|
+
item_brand: brand || gtmParams?.brand || "",
|
|
744
|
+
item_category: item.variant?.product?.productType,
|
|
745
|
+
item_variant: item.variant?.title,
|
|
746
|
+
price: item.finalPrice?.amount || item.variant?.price?.amount,
|
|
747
|
+
quantity: item.quantity || 1
|
|
748
|
+
})),
|
|
749
|
+
...gtmParams?.ga4Params
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
};
|
|
753
|
+
var trackBuyNowGA = ({
|
|
754
|
+
lineItems = [],
|
|
755
|
+
gtmParams = {},
|
|
756
|
+
brand
|
|
757
|
+
}) => {
|
|
758
|
+
if (!lineItems.length || !lineItems[0]?.variant) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const { variant } = lineItems[0];
|
|
762
|
+
const currencyCode = variant.price?.currencyCode;
|
|
763
|
+
const totalPrice = lineItems.reduce((sum, item) => {
|
|
764
|
+
const price = parseFloat(item.finalPrice?.amount || item.variant?.price?.amount || "0");
|
|
765
|
+
const quantity = item.quantity || 1;
|
|
766
|
+
return sum + price * quantity;
|
|
767
|
+
}, 0);
|
|
768
|
+
gaTrack({
|
|
769
|
+
event: "ga4Event",
|
|
770
|
+
event_name: "begin_checkout",
|
|
771
|
+
event_parameters: {
|
|
772
|
+
page_group: gtmParams?.pageGroup,
|
|
773
|
+
position: gtmParams?.position,
|
|
774
|
+
currency: currencyCode,
|
|
775
|
+
value: totalPrice,
|
|
776
|
+
items: lineItems.map((item) => ({
|
|
777
|
+
item_id: item.variant?.sku,
|
|
778
|
+
item_name: item.variant?.product?.title || item.variant?.title,
|
|
779
|
+
item_brand: item.variant?.product?.vendor || brand || gtmParams?.brand || "",
|
|
780
|
+
item_category: item.variant?.product?.productType || "",
|
|
781
|
+
item_variant: item.variant?.title,
|
|
782
|
+
price: item.finalPrice?.amount || item.variant?.price?.amount,
|
|
783
|
+
quantity: item.quantity || 1
|
|
784
|
+
})),
|
|
785
|
+
...gtmParams?.ga4Params
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
// src/tracking/fbq.ts
|
|
791
|
+
var trackAddToCartFBQ = ({ lineItems = [] }) => {
|
|
792
|
+
if (typeof window === "undefined" || !window.fbq) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (lineItems.length && lineItems[0]?.variant) {
|
|
796
|
+
const { variant, quantity, finalPrice } = lineItems[0];
|
|
797
|
+
try {
|
|
798
|
+
window.fbq("track", "AddToCart", {
|
|
799
|
+
value: finalPrice?.amount || variant?.price?.amount,
|
|
800
|
+
num_items: quantity,
|
|
801
|
+
currency: variant?.price?.currencyCode,
|
|
802
|
+
content_name: variant?.product?.title,
|
|
803
|
+
content_type: "product_group",
|
|
804
|
+
content_ids: String(variant?.id),
|
|
805
|
+
content_category: variant?.product?.metafields?.global?.trafficType || "public"
|
|
806
|
+
});
|
|
807
|
+
} catch (error) {
|
|
808
|
+
console.error("FBQ tracking error:", error);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
var trackBuyNowFBQ = ({ trackConfig }) => {
|
|
813
|
+
if (typeof window === "undefined") {
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
try {
|
|
817
|
+
if (trackConfig?.fbqBuyNowEvent && window.fbq) {
|
|
818
|
+
window.fbq("trackCustom", trackConfig.fbqBuyNowEvent);
|
|
819
|
+
}
|
|
820
|
+
if (trackConfig?.gtagBuyNowLabel && trackConfig?.gtagId && window.gtag) {
|
|
821
|
+
window.gtag("event", trackConfig.gtagBuyNowConversion || "conversion", {
|
|
822
|
+
send_to: `${trackConfig.gtagId}/${trackConfig.gtagBuyNowLabel}`
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
} catch (error) {
|
|
826
|
+
console.error("Buy Now tracking error:", error);
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
function useApplyCartCodes(options) {
|
|
830
|
+
const { client, locale, cartCookieAdapter } = useShopify();
|
|
831
|
+
const { mutateCart, cart, metafieldIdentifiers } = useCartContext();
|
|
832
|
+
const applyCodes = react.useCallback(
|
|
833
|
+
async (_key, { arg }) => {
|
|
834
|
+
const { cartId: providedCartId, discountCodes, replaceExistingCodes } = arg;
|
|
835
|
+
if (!discountCodes?.length) {
|
|
836
|
+
throw new Error("Invalid input used for this operation: Miss discountCode");
|
|
837
|
+
}
|
|
838
|
+
const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
|
|
839
|
+
if (!cartId) {
|
|
840
|
+
return void 0;
|
|
841
|
+
}
|
|
842
|
+
const updatedCart = await shopifySdk.updateCartCodes(client, {
|
|
843
|
+
cartId,
|
|
844
|
+
discountCodes: replaceExistingCodes ? discountCodes : [
|
|
845
|
+
...discountCodes,
|
|
846
|
+
...cart?.discountCodes?.filter((item) => item.applicable).map((item) => item.code) || []
|
|
847
|
+
],
|
|
848
|
+
cookieAdapter: cartCookieAdapter,
|
|
849
|
+
metafieldIdentifiers
|
|
850
|
+
});
|
|
851
|
+
if (updatedCart) {
|
|
852
|
+
mutateCart(updatedCart);
|
|
853
|
+
}
|
|
854
|
+
return updatedCart;
|
|
855
|
+
},
|
|
856
|
+
[client, locale, cartCookieAdapter, mutateCart, cart]
|
|
857
|
+
);
|
|
858
|
+
return useSWRMutation__default.default("apply-codes", applyCodes, options);
|
|
859
|
+
}
|
|
860
|
+
function useRemoveCartCodes(options) {
|
|
861
|
+
const { client, locale, cartCookieAdapter } = useShopify();
|
|
862
|
+
const { mutateCart, cart, metafieldIdentifiers } = useCartContext();
|
|
863
|
+
const removeCodes = react.useCallback(
|
|
864
|
+
async (_key, { arg }) => {
|
|
865
|
+
const { cartId: providedCartId, discountCodes } = arg;
|
|
866
|
+
const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
|
|
867
|
+
const codes = cart?.discountCodes?.filter((code) => !!code.applicable) || [];
|
|
868
|
+
const leftCodes = codes.filter((code) => discountCodes?.length ? !discountCodes.includes(code.code) : code.code).map((code) => code.code);
|
|
869
|
+
const updatedCart = await shopifySdk.updateCartCodes(client, {
|
|
870
|
+
cartId,
|
|
871
|
+
discountCodes: leftCodes,
|
|
872
|
+
metafieldIdentifiers,
|
|
873
|
+
cookieAdapter: cartCookieAdapter
|
|
874
|
+
});
|
|
875
|
+
if (updatedCart) {
|
|
876
|
+
mutateCart(updatedCart);
|
|
877
|
+
}
|
|
878
|
+
return updatedCart;
|
|
879
|
+
},
|
|
880
|
+
[client, locale, cartCookieAdapter, mutateCart, cart]
|
|
881
|
+
);
|
|
882
|
+
return useSWRMutation__default.default("remove-codes", removeCodes, options);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// src/hooks/cart/use-add-to-cart.ts
|
|
886
|
+
function useAddToCart({ withTrack = true, brand } = {}, swrOptions) {
|
|
887
|
+
const { client, locale, cartCookieAdapter, userAdapter } = useShopify();
|
|
888
|
+
const { mutateCart, cart, metafieldIdentifiers } = useCartContext();
|
|
889
|
+
const { trigger: applyCartCodes } = useApplyCartCodes();
|
|
890
|
+
const { trigger: removeInvalidCodes } = useRemoveCartCodes();
|
|
891
|
+
const { trigger: addCartLines2 } = useAddCartLines();
|
|
892
|
+
const addToCart = react.useCallback(
|
|
893
|
+
async (_key, { arg }) => {
|
|
894
|
+
const {
|
|
895
|
+
lineItems,
|
|
896
|
+
cartId: providedCartId,
|
|
897
|
+
discountCodes,
|
|
898
|
+
gtmParams = {},
|
|
899
|
+
buyerIdentity,
|
|
900
|
+
needCreateCart = false,
|
|
901
|
+
onCodesInvalid,
|
|
902
|
+
replaceExistingCodes
|
|
903
|
+
} = arg;
|
|
904
|
+
if (!lineItems || lineItems.length === 0) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
const lines = lineItems.map((item) => ({
|
|
908
|
+
merchandiseId: item.variant?.id || "",
|
|
909
|
+
quantity: item.quantity || 1,
|
|
910
|
+
attributes: item.attributes
|
|
911
|
+
})).filter((item) => item.merchandiseId && item.quantity);
|
|
912
|
+
if (lines.length === 0) {
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
const cartId = needCreateCart ? void 0 : providedCartId || cart?.id;
|
|
916
|
+
let resultCart = await addCartLines2({
|
|
917
|
+
cartId,
|
|
918
|
+
lines,
|
|
919
|
+
buyerIdentity
|
|
920
|
+
});
|
|
921
|
+
if (!resultCart) {
|
|
922
|
+
return void 0;
|
|
923
|
+
}
|
|
924
|
+
if (resultCart.discountCodes && resultCart.discountCodes.length > 0) {
|
|
925
|
+
const unapplicableCodes = resultCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
|
|
926
|
+
if (unapplicableCodes.length > 0) {
|
|
927
|
+
if (onCodesInvalid) {
|
|
928
|
+
const handledCart = await onCodesInvalid(resultCart, unapplicableCodes);
|
|
929
|
+
if (handledCart) {
|
|
930
|
+
resultCart = handledCart;
|
|
931
|
+
}
|
|
932
|
+
} else {
|
|
933
|
+
await removeInvalidCodes({
|
|
934
|
+
discountCodes: unapplicableCodes
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (discountCodes && discountCodes.length > 0) {
|
|
940
|
+
applyCartCodes({
|
|
941
|
+
replaceExistingCodes,
|
|
942
|
+
discountCodes
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
if (withTrack && resultCart.lineItems) {
|
|
946
|
+
const trackingLineItems = resultCart.lineItems.map((line) => ({
|
|
947
|
+
variant: {
|
|
948
|
+
id: line.variant.id,
|
|
949
|
+
sku: line.variant.sku || "",
|
|
950
|
+
title: line.variant.name,
|
|
951
|
+
price: {
|
|
952
|
+
amount: String(line.variant.price),
|
|
953
|
+
currencyCode: resultCart.currency.code
|
|
954
|
+
},
|
|
955
|
+
product: line.product ? {
|
|
956
|
+
title: line.product.title || line.name,
|
|
957
|
+
productType: line.product.productType,
|
|
958
|
+
vendor: line.product.vendor
|
|
959
|
+
} : void 0
|
|
960
|
+
},
|
|
961
|
+
quantity: line.quantity
|
|
962
|
+
}));
|
|
963
|
+
trackAddToCartGA({
|
|
964
|
+
lineItems: trackingLineItems,
|
|
965
|
+
gtmParams: { ...gtmParams, brand },
|
|
966
|
+
brand
|
|
967
|
+
});
|
|
968
|
+
trackAddToCartFBQ({ lineItems: trackingLineItems });
|
|
969
|
+
}
|
|
970
|
+
return resultCart;
|
|
971
|
+
},
|
|
972
|
+
[client, locale, cartCookieAdapter, userAdapter, cart, withTrack, brand]
|
|
973
|
+
);
|
|
974
|
+
return useSWRMutation__default.default("add-to-cart", addToCart, swrOptions);
|
|
975
|
+
}
|
|
976
|
+
function useUpdateCartLines(options) {
|
|
977
|
+
const { client, locale, cartCookieAdapter } = useShopify();
|
|
978
|
+
const { mutateCart, metafieldIdentifiers } = useCartContext();
|
|
979
|
+
const updateLines = react.useCallback(
|
|
980
|
+
async (_key, { arg }) => {
|
|
981
|
+
const updatedCart = await shopifySdk.updateCartLines(client, {
|
|
982
|
+
...arg,
|
|
983
|
+
metafieldIdentifiers,
|
|
984
|
+
cookieAdapter: cartCookieAdapter
|
|
985
|
+
});
|
|
986
|
+
if (updatedCart) {
|
|
987
|
+
mutateCart(updatedCart);
|
|
988
|
+
}
|
|
989
|
+
return updatedCart;
|
|
990
|
+
},
|
|
991
|
+
[client, locale, cartCookieAdapter, mutateCart]
|
|
992
|
+
);
|
|
993
|
+
return useSWRMutation__default.default("update-cart-lines", updateLines, options);
|
|
994
|
+
}
|
|
995
|
+
function useRemoveCartLines(options) {
|
|
996
|
+
const { client, locale, cartCookieAdapter } = useShopify();
|
|
997
|
+
const { mutateCart, metafieldIdentifiers } = useCartContext();
|
|
998
|
+
const removeLines = react.useCallback(
|
|
999
|
+
async (_key, { arg }) => {
|
|
1000
|
+
const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
|
|
1001
|
+
let updatedCart = await shopifySdk.removeCartLines(client, {
|
|
1002
|
+
cartId,
|
|
1003
|
+
lineIds,
|
|
1004
|
+
metafieldIdentifiers,
|
|
1005
|
+
cookieAdapter: cartCookieAdapter
|
|
1006
|
+
});
|
|
1007
|
+
if (updatedCart && autoRemoveInvalidCodes) {
|
|
1008
|
+
const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
|
|
1009
|
+
if (unApplicableCodes.length > 0) {
|
|
1010
|
+
if (onCodesRemoved) {
|
|
1011
|
+
const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
|
|
1012
|
+
if (handledCart) {
|
|
1013
|
+
updatedCart = handledCart;
|
|
1014
|
+
}
|
|
1015
|
+
} else {
|
|
1016
|
+
updatedCart = await shopifySdk.updateCartCodes(client, {
|
|
1017
|
+
cartId: updatedCart.id,
|
|
1018
|
+
discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
|
|
1019
|
+
metafieldIdentifiers,
|
|
1020
|
+
cookieAdapter: cartCookieAdapter
|
|
1021
|
+
}) || updatedCart;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
if (updatedCart) {
|
|
1026
|
+
mutateCart(updatedCart);
|
|
1027
|
+
}
|
|
1028
|
+
return updatedCart;
|
|
1029
|
+
},
|
|
1030
|
+
[client, locale, cartCookieAdapter, mutateCart]
|
|
1031
|
+
);
|
|
1032
|
+
return useSWRMutation__default.default("remove-cart-lines", removeLines, options);
|
|
1033
|
+
}
|
|
1034
|
+
function useUpdateCartAttributes(mutate, metafieldIdentifiers, options) {
|
|
1035
|
+
const { client, locale, cartCookieAdapter } = useShopify();
|
|
1036
|
+
const updateAttributes = react.useCallback(
|
|
1037
|
+
async (_key, { arg }) => {
|
|
1038
|
+
const updatedCart = await shopifySdk.updateCartAttributes(client, {
|
|
1039
|
+
...arg,
|
|
1040
|
+
metafieldIdentifiers,
|
|
1041
|
+
cookieAdapter: cartCookieAdapter
|
|
1042
|
+
});
|
|
1043
|
+
console.log("useUpdateCartAttributes updatedCart", updatedCart);
|
|
1044
|
+
if (updatedCart) {
|
|
1045
|
+
mutate(updatedCart);
|
|
1046
|
+
}
|
|
1047
|
+
return updatedCart;
|
|
1048
|
+
},
|
|
1049
|
+
[client, locale, cartCookieAdapter, mutate]
|
|
1050
|
+
);
|
|
1051
|
+
return useSWRMutation__default.default("update-cart-attributes", updateAttributes, options);
|
|
1052
|
+
}
|
|
1053
|
+
function useBuyNow({ withTrack = true, brand } = {}, swrOptions) {
|
|
1054
|
+
const { client, locale, cartCookieAdapter, userAdapter } = useShopify();
|
|
1055
|
+
const isLoggedIn = userAdapter?.isLoggedIn || false;
|
|
1056
|
+
const buyNow = react.useCallback(
|
|
1057
|
+
async (_key, { arg }) => {
|
|
1058
|
+
const {
|
|
1059
|
+
lineItems,
|
|
1060
|
+
discountCodes,
|
|
1061
|
+
gtmParams = {},
|
|
1062
|
+
buyerIdentity,
|
|
1063
|
+
fbqTrackConfig,
|
|
1064
|
+
customAttributes,
|
|
1065
|
+
metafieldIdentifiers,
|
|
1066
|
+
redirectToCheckout
|
|
1067
|
+
} = arg;
|
|
1068
|
+
if (!lineItems || lineItems.length === 0) {
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
const lines = lineItems.map((item) => ({
|
|
1072
|
+
merchandiseId: item.variant?.id || item.variantId || "",
|
|
1073
|
+
quantity: item.quantity || 1,
|
|
1074
|
+
attributes: item.attributes
|
|
1075
|
+
})).filter((item) => item.merchandiseId && item.quantity);
|
|
1076
|
+
if (lines.length === 0) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
const resultCart = await shopifySdk.createCart(client, {
|
|
1080
|
+
lines,
|
|
1081
|
+
metafieldIdentifiers,
|
|
1082
|
+
cookieAdapter: cartCookieAdapter,
|
|
1083
|
+
buyerIdentity,
|
|
1084
|
+
discountCodes,
|
|
1085
|
+
customAttributes
|
|
1086
|
+
});
|
|
1087
|
+
if (!resultCart) {
|
|
1088
|
+
throw new Error("Failed to create cart for buy now");
|
|
1089
|
+
}
|
|
1090
|
+
if (withTrack && resultCart.lineItems) {
|
|
1091
|
+
const trackingLineItems = resultCart.lineItems.map((line) => ({
|
|
1092
|
+
variant: {
|
|
1093
|
+
id: line.variantId,
|
|
1094
|
+
sku: line.variant.sku || "",
|
|
1095
|
+
title: line.variant.name,
|
|
1096
|
+
price: {
|
|
1097
|
+
amount: String(line.variant.price),
|
|
1098
|
+
currencyCode: resultCart.currency.code
|
|
1099
|
+
},
|
|
1100
|
+
product: line.product ? {
|
|
1101
|
+
title: line.product.title || line.name,
|
|
1102
|
+
productType: line.product.productType,
|
|
1103
|
+
vendor: line.product.vendor
|
|
1104
|
+
} : void 0
|
|
1105
|
+
},
|
|
1106
|
+
quantity: line.quantity
|
|
1107
|
+
}));
|
|
1108
|
+
trackBuyNowGA({
|
|
1109
|
+
lineItems: trackingLineItems,
|
|
1110
|
+
gtmParams: { ...gtmParams, brand },
|
|
1111
|
+
brand
|
|
1112
|
+
});
|
|
1113
|
+
if (fbqTrackConfig) {
|
|
1114
|
+
trackBuyNowFBQ({ trackConfig: fbqTrackConfig });
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
if (redirectToCheckout) {
|
|
1118
|
+
if (resultCart.url) {
|
|
1119
|
+
if (typeof window !== "undefined") {
|
|
1120
|
+
window.location.href = resultCart.url;
|
|
1121
|
+
}
|
|
1122
|
+
} else {
|
|
1123
|
+
throw new Error("Failed to get checkout URL");
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
return resultCart;
|
|
1127
|
+
},
|
|
1128
|
+
[client, locale, isLoggedIn, cartCookieAdapter, withTrack, brand]
|
|
1129
|
+
);
|
|
1130
|
+
return useSWRMutation__default.default("buy-now", buyNow, swrOptions);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// src/hooks/cart/types/order-discount.ts
|
|
1134
|
+
var OrderDiscountType = /* @__PURE__ */ ((OrderDiscountType2) => {
|
|
1135
|
+
OrderDiscountType2[OrderDiscountType2["PERCENTAGE"] = 1] = "PERCENTAGE";
|
|
1136
|
+
OrderDiscountType2[OrderDiscountType2["FIXED_AMOUNT"] = 2] = "FIXED_AMOUNT";
|
|
1137
|
+
OrderDiscountType2[OrderDiscountType2["REDUCE_PRICE"] = 3] = "REDUCE_PRICE";
|
|
1138
|
+
return OrderDiscountType2;
|
|
1139
|
+
})(OrderDiscountType || {});
|
|
1140
|
+
var OrderBasePriceType = /* @__PURE__ */ ((OrderBasePriceType2) => {
|
|
1141
|
+
OrderBasePriceType2[OrderBasePriceType2["ORIGIN_PRICE"] = 1] = "ORIGIN_PRICE";
|
|
1142
|
+
OrderBasePriceType2[OrderBasePriceType2["MIN_DISCOUNTED_PRICE"] = 2] = "MIN_DISCOUNTED_PRICE";
|
|
1143
|
+
return OrderBasePriceType2;
|
|
1144
|
+
})(OrderBasePriceType || {});
|
|
1145
|
+
|
|
1146
|
+
// src/hooks/cart/feature/use-calc-order-discount.ts
|
|
1147
|
+
var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
|
|
1148
|
+
const tags = react.useMemo(() => customer?.tags || [], [customer?.tags]);
|
|
1149
|
+
const isCustomerLoading = react.useMemo(() => !customer ? true : false, [customer]);
|
|
1150
|
+
const dealsType = "";
|
|
1151
|
+
const { activeCampaign, subtotal } = react.useMemo(() => {
|
|
1152
|
+
for (const campaign of orderDiscountConfig) {
|
|
1153
|
+
const { rule_conditions = [], result_detail } = campaign;
|
|
1154
|
+
const { main_product, order_discount_conf } = result_detail || {};
|
|
1155
|
+
const isPreCheckPassed = preCheck(rule_conditions, tags, []);
|
|
1156
|
+
if (isPreCheckPassed && main_product && order_discount_conf) {
|
|
1157
|
+
const matchedSubtotal = getMatchedMainProductSubTotal(
|
|
1158
|
+
cart,
|
|
1159
|
+
main_product?.variant_list?.map((v) => v.variant_id) || [],
|
|
1160
|
+
{
|
|
1161
|
+
spend_money_type: order_discount_conf.base_price === 2 /* MIN_DISCOUNTED_PRICE */ ? 2 : 1,
|
|
1162
|
+
// 根据基础价格类型设置
|
|
1163
|
+
variant_id_list: main_product?.variant_list?.map((v) => v.variant_id) || [],
|
|
1164
|
+
all_store_variant: main_product?.all_store_variant || false
|
|
1165
|
+
}
|
|
1166
|
+
);
|
|
1167
|
+
if (matchedSubtotal > 0) {
|
|
1168
|
+
return { activeCampaign: campaign, subtotal: matchedSubtotal };
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
return { activeCampaign: null, subtotal: 0 };
|
|
1173
|
+
}, [orderDiscountConfig, cart, tags, dealsType]);
|
|
1174
|
+
const { qualifyingDiscount, nextTierGoal, discountAmount } = react.useMemo(() => {
|
|
1175
|
+
if (!activeCampaign || !activeCampaign.result_detail?.order_discount_conf?.tiered_discounts) {
|
|
1176
|
+
return {
|
|
1177
|
+
qualifyingDiscount: null,
|
|
1178
|
+
nextTierGoal: null,
|
|
1179
|
+
discountAmount: 0
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
const tieredDiscounts = activeCampaign.result_detail.order_discount_conf.tiered_discounts;
|
|
1183
|
+
const qualifyingTier = [...tieredDiscounts].reverse().find((tier) => subtotal >= Number(tier.amount));
|
|
1184
|
+
const nextGoal = tieredDiscounts.find((tier) => subtotal < Number(tier.amount));
|
|
1185
|
+
if (!qualifyingTier) {
|
|
1186
|
+
return {
|
|
1187
|
+
qualifyingDiscount: null,
|
|
1188
|
+
nextTierGoal: nextGoal || null,
|
|
1189
|
+
discountAmount: 0
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
let calculatedDiscount = 0;
|
|
1193
|
+
switch (qualifyingTier.discount_type) {
|
|
1194
|
+
case 1 /* PERCENTAGE */:
|
|
1195
|
+
calculatedDiscount = subtotal * qualifyingTier.discount / 100;
|
|
1196
|
+
break;
|
|
1197
|
+
case 2 /* FIXED_AMOUNT */:
|
|
1198
|
+
calculatedDiscount = qualifyingTier.discount;
|
|
1199
|
+
break;
|
|
1200
|
+
case 3 /* REDUCE_PRICE */:
|
|
1201
|
+
calculatedDiscount = Math.min(subtotal, qualifyingTier.discount);
|
|
1202
|
+
break;
|
|
1203
|
+
default:
|
|
1204
|
+
calculatedDiscount = 0;
|
|
1205
|
+
}
|
|
1206
|
+
return {
|
|
1207
|
+
qualifyingDiscount: qualifyingTier,
|
|
1208
|
+
nextTierGoal: nextGoal || null,
|
|
1209
|
+
discountAmount: calculatedDiscount
|
|
1210
|
+
};
|
|
1211
|
+
}, [activeCampaign, subtotal]);
|
|
1212
|
+
return {
|
|
1213
|
+
qualifyingDiscount,
|
|
1214
|
+
nextTierGoal,
|
|
1215
|
+
activeCampaign,
|
|
1216
|
+
discountAmount,
|
|
1217
|
+
cartTotalForDiscount: subtotal,
|
|
1218
|
+
isLoading: isCustomerLoading
|
|
1219
|
+
};
|
|
1220
|
+
};
|
|
1221
|
+
function useHasPlusMemberInCart({
|
|
1222
|
+
memberSetting,
|
|
1223
|
+
cart
|
|
1224
|
+
}) {
|
|
1225
|
+
const { plus_monthly_product, plus_annual_product } = memberSetting || {};
|
|
1226
|
+
return react.useMemo(() => {
|
|
1227
|
+
if (!cart?.lineItems) {
|
|
1228
|
+
return {
|
|
1229
|
+
hasPlusMember: false,
|
|
1230
|
+
hasMonthlyPlus: false,
|
|
1231
|
+
hasAnnualPlus: false
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
const monthlyPlusItem = cart.lineItems.find(
|
|
1235
|
+
(item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
|
|
1236
|
+
);
|
|
1237
|
+
const annualPlusItem = cart.lineItems.find(
|
|
1238
|
+
(item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
|
|
1239
|
+
);
|
|
1240
|
+
const hasMonthlyPlus = !!monthlyPlusItem;
|
|
1241
|
+
const hasAnnualPlus = !!annualPlusItem;
|
|
1242
|
+
const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
|
|
1243
|
+
return {
|
|
1244
|
+
hasPlusMember,
|
|
1245
|
+
hasMonthlyPlus,
|
|
1246
|
+
hasAnnualPlus,
|
|
1247
|
+
monthlyPlusItem,
|
|
1248
|
+
annualPlusItem
|
|
1249
|
+
};
|
|
1250
|
+
}, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// src/hooks/cart/feature/use-cart-attributes.ts
|
|
1254
|
+
var getReferralAttributes = () => {
|
|
1255
|
+
const inviteCode = Cookies5__default.default.get("invite_code");
|
|
1256
|
+
const playModeId = Cookies5__default.default.get("playModeId");
|
|
1257
|
+
const popup = Cookies5__default.default.get("_popup");
|
|
1258
|
+
if (inviteCode && playModeId) {
|
|
1259
|
+
return popup ? [
|
|
1260
|
+
{ key: "_invite_code", value: inviteCode ? inviteCode : "" },
|
|
1261
|
+
{ key: "_play_mode_id", value: playModeId ? playModeId : "" },
|
|
1262
|
+
{ key: "_popup", value: popup }
|
|
1263
|
+
] : [
|
|
1264
|
+
{ key: "_invite_code", value: inviteCode ? inviteCode : "" },
|
|
1265
|
+
{ key: "_play_mode_id", value: playModeId ? playModeId : "" }
|
|
1266
|
+
];
|
|
1267
|
+
}
|
|
1268
|
+
return [];
|
|
1269
|
+
};
|
|
1270
|
+
var useCartAttributes = ({
|
|
1271
|
+
profile,
|
|
1272
|
+
customer,
|
|
1273
|
+
cart,
|
|
1274
|
+
memberSetting
|
|
1275
|
+
}) => {
|
|
1276
|
+
const [currentUrl, setCurrentUrl] = react.useState("");
|
|
1277
|
+
const { hasPlusMember } = useHasPlusMemberInCart({
|
|
1278
|
+
memberSetting,
|
|
1279
|
+
cart
|
|
1280
|
+
});
|
|
1281
|
+
console.log("memberSetting", memberSetting);
|
|
1282
|
+
console.log("hasPlusMember", hasPlusMember);
|
|
1283
|
+
react.useEffect(() => {
|
|
1284
|
+
setCurrentUrl(window.location.href);
|
|
1285
|
+
}, []);
|
|
1286
|
+
const userType = react.useMemo(() => {
|
|
1287
|
+
let userInfo = Cookies5__default.default.get("userInfo");
|
|
1288
|
+
if (userInfo) {
|
|
1289
|
+
userInfo = JSON.parse(userInfo);
|
|
1290
|
+
let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
|
|
1291
|
+
userInfo.setId = arr[arr.length - 1];
|
|
1292
|
+
}
|
|
1293
|
+
const customerInfo = userInfo || customer;
|
|
1294
|
+
if (!customerInfo) {
|
|
1295
|
+
return "new_user_unlogin";
|
|
1296
|
+
}
|
|
1297
|
+
if (customer) {
|
|
1298
|
+
const { orders = {} } = customer;
|
|
1299
|
+
if (orders?.edges?.length === 1) {
|
|
1300
|
+
return "old_user_orders_once";
|
|
1301
|
+
} else if (orders?.edges?.length > 1) {
|
|
1302
|
+
return "old_user_orders_twice";
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
return "new_user_login";
|
|
1306
|
+
}, [customer]);
|
|
1307
|
+
const memberAttributes = react.useMemo(() => {
|
|
1308
|
+
return [
|
|
1309
|
+
{
|
|
1310
|
+
key: "_token",
|
|
1311
|
+
value: profile?.token
|
|
1312
|
+
//是否登录
|
|
1313
|
+
},
|
|
1314
|
+
{
|
|
1315
|
+
key: "_member_type",
|
|
1316
|
+
value: hasPlusMember ? "2" : profile?.memberType
|
|
1317
|
+
//:0(游客),1(普通会员),2(付费会员)
|
|
1318
|
+
},
|
|
1319
|
+
{
|
|
1320
|
+
key: "_user_type",
|
|
1321
|
+
value: userType
|
|
1322
|
+
// n
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
key: "_is_login",
|
|
1326
|
+
value: profile?.token ? "true" : "false"
|
|
1327
|
+
}
|
|
1328
|
+
];
|
|
1329
|
+
}, [profile?.memberType, profile?.token, userType, hasPlusMember]);
|
|
1330
|
+
const functionAttributes = react.useMemo(() => {
|
|
1331
|
+
return [
|
|
1332
|
+
cart?.discountCodes && {
|
|
1333
|
+
key: "_discounts_function_env",
|
|
1334
|
+
value: JSON.stringify({
|
|
1335
|
+
discount_code: cart?.discountCodes.map((item) => item.code),
|
|
1336
|
+
user_tags: customer?.tags || []
|
|
1337
|
+
})
|
|
1338
|
+
}
|
|
1339
|
+
];
|
|
1340
|
+
}, [cart]);
|
|
1341
|
+
const presellAttributes = react.useMemo(() => {
|
|
1342
|
+
return [
|
|
1343
|
+
{
|
|
1344
|
+
key: "_presale",
|
|
1345
|
+
value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
|
|
1346
|
+
}
|
|
1347
|
+
];
|
|
1348
|
+
}, [cart]);
|
|
1349
|
+
const weightAttributes = react.useMemo(() => {
|
|
1350
|
+
return [
|
|
1351
|
+
{
|
|
1352
|
+
key: "_weight",
|
|
1353
|
+
value: cart?.lineItems.reduce((acc, item) => {
|
|
1354
|
+
return new Decimal2__default.default(acc).plus(item.variant.weight ?? 0).toNumber();
|
|
1355
|
+
}, 0).toString()
|
|
1356
|
+
},
|
|
1357
|
+
{
|
|
1358
|
+
key: "_app_source_name",
|
|
1359
|
+
value: "dtc"
|
|
1360
|
+
}
|
|
1361
|
+
];
|
|
1362
|
+
}, [cart]);
|
|
1363
|
+
const trackingAttributes = react.useMemo(() => {
|
|
1364
|
+
return [
|
|
1365
|
+
{
|
|
1366
|
+
key: "utm_params",
|
|
1367
|
+
value: currentUrl
|
|
1368
|
+
}
|
|
1369
|
+
];
|
|
1370
|
+
}, [currentUrl]);
|
|
1371
|
+
return react.useMemo(
|
|
1372
|
+
() => ({
|
|
1373
|
+
attributes: [
|
|
1374
|
+
...memberAttributes,
|
|
1375
|
+
...functionAttributes,
|
|
1376
|
+
...presellAttributes,
|
|
1377
|
+
...weightAttributes,
|
|
1378
|
+
...trackingAttributes,
|
|
1379
|
+
...getReferralAttributes()
|
|
1380
|
+
].filter((item) => item?.value)
|
|
1381
|
+
}),
|
|
1382
|
+
[memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
|
|
1383
|
+
);
|
|
1384
|
+
};
|
|
1385
|
+
var DEFAULT_MIN = 1;
|
|
1386
|
+
var DEFAULT_MAX = 999;
|
|
1387
|
+
var useCartItemQuantityLimit = ({
|
|
1388
|
+
cart,
|
|
1389
|
+
cartItem,
|
|
1390
|
+
config
|
|
1391
|
+
}) => {
|
|
1392
|
+
const quantityLimit = react.useMemo(() => {
|
|
1393
|
+
if (config?.handle) {
|
|
1394
|
+
const cartItemQuantityLimit = config?.handle?.[cartItem?.product?.handle || ""];
|
|
1395
|
+
const sameHandleTotalQuantity = cart?.lineItems.reduce((acc, item) => {
|
|
1396
|
+
if (item.product?.handle === cartItem?.product?.handle && item.variant.sku !== cartItem.variant.sku) {
|
|
1397
|
+
acc += item.quantity;
|
|
1398
|
+
}
|
|
1399
|
+
return acc;
|
|
1400
|
+
}, 0) || 0;
|
|
1401
|
+
return {
|
|
1402
|
+
min: cartItemQuantityLimit?.min || DEFAULT_MIN,
|
|
1403
|
+
max: cartItemQuantityLimit?.max ? cartItemQuantityLimit?.max - sameHandleTotalQuantity : DEFAULT_MAX
|
|
1404
|
+
};
|
|
1405
|
+
} else if (config?.sku) {
|
|
1406
|
+
const cartItemQuantityLimit = config?.sku?.[cartItem?.variant?.sku];
|
|
1407
|
+
return {
|
|
1408
|
+
min: cartItemQuantityLimit?.min || DEFAULT_MIN,
|
|
1409
|
+
max: cartItemQuantityLimit?.max || DEFAULT_MAX
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
return {
|
|
1413
|
+
min: DEFAULT_MIN,
|
|
1414
|
+
max: DEFAULT_MAX
|
|
1415
|
+
};
|
|
1416
|
+
}, [cartItem, cart]);
|
|
1417
|
+
return quantityLimit;
|
|
1418
|
+
};
|
|
1419
|
+
var useUpdateLineCodeAmountAttributes = ({
|
|
1420
|
+
cart,
|
|
1421
|
+
mutateCart,
|
|
1422
|
+
isCartLoading,
|
|
1423
|
+
setLoadingState,
|
|
1424
|
+
metafieldIdentifiers
|
|
1425
|
+
}) => {
|
|
1426
|
+
const { client, cartCookieAdapter } = useShopify();
|
|
1427
|
+
const mainProductDiscountCodes = react.useMemo(
|
|
1428
|
+
() => cart?.discountCodes.filter(
|
|
1429
|
+
({ code, applicable }) => applicable && MAIN_PRODUCT_CODE.some((codePrefix) => code.startsWith(codePrefix))
|
|
1430
|
+
).map(({ code }) => code),
|
|
1431
|
+
[cart]
|
|
1432
|
+
);
|
|
1433
|
+
const linesNeedUpdate = react.useMemo(
|
|
1434
|
+
() => cart?.lineItems.map((line) => {
|
|
1435
|
+
const attrNeedUpdate = [];
|
|
1436
|
+
const attrNeedDelete = [];
|
|
1437
|
+
const codeDiscount = line.discountAllocations?.find(
|
|
1438
|
+
(allocation) => mainProductDiscountCodes?.includes(allocation.code)
|
|
1439
|
+
);
|
|
1440
|
+
const hasFunctionEnvAttribute = line.customAttributes?.find(
|
|
1441
|
+
(attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY
|
|
1442
|
+
);
|
|
1443
|
+
const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
|
|
1444
|
+
const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
|
|
1445
|
+
if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
|
|
1446
|
+
attrNeedUpdate.push({
|
|
1447
|
+
key: CUSTOMER_ATTRIBUTE_KEY,
|
|
1448
|
+
value: JSON.stringify({
|
|
1449
|
+
...functionEnvValue,
|
|
1450
|
+
discounted_amount: Number(line.totalAmount)
|
|
1451
|
+
})
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
const codeDiscountAmount = codeDiscount?.amount || 0;
|
|
1455
|
+
const hasCodeAmountAttribute = line.customAttributes?.find(
|
|
1456
|
+
(attr) => attr.key === CODE_AMOUNT_KEY || attr.key === SCRIPT_CODE_AMOUNT_KEY
|
|
1457
|
+
);
|
|
1458
|
+
const hasSameCodeAmountAttribute = line.customAttributes?.find(
|
|
1459
|
+
(attr) => attr.key === CODE_AMOUNT_KEY && attr.value === String(codeDiscountAmount)
|
|
1460
|
+
) && line.customAttributes?.find(
|
|
1461
|
+
(attr) => attr.key === SCRIPT_CODE_AMOUNT_KEY && attr.value === String(codeDiscountAmount)
|
|
1462
|
+
);
|
|
1463
|
+
if (codeDiscount && !hasSameCodeAmountAttribute) {
|
|
1464
|
+
attrNeedUpdate.push({
|
|
1465
|
+
key: CODE_AMOUNT_KEY,
|
|
1466
|
+
value: String(codeDiscountAmount)
|
|
1467
|
+
});
|
|
1468
|
+
attrNeedUpdate.push({
|
|
1469
|
+
key: SCRIPT_CODE_AMOUNT_KEY,
|
|
1470
|
+
value: String(codeDiscountAmount)
|
|
1471
|
+
});
|
|
1472
|
+
} else if (!codeDiscount && hasCodeAmountAttribute) {
|
|
1473
|
+
attrNeedDelete.push(CODE_AMOUNT_KEY);
|
|
1474
|
+
attrNeedDelete.push(SCRIPT_CODE_AMOUNT_KEY);
|
|
1475
|
+
}
|
|
1476
|
+
return {
|
|
1477
|
+
line,
|
|
1478
|
+
attrNeedUpdate,
|
|
1479
|
+
attrNeedDelete
|
|
1480
|
+
};
|
|
1481
|
+
}).filter(
|
|
1482
|
+
({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
|
|
1483
|
+
).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
|
|
1484
|
+
if (attrNeedUpdate.length) {
|
|
1485
|
+
return {
|
|
1486
|
+
id: line.id,
|
|
1487
|
+
attributes: [
|
|
1488
|
+
...line.customAttributes?.filter(
|
|
1489
|
+
(attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
|
|
1490
|
+
) || [],
|
|
1491
|
+
...attrNeedUpdate
|
|
1492
|
+
]
|
|
1493
|
+
};
|
|
1494
|
+
} else if (attrNeedDelete.length) {
|
|
1495
|
+
return {
|
|
1496
|
+
id: line.id,
|
|
1497
|
+
attributes: line.customAttributes?.filter(
|
|
1498
|
+
(attr) => !attrNeedDelete.includes(attr.key)
|
|
1499
|
+
) || []
|
|
1500
|
+
};
|
|
1501
|
+
} else {
|
|
1502
|
+
return {
|
|
1503
|
+
id: line.id,
|
|
1504
|
+
attributes: line.customAttributes || []
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
}),
|
|
1508
|
+
[cart?.lineItems, mainProductDiscountCodes]
|
|
1509
|
+
);
|
|
1510
|
+
const { loading } = ahooks.useRequest(
|
|
1511
|
+
async () => {
|
|
1512
|
+
if (linesNeedUpdate?.length && !isCartLoading) {
|
|
1513
|
+
const result = await shopifySdk.updateCartLines(client, {
|
|
1514
|
+
cartId: cart?.id || "",
|
|
1515
|
+
lines: linesNeedUpdate,
|
|
1516
|
+
metafieldIdentifiers,
|
|
1517
|
+
cookieAdapter: cartCookieAdapter
|
|
1518
|
+
});
|
|
1519
|
+
if (result) {
|
|
1520
|
+
mutateCart(result);
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
},
|
|
1524
|
+
{
|
|
1525
|
+
throttleWait: 3e3,
|
|
1526
|
+
// 3 秒内只触发最后一次更新
|
|
1527
|
+
throttleTrailing: true,
|
|
1528
|
+
refreshDeps: [linesNeedUpdate, isCartLoading]
|
|
1529
|
+
}
|
|
1530
|
+
);
|
|
1531
|
+
react.useEffect(() => {
|
|
1532
|
+
setLoadingState((prev) => {
|
|
1533
|
+
return {
|
|
1534
|
+
...prev,
|
|
1535
|
+
editLineCodeAmountLoading: loading
|
|
1536
|
+
};
|
|
1537
|
+
});
|
|
1538
|
+
}, [loading, setLoadingState]);
|
|
1539
|
+
};
|
|
1540
|
+
|
|
1541
|
+
// src/hooks/cart/types/price-discount.ts
|
|
1542
|
+
var PriceDiscountType = /* @__PURE__ */ ((PriceDiscountType2) => {
|
|
1543
|
+
PriceDiscountType2[PriceDiscountType2["PERCENTAGE"] = 1] = "PERCENTAGE";
|
|
1544
|
+
PriceDiscountType2[PriceDiscountType2["FIXED_AMOUNT"] = 2] = "FIXED_AMOUNT";
|
|
1545
|
+
return PriceDiscountType2;
|
|
1546
|
+
})(PriceDiscountType || {});
|
|
1547
|
+
var PriceBasePriceType = /* @__PURE__ */ ((PriceBasePriceType2) => {
|
|
1548
|
+
PriceBasePriceType2[PriceBasePriceType2["MIN_DISCOUNTED_PRICE"] = 1] = "MIN_DISCOUNTED_PRICE";
|
|
1549
|
+
PriceBasePriceType2[PriceBasePriceType2["MIN_TOTAL_PRICE"] = 2] = "MIN_TOTAL_PRICE";
|
|
1550
|
+
return PriceBasePriceType2;
|
|
1551
|
+
})(PriceBasePriceType || {});
|
|
1552
|
+
function useProduct(options = {}) {
|
|
1553
|
+
const { client, locale } = useShopify();
|
|
1554
|
+
const { handle, metafieldIdentifiers, ...swrOptions } = options;
|
|
1555
|
+
return useSWR__default.default(
|
|
1556
|
+
handle ? ["product", locale, handle, metafieldIdentifiers] : null,
|
|
1557
|
+
() => shopifySdk.getProduct(client, {
|
|
1558
|
+
handle,
|
|
1559
|
+
locale,
|
|
1560
|
+
metafieldIdentifiers
|
|
1561
|
+
}),
|
|
1562
|
+
swrOptions
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1565
|
+
function useAllProducts(options = {}) {
|
|
1566
|
+
const { client, locale } = useShopify();
|
|
1567
|
+
const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
|
|
1568
|
+
return useSWR__default.default(
|
|
1569
|
+
["all-products", locale, first, query, sortKey, reverse, metafieldIdentifiers],
|
|
1570
|
+
() => shopifySdk.getAllProducts(client, {
|
|
1571
|
+
locale,
|
|
1572
|
+
first,
|
|
1573
|
+
query,
|
|
1574
|
+
sortKey,
|
|
1575
|
+
reverse,
|
|
1576
|
+
metafieldIdentifiers
|
|
1577
|
+
}),
|
|
1578
|
+
swrOptions
|
|
1579
|
+
);
|
|
1580
|
+
}
|
|
1581
|
+
function useProductsByHandles(options = {}) {
|
|
1582
|
+
const { client, locale } = useShopify();
|
|
1583
|
+
const { handles: originHandles, metafieldIdentifiers, ...swrOptions } = options;
|
|
1584
|
+
const handles = new Set(originHandles || []);
|
|
1585
|
+
const sortedHandles = handles ? [...handles].sort() : void 0;
|
|
1586
|
+
return useSWR__default.default(
|
|
1587
|
+
sortedHandles && sortedHandles.length > 0 ? ["products-by-handles", locale, sortedHandles.join(","), metafieldIdentifiers] : null,
|
|
1588
|
+
() => {
|
|
1589
|
+
const handlesArray = [...handles];
|
|
1590
|
+
if (handlesArray?.length === 0) {
|
|
1591
|
+
throw new Error("Handles are required");
|
|
1592
|
+
}
|
|
1593
|
+
return shopifySdk.getProductsByHandles(client, {
|
|
1594
|
+
handles: [...handles],
|
|
1595
|
+
locale,
|
|
1596
|
+
metafieldIdentifiers
|
|
1597
|
+
});
|
|
1598
|
+
},
|
|
1599
|
+
swrOptions || {
|
|
1600
|
+
revalidateOnFocus: false
|
|
1601
|
+
}
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
function getFirstAvailableVariant(product) {
|
|
1605
|
+
const availableVariant = product.variants.find((v) => v.availableForSale);
|
|
1606
|
+
return availableVariant || product.variants[0];
|
|
1607
|
+
}
|
|
1608
|
+
function getVariantFromSelectedOptions(product, selectedOptions) {
|
|
1609
|
+
return product.variants.find((variant) => {
|
|
1610
|
+
return variant.selectedOptions.every((option) => {
|
|
1611
|
+
return selectedOptions[option.name] === option.value;
|
|
1612
|
+
});
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
function useVariant({
|
|
1616
|
+
product,
|
|
1617
|
+
selectedOptions
|
|
1618
|
+
}) {
|
|
1619
|
+
const [variant, setVariant] = react.useState(
|
|
1620
|
+
product ? getFirstAvailableVariant(product) : void 0
|
|
1621
|
+
);
|
|
1622
|
+
react.useEffect(() => {
|
|
1623
|
+
if (!product) {
|
|
1624
|
+
setVariant(void 0);
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
const newVariant = getVariantFromSelectedOptions(product, selectedOptions);
|
|
1628
|
+
if (newVariant && newVariant.id !== variant?.id) {
|
|
1629
|
+
setVariant(newVariant);
|
|
1630
|
+
} else if (!newVariant) {
|
|
1631
|
+
setVariant(getFirstAvailableVariant(product));
|
|
1632
|
+
}
|
|
1633
|
+
}, [selectedOptions, product, variant?.id]);
|
|
1634
|
+
return variant;
|
|
1635
|
+
}
|
|
1636
|
+
var FAKE_PRICE = 999999999e-2;
|
|
1637
|
+
function formatPrice({
|
|
1638
|
+
amount,
|
|
1639
|
+
currencyCode,
|
|
1640
|
+
locale,
|
|
1641
|
+
maximumFractionDigits,
|
|
1642
|
+
minimumFractionDigits,
|
|
1643
|
+
removeTrailingZeros
|
|
1644
|
+
}) {
|
|
1645
|
+
const formatter = new Intl.NumberFormat(locale, {
|
|
1646
|
+
style: "currency",
|
|
1647
|
+
currency: currencyCode,
|
|
1648
|
+
maximumFractionDigits: maximumFractionDigits ?? 2,
|
|
1649
|
+
minimumFractionDigits: minimumFractionDigits ?? 2
|
|
1650
|
+
});
|
|
1651
|
+
let formatted = formatter.format(amount);
|
|
1652
|
+
if (removeTrailingZeros) {
|
|
1653
|
+
formatted = formatted.replace(/\.00$/, "");
|
|
1654
|
+
}
|
|
1655
|
+
return formatted;
|
|
1656
|
+
}
|
|
1657
|
+
function formatVariantPrice({
|
|
1658
|
+
amount,
|
|
1659
|
+
baseAmount,
|
|
1660
|
+
currencyCode,
|
|
1661
|
+
locale,
|
|
1662
|
+
maximumFractionDigits,
|
|
1663
|
+
minimumFractionDigits,
|
|
1664
|
+
removeTrailingZeros
|
|
1665
|
+
}) {
|
|
1666
|
+
return {
|
|
1667
|
+
price: formatPrice({
|
|
1668
|
+
amount,
|
|
1669
|
+
currencyCode,
|
|
1670
|
+
locale,
|
|
1671
|
+
maximumFractionDigits,
|
|
1672
|
+
minimumFractionDigits,
|
|
1673
|
+
removeTrailingZeros
|
|
1674
|
+
}),
|
|
1675
|
+
basePrice: formatPrice({
|
|
1676
|
+
amount: baseAmount,
|
|
1677
|
+
currencyCode,
|
|
1678
|
+
locale,
|
|
1679
|
+
maximumFractionDigits,
|
|
1680
|
+
minimumFractionDigits,
|
|
1681
|
+
removeTrailingZeros
|
|
1682
|
+
})
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
function usePrice({
|
|
1686
|
+
amount,
|
|
1687
|
+
baseAmount,
|
|
1688
|
+
currencyCode,
|
|
1689
|
+
soldOutDescription = "",
|
|
1690
|
+
maximumFractionDigits,
|
|
1691
|
+
minimumFractionDigits,
|
|
1692
|
+
removeTrailingZeros
|
|
1693
|
+
}) {
|
|
1694
|
+
const { locale } = useShopify();
|
|
1695
|
+
const value = react.useMemo(() => {
|
|
1696
|
+
if (typeof amount !== "number" || !currencyCode) {
|
|
1697
|
+
return "";
|
|
1698
|
+
}
|
|
1699
|
+
if (soldOutDescription && amount >= FAKE_PRICE) {
|
|
1700
|
+
return soldOutDescription;
|
|
1701
|
+
}
|
|
1702
|
+
return baseAmount ? formatVariantPrice({
|
|
1703
|
+
amount,
|
|
1704
|
+
baseAmount,
|
|
1705
|
+
currencyCode,
|
|
1706
|
+
locale,
|
|
1707
|
+
maximumFractionDigits,
|
|
1708
|
+
minimumFractionDigits,
|
|
1709
|
+
removeTrailingZeros
|
|
1710
|
+
}) : formatPrice({
|
|
1711
|
+
amount,
|
|
1712
|
+
currencyCode,
|
|
1713
|
+
locale,
|
|
1714
|
+
maximumFractionDigits,
|
|
1715
|
+
minimumFractionDigits,
|
|
1716
|
+
removeTrailingZeros
|
|
1717
|
+
});
|
|
1718
|
+
}, [
|
|
1719
|
+
amount,
|
|
1720
|
+
baseAmount,
|
|
1721
|
+
currencyCode,
|
|
1722
|
+
locale,
|
|
1723
|
+
maximumFractionDigits,
|
|
1724
|
+
minimumFractionDigits,
|
|
1725
|
+
soldOutDescription,
|
|
1726
|
+
removeTrailingZeros
|
|
1727
|
+
]);
|
|
1728
|
+
const result = react.useMemo(() => {
|
|
1729
|
+
const free = Boolean(amount && amount <= 0);
|
|
1730
|
+
return typeof value === "string" ? { price: value, basePrice: value, free } : { ...value, free };
|
|
1731
|
+
}, [value, amount]);
|
|
1732
|
+
return result;
|
|
1733
|
+
}
|
|
1734
|
+
function optionsConstructor(selectedOptions) {
|
|
1735
|
+
return selectedOptions.reduce((acc, option) => {
|
|
1736
|
+
acc[option.name] = option.value;
|
|
1737
|
+
return acc;
|
|
1738
|
+
}, {});
|
|
1739
|
+
}
|
|
1740
|
+
function decodeShopifyId(gid) {
|
|
1741
|
+
try {
|
|
1742
|
+
const base64 = gid.split("/").pop() || "";
|
|
1743
|
+
return atob(base64);
|
|
1744
|
+
} catch {
|
|
1745
|
+
return gid;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
function useSelectedOptions(product, sku) {
|
|
1749
|
+
const [options, setOptions] = react.useState({});
|
|
1750
|
+
react.useEffect(() => {
|
|
1751
|
+
if (!product || !product.variants.length) {
|
|
1752
|
+
setOptions({});
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
let variant = product.variants[0];
|
|
1756
|
+
if (typeof window !== "undefined") {
|
|
1757
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
1758
|
+
const variantIdParam = searchParams.get("variant");
|
|
1759
|
+
if (variantIdParam) {
|
|
1760
|
+
const foundVariant = product.variants.find((v) => {
|
|
1761
|
+
if (sku) return v.sku === sku;
|
|
1762
|
+
return v.id === variantIdParam || v.id.includes(variantIdParam) || decodeShopifyId(v.id) === variantIdParam;
|
|
1763
|
+
});
|
|
1764
|
+
if (foundVariant) {
|
|
1765
|
+
variant = foundVariant;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
if (variant) {
|
|
1770
|
+
const newOptions = optionsConstructor(variant.selectedOptions);
|
|
1771
|
+
setOptions(newOptions);
|
|
1772
|
+
}
|
|
1773
|
+
}, [product, sku]);
|
|
1774
|
+
return [options, setOptions];
|
|
1775
|
+
}
|
|
1776
|
+
function decodeShopifyId2(gid) {
|
|
1777
|
+
try {
|
|
1778
|
+
const parts = gid.split("/");
|
|
1779
|
+
return parts[parts.length - 1] || gid;
|
|
1780
|
+
} catch {
|
|
1781
|
+
return gid;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
function useProductUrl(otherQuery) {
|
|
1785
|
+
const { routerAdapter } = useShopify();
|
|
1786
|
+
return react.useCallback(
|
|
1787
|
+
({ product, variant }) => {
|
|
1788
|
+
if (!product) return "";
|
|
1789
|
+
const queryParams = new URLSearchParams();
|
|
1790
|
+
if (variant?.id) {
|
|
1791
|
+
const variantId = decodeShopifyId2(variant.id);
|
|
1792
|
+
if (variantId) {
|
|
1793
|
+
queryParams.set("variant", variantId);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
if (otherQuery) {
|
|
1797
|
+
Object.entries(otherQuery).forEach(([key, value]) => {
|
|
1798
|
+
queryParams.set(key, value);
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
const queryString = queryParams.toString();
|
|
1802
|
+
const path = `/products/${product.handle}${queryString ? `?${queryString}` : ""}`;
|
|
1803
|
+
if (routerAdapter?.getLocalizedPath) {
|
|
1804
|
+
return routerAdapter.getLocalizedPath(path);
|
|
1805
|
+
}
|
|
1806
|
+
return path;
|
|
1807
|
+
},
|
|
1808
|
+
[routerAdapter, otherQuery]
|
|
1809
|
+
);
|
|
1810
|
+
}
|
|
1811
|
+
function decodeShopifyId3(gid) {
|
|
1812
|
+
try {
|
|
1813
|
+
const parts = gid.split("/");
|
|
1814
|
+
return parts[parts.length - 1] || gid;
|
|
1815
|
+
} catch {
|
|
1816
|
+
return gid;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
function useUpdateVariantQuery(variant) {
|
|
1820
|
+
react.useEffect(() => {
|
|
1821
|
+
if (!variant || typeof window === "undefined") {
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
1825
|
+
const currentVariantId = searchParams.get("variant");
|
|
1826
|
+
const newVariantId = decodeShopifyId3(variant.id);
|
|
1827
|
+
if (newVariantId && currentVariantId !== newVariantId) {
|
|
1828
|
+
searchParams.set("variant", newVariantId);
|
|
1829
|
+
const newUrl = `${window.location.pathname}?${searchParams.toString()}${window.location.hash}`;
|
|
1830
|
+
window.history.replaceState({}, "", newUrl);
|
|
1831
|
+
}
|
|
1832
|
+
}, [variant]);
|
|
1833
|
+
}
|
|
1834
|
+
function getVariantMediaList({
|
|
1835
|
+
product,
|
|
1836
|
+
variant
|
|
1837
|
+
}) {
|
|
1838
|
+
if (variant.image?.url) {
|
|
1839
|
+
const variantMediaId = variant.image.url;
|
|
1840
|
+
const variantMedia = product.media.filter((media) => {
|
|
1841
|
+
if (media.mediaContentType === "IMAGE" && media.previewImage) {
|
|
1842
|
+
return media.previewImage?.url === variantMediaId;
|
|
1843
|
+
}
|
|
1844
|
+
return false;
|
|
1845
|
+
});
|
|
1846
|
+
if (variantMedia.length > 0) {
|
|
1847
|
+
const otherMedia = product.media.filter((media) => {
|
|
1848
|
+
if (media.mediaContentType === "IMAGE" && media.previewImage) {
|
|
1849
|
+
return media.previewImage.url !== variantMediaId;
|
|
1850
|
+
}
|
|
1851
|
+
return true;
|
|
1852
|
+
});
|
|
1853
|
+
return [...variantMedia, ...otherMedia];
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
return product.media;
|
|
1857
|
+
}
|
|
1858
|
+
function useVariantMedia({
|
|
1859
|
+
product,
|
|
1860
|
+
variant
|
|
1861
|
+
}) {
|
|
1862
|
+
const [imageList, setImageList] = react.useState([]);
|
|
1863
|
+
const [sceneList, setSceneList] = react.useState([]);
|
|
1864
|
+
const [videoList, setVideoList] = react.useState([]);
|
|
1865
|
+
react.useEffect(() => {
|
|
1866
|
+
if (!product || !variant) {
|
|
1867
|
+
setImageList([]);
|
|
1868
|
+
setSceneList([]);
|
|
1869
|
+
setVideoList([]);
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
const mediaList = getVariantMediaList({ product, variant });
|
|
1873
|
+
const images = mediaList.filter((media) => media.mediaContentType === "IMAGE");
|
|
1874
|
+
const videos = mediaList.filter(
|
|
1875
|
+
(media) => media.mediaContentType === "VIDEO" || media.mediaContentType === "EXTERNAL_VIDEO"
|
|
1876
|
+
);
|
|
1877
|
+
setImageList(images.length > 0 && images[0] ? [images[0]] : []);
|
|
1878
|
+
setSceneList(images.length > 1 ? images.slice(1) : []);
|
|
1879
|
+
setVideoList(videos);
|
|
1880
|
+
}, [product, variant]);
|
|
1881
|
+
return {
|
|
1882
|
+
productList: imageList,
|
|
1883
|
+
sceneList,
|
|
1884
|
+
videoList
|
|
1885
|
+
};
|
|
1886
|
+
}
|
|
1887
|
+
function useCollection(options = {}) {
|
|
1888
|
+
const { client, locale } = useShopify();
|
|
1889
|
+
const { handle, metafieldIdentifiers, ...swrOptions } = options;
|
|
1890
|
+
return useSWR__default.default(
|
|
1891
|
+
handle ? ["collection", locale, handle, metafieldIdentifiers] : null,
|
|
1892
|
+
() => shopifySdk.getCollection(client, {
|
|
1893
|
+
handle,
|
|
1894
|
+
locale,
|
|
1895
|
+
metafieldIdentifiers
|
|
1896
|
+
}),
|
|
1897
|
+
swrOptions
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
function useAllCollections(options = {}) {
|
|
1901
|
+
const { client, locale } = useShopify();
|
|
1902
|
+
const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
|
|
1903
|
+
return useSWR__default.default(
|
|
1904
|
+
["all-collections", locale, first, query, sortKey, reverse, metafieldIdentifiers],
|
|
1905
|
+
() => shopifySdk.getAllCollections(client, {
|
|
1906
|
+
locale,
|
|
1907
|
+
first,
|
|
1908
|
+
query,
|
|
1909
|
+
sortKey,
|
|
1910
|
+
reverse,
|
|
1911
|
+
metafieldIdentifiers
|
|
1912
|
+
}),
|
|
1913
|
+
swrOptions
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1916
|
+
function useCollections(options = {}) {
|
|
1917
|
+
const { client, locale } = useShopify();
|
|
1918
|
+
const { first, after, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
|
|
1919
|
+
return useSWR__default.default(
|
|
1920
|
+
["collections", locale, first, after, query, sortKey, reverse, metafieldIdentifiers],
|
|
1921
|
+
() => shopifySdk.getCollections(client, {
|
|
1922
|
+
locale,
|
|
1923
|
+
first,
|
|
1924
|
+
after,
|
|
1925
|
+
query,
|
|
1926
|
+
sortKey,
|
|
1927
|
+
reverse,
|
|
1928
|
+
metafieldIdentifiers
|
|
1929
|
+
}),
|
|
1930
|
+
swrOptions
|
|
1931
|
+
);
|
|
1932
|
+
}
|
|
1933
|
+
function useBlog(options = {}) {
|
|
1934
|
+
const { client, locale } = useShopify();
|
|
1935
|
+
const { handle, metafieldIdentifiers, ...swrOptions } = options;
|
|
1936
|
+
return useSWR__default.default(
|
|
1937
|
+
handle ? ["blog", locale, handle, metafieldIdentifiers] : null,
|
|
1938
|
+
() => shopifySdk.getBlog(client, { handle, locale, metafieldIdentifiers }),
|
|
1939
|
+
swrOptions
|
|
1940
|
+
);
|
|
1941
|
+
}
|
|
1942
|
+
function useAllBlogs(options = {}) {
|
|
1943
|
+
const { client, locale } = useShopify();
|
|
1944
|
+
const { first, query, metafieldIdentifiers, ...swrOptions } = options;
|
|
1945
|
+
return useSWR__default.default(
|
|
1946
|
+
["all-blogs", locale, first, query, metafieldIdentifiers],
|
|
1947
|
+
() => shopifySdk.getAllBlogs(client, {
|
|
1948
|
+
locale,
|
|
1949
|
+
first,
|
|
1950
|
+
query,
|
|
1951
|
+
metafieldIdentifiers
|
|
1952
|
+
}),
|
|
1953
|
+
swrOptions
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1956
|
+
function useArticle(options = {}) {
|
|
1957
|
+
const { client, locale } = useShopify();
|
|
1958
|
+
const { blogHandle, articleHandle, metafieldIdentifiers, ...swrOptions } = options;
|
|
1959
|
+
return useSWR__default.default(
|
|
1960
|
+
blogHandle && articleHandle ? ["article", locale, blogHandle, articleHandle, metafieldIdentifiers] : null,
|
|
1961
|
+
() => shopifySdk.getArticle(client, {
|
|
1962
|
+
blogHandle,
|
|
1963
|
+
articleHandle,
|
|
1964
|
+
locale,
|
|
1965
|
+
metafieldIdentifiers
|
|
1966
|
+
}),
|
|
1967
|
+
swrOptions
|
|
1968
|
+
);
|
|
1969
|
+
}
|
|
1970
|
+
function useArticles(options = {}) {
|
|
1971
|
+
const { client, locale } = useShopify();
|
|
1972
|
+
const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
|
|
1973
|
+
return useSWR__default.default(
|
|
1974
|
+
["articles", locale, first, query, sortKey, reverse, metafieldIdentifiers],
|
|
1975
|
+
() => shopifySdk.getArticles(client, {
|
|
1976
|
+
locale,
|
|
1977
|
+
first,
|
|
1978
|
+
query,
|
|
1979
|
+
sortKey,
|
|
1980
|
+
reverse,
|
|
1981
|
+
metafieldIdentifiers
|
|
1982
|
+
}),
|
|
1983
|
+
swrOptions
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
function useArticlesInBlog(options = {}) {
|
|
1987
|
+
const { client, locale } = useShopify();
|
|
1988
|
+
const { blogHandle, first, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
|
|
1989
|
+
return useSWR__default.default(
|
|
1990
|
+
blogHandle ? ["articles-in-blog", locale, blogHandle, first, sortKey, reverse, metafieldIdentifiers] : null,
|
|
1991
|
+
() => shopifySdk.getArticlesInBlog(client, {
|
|
1992
|
+
blogHandle,
|
|
1993
|
+
locale,
|
|
1994
|
+
first,
|
|
1995
|
+
sortKey,
|
|
1996
|
+
reverse,
|
|
1997
|
+
metafieldIdentifiers
|
|
1998
|
+
}),
|
|
1999
|
+
swrOptions
|
|
2000
|
+
);
|
|
2001
|
+
}
|
|
2002
|
+
async function performSearch(client, locale, searchQuery, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"]) {
|
|
2003
|
+
if (!searchQuery) {
|
|
2004
|
+
return void 0;
|
|
2005
|
+
}
|
|
2006
|
+
const query = (
|
|
2007
|
+
/* GraphQL */
|
|
2008
|
+
`
|
|
2009
|
+
query search($query: String!, $first: Int!, $types: [SearchType!])
|
|
2010
|
+
@inContext(language: $language) {
|
|
2011
|
+
search(query: $query, first: $first, types: $types, unavailableProducts: HIDE) {
|
|
2012
|
+
totalCount
|
|
2013
|
+
edges {
|
|
2014
|
+
node {
|
|
2015
|
+
... on Article {
|
|
2016
|
+
__typename
|
|
2017
|
+
id
|
|
2018
|
+
handle
|
|
2019
|
+
title
|
|
2020
|
+
excerpt
|
|
2021
|
+
image {
|
|
2022
|
+
url
|
|
2023
|
+
altText
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
... on Page {
|
|
2027
|
+
__typename
|
|
2028
|
+
id
|
|
2029
|
+
handle
|
|
2030
|
+
title
|
|
2031
|
+
}
|
|
2032
|
+
... on Product {
|
|
2033
|
+
__typename
|
|
2034
|
+
id
|
|
2035
|
+
handle
|
|
2036
|
+
title
|
|
2037
|
+
description
|
|
2038
|
+
featuredImage {
|
|
2039
|
+
url
|
|
2040
|
+
altText
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
pageInfo {
|
|
2046
|
+
hasNextPage
|
|
2047
|
+
endCursor
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
`
|
|
2052
|
+
);
|
|
2053
|
+
const data = await client.query(query, {
|
|
2054
|
+
query: searchQuery,
|
|
2055
|
+
first,
|
|
2056
|
+
types
|
|
2057
|
+
});
|
|
2058
|
+
if (!data || !data.search) {
|
|
2059
|
+
return void 0;
|
|
2060
|
+
}
|
|
2061
|
+
const items = data.search.edges?.map((edge) => {
|
|
2062
|
+
const node = edge.node;
|
|
2063
|
+
const item = {
|
|
2064
|
+
type: node.__typename.toUpperCase(),
|
|
2065
|
+
id: node.id,
|
|
2066
|
+
handle: node.handle,
|
|
2067
|
+
title: node.title
|
|
2068
|
+
};
|
|
2069
|
+
if (node.__typename === "Product") {
|
|
2070
|
+
item.description = node.description;
|
|
2071
|
+
item.image = node.featuredImage ? {
|
|
2072
|
+
url: node.featuredImage.url,
|
|
2073
|
+
altText: node.featuredImage.altText
|
|
2074
|
+
} : void 0;
|
|
2075
|
+
} else if (node.__typename === "Article") {
|
|
2076
|
+
item.description = node.excerpt;
|
|
2077
|
+
item.image = node.image ? {
|
|
2078
|
+
url: node.image.url,
|
|
2079
|
+
altText: node.image.altText
|
|
2080
|
+
} : void 0;
|
|
2081
|
+
}
|
|
2082
|
+
return item;
|
|
2083
|
+
}) || [];
|
|
2084
|
+
return {
|
|
2085
|
+
items,
|
|
2086
|
+
totalCount: data.search.totalCount || 0,
|
|
2087
|
+
pageInfo: data.search.pageInfo
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
function useSearch(options = {}) {
|
|
2091
|
+
const { client, locale } = useShopify();
|
|
2092
|
+
const { query, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"], ...swrOptions } = options;
|
|
2093
|
+
return useSWR__default.default(
|
|
2094
|
+
query ? ["search", locale, query, first, types] : null,
|
|
2095
|
+
() => performSearch(client, locale, query, first, types),
|
|
2096
|
+
swrOptions
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
async function getSiteInfo(client, locale, metafieldIdentifiers) {
|
|
2100
|
+
const hasMetafields = metafieldIdentifiers && metafieldIdentifiers.length > 0;
|
|
2101
|
+
const query = (
|
|
2102
|
+
/* GraphQL */
|
|
2103
|
+
`
|
|
2104
|
+
query getSiteInfo(
|
|
2105
|
+
${hasMetafields ? "$shopMetafieldIdentifiers: [HasMetafieldsIdentifier!]!" : ""}
|
|
2106
|
+
) @inContext(language: $language) {
|
|
2107
|
+
shop {
|
|
2108
|
+
name
|
|
2109
|
+
description
|
|
2110
|
+
primaryDomain {
|
|
2111
|
+
url
|
|
2112
|
+
host
|
|
2113
|
+
}
|
|
2114
|
+
brand {
|
|
2115
|
+
logo {
|
|
2116
|
+
image {
|
|
2117
|
+
url
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
colors {
|
|
2121
|
+
primary {
|
|
2122
|
+
background
|
|
2123
|
+
}
|
|
2124
|
+
secondary {
|
|
2125
|
+
background
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
${hasMetafields ? "metafields(identifiers: $shopMetafieldIdentifiers) { key value }" : ""}
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
`
|
|
2133
|
+
);
|
|
2134
|
+
const variables = {};
|
|
2135
|
+
if (hasMetafields) {
|
|
2136
|
+
variables.shopMetafieldIdentifiers = metafieldIdentifiers;
|
|
2137
|
+
}
|
|
2138
|
+
const data = await client.query(query, variables);
|
|
2139
|
+
if (!data || !data.shop) {
|
|
2140
|
+
return void 0;
|
|
2141
|
+
}
|
|
2142
|
+
const shop = data.shop;
|
|
2143
|
+
const metafields = shop.metafields?.reduce((acc, mf) => {
|
|
2144
|
+
if (mf && mf.key) {
|
|
2145
|
+
acc[mf.key] = mf.value;
|
|
2146
|
+
}
|
|
2147
|
+
return acc;
|
|
2148
|
+
}, {});
|
|
2149
|
+
return {
|
|
2150
|
+
name: shop.name,
|
|
2151
|
+
description: shop.description,
|
|
2152
|
+
primaryDomain: shop.primaryDomain,
|
|
2153
|
+
brand: shop.brand ? {
|
|
2154
|
+
logo: shop.brand.logo,
|
|
2155
|
+
colors: shop.brand.colors ? {
|
|
2156
|
+
primary: shop.brand.colors.primary?.background,
|
|
2157
|
+
secondary: shop.brand.colors.secondary?.background
|
|
2158
|
+
} : void 0
|
|
2159
|
+
} : void 0,
|
|
2160
|
+
metafields
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
function useSite(options = {}) {
|
|
2164
|
+
const { client, locale } = useShopify();
|
|
2165
|
+
const { metafieldIdentifiers, ...swrOptions } = options;
|
|
2166
|
+
return useSWR__default.default(
|
|
2167
|
+
["site", locale, metafieldIdentifiers],
|
|
2168
|
+
() => getSiteInfo(client, locale, metafieldIdentifiers),
|
|
2169
|
+
swrOptions
|
|
2170
|
+
);
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
// src/hooks/member/plus/types.ts
|
|
2174
|
+
var PLUS_MEMBER_TYPE = /* @__PURE__ */ ((PLUS_MEMBER_TYPE2) => {
|
|
2175
|
+
PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["FREE"] = 0] = "FREE";
|
|
2176
|
+
PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["MONTHLY"] = 1] = "MONTHLY";
|
|
2177
|
+
PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["ANNUAL"] = 2] = "ANNUAL";
|
|
2178
|
+
return PLUS_MEMBER_TYPE2;
|
|
2179
|
+
})(PLUS_MEMBER_TYPE || {});
|
|
2180
|
+
var PlusMemberMode = /* @__PURE__ */ ((PlusMemberMode2) => {
|
|
2181
|
+
PlusMemberMode2["MONTHLY"] = "monthly";
|
|
2182
|
+
PlusMemberMode2["ANNUAL"] = "annual";
|
|
2183
|
+
return PlusMemberMode2;
|
|
2184
|
+
})(PlusMemberMode || {});
|
|
2185
|
+
var DeliveryPlusType = /* @__PURE__ */ ((DeliveryPlusType2) => {
|
|
2186
|
+
DeliveryPlusType2["FREE"] = "free";
|
|
2187
|
+
DeliveryPlusType2["MONTHLY"] = "monthly";
|
|
2188
|
+
DeliveryPlusType2["ANNUAL"] = "annual";
|
|
2189
|
+
return DeliveryPlusType2;
|
|
2190
|
+
})(DeliveryPlusType || {});
|
|
2191
|
+
var ShippingMethodMode = /* @__PURE__ */ ((ShippingMethodMode2) => {
|
|
2192
|
+
ShippingMethodMode2["FREE"] = "free";
|
|
2193
|
+
ShippingMethodMode2["TDD"] = "tdd";
|
|
2194
|
+
ShippingMethodMode2["NDD"] = "ndd";
|
|
2195
|
+
return ShippingMethodMode2;
|
|
2196
|
+
})(ShippingMethodMode || {});
|
|
2197
|
+
var createInitialValue = () => ({
|
|
2198
|
+
zipCode: "",
|
|
2199
|
+
plusMemberMetafields: {},
|
|
2200
|
+
setZipCode: () => {
|
|
2201
|
+
},
|
|
2202
|
+
allowNextDayDelivery: false,
|
|
2203
|
+
setAllowNextDayDelivery: () => {
|
|
2204
|
+
},
|
|
2205
|
+
allowThirdDayDelivery: false,
|
|
2206
|
+
setAllowThirdDayDelivery: () => {
|
|
2207
|
+
},
|
|
2208
|
+
selectedPlusMemberMode: "free",
|
|
2209
|
+
setSelectedPlusMemberMode: () => {
|
|
2210
|
+
},
|
|
2211
|
+
showAreaCheckModal: false,
|
|
2212
|
+
setShowAreaCheckModal: () => {
|
|
2213
|
+
},
|
|
2214
|
+
selectedShippingMethod: void 0,
|
|
2215
|
+
setSelectedShippingMethod: () => {
|
|
2216
|
+
},
|
|
2217
|
+
showTip: false,
|
|
2218
|
+
setShowTip: () => {
|
|
2219
|
+
},
|
|
2220
|
+
showMoreShippingMethod: false,
|
|
2221
|
+
setShowMoreShippingMethod: () => {
|
|
2222
|
+
},
|
|
2223
|
+
variant: {},
|
|
2224
|
+
product: {},
|
|
2225
|
+
shippingMethodsContext: {
|
|
2226
|
+
freeShippingMethods: [],
|
|
2227
|
+
paymentShippingMethods: [],
|
|
2228
|
+
nddOverweight: false,
|
|
2229
|
+
tddOverweight: false
|
|
2230
|
+
},
|
|
2231
|
+
selectedPlusMemberProduct: null,
|
|
2232
|
+
plusMemberProducts: [],
|
|
2233
|
+
showPlusMemberBenefit: false,
|
|
2234
|
+
setShowPlusMemberBenefit: () => {
|
|
2235
|
+
},
|
|
2236
|
+
deleteMarginBottom: false,
|
|
2237
|
+
setDeleteMarginBottom: () => {
|
|
2238
|
+
},
|
|
2239
|
+
profile: void 0,
|
|
2240
|
+
locale: void 0
|
|
2241
|
+
});
|
|
2242
|
+
var PlusMemberContext = react.createContext(createInitialValue());
|
|
2243
|
+
function usePlusMemberContext() {
|
|
2244
|
+
return react.useContext(PlusMemberContext);
|
|
2245
|
+
}
|
|
2246
|
+
function usePlusMonthlyProductVariant() {
|
|
2247
|
+
const { plusMemberProducts, plusMemberMetafields } = usePlusMemberContext();
|
|
2248
|
+
const plusMonthly = plusMemberMetafields?.plus_monthly_product;
|
|
2249
|
+
const plusMonthlyProductVariant = react.useMemo(() => {
|
|
2250
|
+
const product = plusMemberProducts?.find(
|
|
2251
|
+
(item) => item?.handle === plusMonthly?.handle
|
|
2252
|
+
);
|
|
2253
|
+
const productVariant = product?.variants?.find(
|
|
2254
|
+
(item) => item.sku === plusMonthly?.sku
|
|
2255
|
+
);
|
|
2256
|
+
return productVariant;
|
|
2257
|
+
}, [plusMemberProducts, plusMonthly]);
|
|
2258
|
+
return plusMonthlyProductVariant;
|
|
2259
|
+
}
|
|
2260
|
+
function usePlusAnnualProductVariant() {
|
|
2261
|
+
const { plusMemberProducts, plusMemberMetafields } = usePlusMemberContext();
|
|
2262
|
+
const plusAnnual = plusMemberMetafields?.plus_annual_product;
|
|
2263
|
+
const plusAnnualProductVariant = react.useMemo(() => {
|
|
2264
|
+
const product = plusMemberProducts?.find(
|
|
2265
|
+
(item) => item?.handle === plusAnnual?.handle
|
|
2266
|
+
);
|
|
2267
|
+
const productVariant = product?.variants?.find(
|
|
2268
|
+
(item) => item.sku === plusAnnual?.sku
|
|
2269
|
+
);
|
|
2270
|
+
return productVariant;
|
|
2271
|
+
}, [plusMemberProducts, plusAnnual]);
|
|
2272
|
+
return plusAnnualProductVariant;
|
|
2273
|
+
}
|
|
2274
|
+
function useShippingMethods(options) {
|
|
2275
|
+
const {
|
|
2276
|
+
variant,
|
|
2277
|
+
plusMemberMetafields,
|
|
2278
|
+
selectedPlusMemberMode,
|
|
2279
|
+
isPlus = false,
|
|
2280
|
+
nddCoupon,
|
|
2281
|
+
tddCoupon
|
|
2282
|
+
} = options;
|
|
2283
|
+
const { plus_shipping, shippingMethod } = plusMemberMetafields || {};
|
|
2284
|
+
const nddOverweight = react.useMemo(() => {
|
|
2285
|
+
return (variant?.weight || 0) > (shippingMethod?.overWeight_ndd || Infinity);
|
|
2286
|
+
}, [shippingMethod?.overWeight_ndd, variant?.weight]);
|
|
2287
|
+
const tddOverweight = react.useMemo(() => {
|
|
2288
|
+
return (variant?.weight || 0) > (shippingMethod?.overWeight_tdd || Infinity);
|
|
2289
|
+
}, [shippingMethod?.overWeight_tdd, variant?.weight]);
|
|
2290
|
+
const paymentShippingMethods = react.useMemo(() => {
|
|
2291
|
+
const weight = variant?.weight || 0;
|
|
2292
|
+
const methods = plus_shipping?.shipping_methods?.filter(
|
|
2293
|
+
({ weight_low, weight_high, __mode, __plus }) => {
|
|
2294
|
+
const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
|
|
2295
|
+
return __mode !== "free" /* FREE */ && !__plus && fitWeight;
|
|
2296
|
+
}
|
|
2297
|
+
) || [];
|
|
2298
|
+
return methods.map((method) => {
|
|
2299
|
+
let disabled = false;
|
|
2300
|
+
const selectedFreeMember = selectedPlusMemberMode === "free";
|
|
2301
|
+
if (method.__mode === "ndd" /* NDD */) {
|
|
2302
|
+
disabled = selectedFreeMember || nddOverweight;
|
|
2303
|
+
} else if (method.__mode === "tdd" /* TDD */) {
|
|
2304
|
+
disabled = selectedFreeMember || tddOverweight;
|
|
2305
|
+
}
|
|
2306
|
+
return {
|
|
2307
|
+
...method,
|
|
2308
|
+
id: method.__mode + method.__code,
|
|
2309
|
+
useCoupon: false,
|
|
2310
|
+
subtitle: plus_shipping?.directly || "",
|
|
2311
|
+
disabled
|
|
2312
|
+
};
|
|
2313
|
+
});
|
|
2314
|
+
}, [
|
|
2315
|
+
nddOverweight,
|
|
2316
|
+
plus_shipping?.directly,
|
|
2317
|
+
plus_shipping?.shipping_methods,
|
|
2318
|
+
selectedPlusMemberMode,
|
|
2319
|
+
tddOverweight,
|
|
2320
|
+
variant?.weight
|
|
2321
|
+
]);
|
|
2322
|
+
const nddPrice = react.useMemo(() => {
|
|
2323
|
+
const weight = variant?.weight || 0;
|
|
2324
|
+
const nddMethod = paymentShippingMethods.find(
|
|
2325
|
+
({ __mode, weight_high, weight_low }) => {
|
|
2326
|
+
const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
|
|
2327
|
+
return __mode === "ndd" && fitWeight;
|
|
2328
|
+
}
|
|
2329
|
+
);
|
|
2330
|
+
return nddMethod?.price || 0;
|
|
2331
|
+
}, [variant?.weight, paymentShippingMethods]);
|
|
2332
|
+
const tddPrice = react.useMemo(() => {
|
|
2333
|
+
const weight = variant?.weight || 0;
|
|
2334
|
+
const tddMethod = paymentShippingMethods.find(
|
|
2335
|
+
({ __mode, weight_high, weight_low }) => {
|
|
2336
|
+
const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
|
|
2337
|
+
return __mode === "tdd" && fitWeight;
|
|
2338
|
+
}
|
|
2339
|
+
);
|
|
2340
|
+
return tddMethod?.price || 0;
|
|
2341
|
+
}, [variant?.weight, paymentShippingMethods]);
|
|
2342
|
+
const freeShippingMethods = react.useMemo(() => {
|
|
2343
|
+
const weight = variant?.weight || 0;
|
|
2344
|
+
let methods = plus_shipping?.shipping_methods?.filter(
|
|
2345
|
+
({ __mode, __plus, weight_low, weight_high }) => {
|
|
2346
|
+
if (__mode === "free" /* FREE */) {
|
|
2347
|
+
return true;
|
|
2348
|
+
}
|
|
2349
|
+
if (isPlus) {
|
|
2350
|
+
const hasCoupon = isPlus && __mode === "ndd" /* NDD */ && nddCoupon || isPlus && __mode === "tdd" /* TDD */ && (tddCoupon || nddCoupon);
|
|
2351
|
+
const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
|
|
2352
|
+
return hasCoupon && fitWeight && !__plus;
|
|
2353
|
+
} else {
|
|
2354
|
+
return __plus;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
) || [];
|
|
2358
|
+
if (isPlus) {
|
|
2359
|
+
methods = methods.sort((a, b) => {
|
|
2360
|
+
if (b.__mode === "free" /* FREE */) return -1;
|
|
2361
|
+
return 0;
|
|
2362
|
+
});
|
|
2363
|
+
}
|
|
2364
|
+
return methods.map((method) => {
|
|
2365
|
+
let price = 0;
|
|
2366
|
+
let coupon;
|
|
2367
|
+
let disabled;
|
|
2368
|
+
if (method.__mode !== "free" /* FREE */) {
|
|
2369
|
+
switch (method.__mode) {
|
|
2370
|
+
case "tdd":
|
|
2371
|
+
price = tddPrice;
|
|
2372
|
+
coupon = tddCoupon || nddCoupon;
|
|
2373
|
+
break;
|
|
2374
|
+
case "ndd":
|
|
2375
|
+
price = nddPrice;
|
|
2376
|
+
coupon = nddCoupon;
|
|
2377
|
+
break;
|
|
2378
|
+
}
|
|
2379
|
+
disabled = selectedPlusMemberMode === "free";
|
|
2380
|
+
if (method.__mode === "ndd" /* NDD */) {
|
|
2381
|
+
disabled = disabled || nddOverweight;
|
|
2382
|
+
} else if (method.__mode === "tdd" /* TDD */) {
|
|
2383
|
+
disabled = disabled || tddOverweight;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
return {
|
|
2387
|
+
...method,
|
|
2388
|
+
id: method.__mode + method.__code,
|
|
2389
|
+
useCoupon: true,
|
|
2390
|
+
disabled,
|
|
2391
|
+
coupon,
|
|
2392
|
+
price
|
|
2393
|
+
};
|
|
2394
|
+
});
|
|
2395
|
+
}, [
|
|
2396
|
+
variant?.weight,
|
|
2397
|
+
plus_shipping?.shipping_methods,
|
|
2398
|
+
isPlus,
|
|
2399
|
+
nddCoupon,
|
|
2400
|
+
tddCoupon,
|
|
2401
|
+
selectedPlusMemberMode,
|
|
2402
|
+
tddPrice,
|
|
2403
|
+
nddPrice,
|
|
2404
|
+
nddOverweight,
|
|
2405
|
+
tddOverweight
|
|
2406
|
+
]);
|
|
2407
|
+
return {
|
|
2408
|
+
freeShippingMethods,
|
|
2409
|
+
paymentShippingMethods,
|
|
2410
|
+
nddOverweight,
|
|
2411
|
+
tddOverweight
|
|
2412
|
+
};
|
|
2413
|
+
}
|
|
2414
|
+
function useShippingMethodAvailableCheck() {
|
|
2415
|
+
const {
|
|
2416
|
+
zipCode,
|
|
2417
|
+
allowNextDayDelivery,
|
|
2418
|
+
allowThirdDayDelivery,
|
|
2419
|
+
selectedShippingMethod,
|
|
2420
|
+
setSelectedShippingMethod,
|
|
2421
|
+
setShowTip,
|
|
2422
|
+
shippingMethodsContext
|
|
2423
|
+
} = usePlusMemberContext();
|
|
2424
|
+
react.useEffect(() => {
|
|
2425
|
+
const freeShippingMethod = shippingMethodsContext.freeShippingMethods[0];
|
|
2426
|
+
const standardShippingMethod = shippingMethodsContext.freeShippingMethods?.find(
|
|
2427
|
+
(item) => item.__mode === "free" /* FREE */
|
|
2428
|
+
);
|
|
2429
|
+
const freeTDD = shippingMethodsContext.freeShippingMethods.find(
|
|
2430
|
+
(item) => item.__mode === "tdd" /* TDD */
|
|
2431
|
+
);
|
|
2432
|
+
const paymentTDD = shippingMethodsContext.paymentShippingMethods.find(
|
|
2433
|
+
(item) => item.__mode === "tdd" /* TDD */
|
|
2434
|
+
);
|
|
2435
|
+
if (zipCode) {
|
|
2436
|
+
console.log(
|
|
2437
|
+
"allowNextDayDelivery, allowThirdDayDelivery:",
|
|
2438
|
+
allowNextDayDelivery,
|
|
2439
|
+
allowThirdDayDelivery
|
|
2440
|
+
);
|
|
2441
|
+
if (!allowNextDayDelivery && !allowThirdDayDelivery) {
|
|
2442
|
+
setShowTip(true);
|
|
2443
|
+
setSelectedShippingMethod(standardShippingMethod);
|
|
2444
|
+
} else {
|
|
2445
|
+
if (selectedShippingMethod?.__mode === "ndd" /* NDD */ && !allowNextDayDelivery) {
|
|
2446
|
+
setShowTip(true);
|
|
2447
|
+
if (allowThirdDayDelivery) {
|
|
2448
|
+
if (selectedShippingMethod.useCoupon) {
|
|
2449
|
+
const method = freeTDD || freeShippingMethod;
|
|
2450
|
+
if (method) setSelectedShippingMethod(method);
|
|
2451
|
+
} else {
|
|
2452
|
+
const method = paymentTDD || freeShippingMethod;
|
|
2453
|
+
if (method) setSelectedShippingMethod(method);
|
|
2454
|
+
}
|
|
2455
|
+
} else {
|
|
2456
|
+
if (freeShippingMethod) setSelectedShippingMethod(freeShippingMethod);
|
|
2457
|
+
}
|
|
2458
|
+
} else if (
|
|
2459
|
+
// TDD 无法使用
|
|
2460
|
+
selectedShippingMethod?.__mode === "tdd" /* TDD */ && !allowThirdDayDelivery
|
|
2461
|
+
) {
|
|
2462
|
+
setShowTip(true);
|
|
2463
|
+
if (freeShippingMethod) setSelectedShippingMethod(freeShippingMethod);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
}, [
|
|
2468
|
+
allowNextDayDelivery,
|
|
2469
|
+
allowThirdDayDelivery,
|
|
2470
|
+
zipCode,
|
|
2471
|
+
shippingMethodsContext,
|
|
2472
|
+
selectedShippingMethod,
|
|
2473
|
+
setSelectedShippingMethod,
|
|
2474
|
+
setShowTip
|
|
2475
|
+
]);
|
|
2476
|
+
}
|
|
2477
|
+
var useReplaceCartPlusMember = () => {
|
|
2478
|
+
const { plusMemberMetafields, selectedPlusMemberMode } = usePlusMemberContext();
|
|
2479
|
+
const { trigger: removeCartLines2 } = useRemoveCartLines();
|
|
2480
|
+
const { cart } = useCartContext();
|
|
2481
|
+
const plusMonthly = plusMemberMetafields?.plus_monthly_product;
|
|
2482
|
+
const plusAnnual = plusMemberMetafields?.plus_annual_product;
|
|
2483
|
+
const handler = react.useCallback(async () => {
|
|
2484
|
+
const plusMonthlyInCart = cart?.lineItems.find(
|
|
2485
|
+
(item) => item.variant?.sku === plusMonthly?.sku
|
|
2486
|
+
);
|
|
2487
|
+
const plusAnnualInCart = cart?.lineItems.find(
|
|
2488
|
+
(item) => item.variant?.sku === plusAnnual?.sku
|
|
2489
|
+
);
|
|
2490
|
+
if (selectedPlusMemberMode === "annual" /* ANNUAL */ && plusMonthlyInCart) {
|
|
2491
|
+
await removeCartLines2({
|
|
2492
|
+
lineIds: [plusMonthlyInCart.id]
|
|
2493
|
+
});
|
|
2494
|
+
} else if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && plusAnnualInCart) {
|
|
2495
|
+
await removeCartLines2({
|
|
2496
|
+
lineIds: [plusAnnualInCart.id]
|
|
2497
|
+
});
|
|
2498
|
+
}
|
|
2499
|
+
}, [
|
|
2500
|
+
cart?.lineItems,
|
|
2501
|
+
selectedPlusMemberMode,
|
|
2502
|
+
plusMonthly?.sku,
|
|
2503
|
+
plusAnnual?.sku,
|
|
2504
|
+
removeCartLines2
|
|
2505
|
+
]);
|
|
2506
|
+
return handler;
|
|
2507
|
+
};
|
|
2508
|
+
var usePlusMemberDeliveryCodes = ({
|
|
2509
|
+
deliveryData
|
|
2510
|
+
}) => {
|
|
2511
|
+
return react.useMemo(
|
|
2512
|
+
() => deliveryData?.deliveryCustomData?.discount_code,
|
|
2513
|
+
[deliveryData]
|
|
2514
|
+
);
|
|
2515
|
+
};
|
|
2516
|
+
var usePlusMemberItemCustomAttributes = ({
|
|
2517
|
+
deliveryData
|
|
2518
|
+
}) => {
|
|
2519
|
+
const { deliveryCustomData } = deliveryData || {};
|
|
2520
|
+
return react.useMemo(() => {
|
|
2521
|
+
const itemCustomAttributes = [];
|
|
2522
|
+
if (deliveryCustomData?.is_presale) {
|
|
2523
|
+
itemCustomAttributes.push({
|
|
2524
|
+
key: "_is_presale",
|
|
2525
|
+
value: "true"
|
|
2526
|
+
});
|
|
2527
|
+
}
|
|
2528
|
+
return itemCustomAttributes;
|
|
2529
|
+
}, [deliveryCustomData]);
|
|
2530
|
+
};
|
|
2531
|
+
var usePlusMemberCheckoutCustomAttributes = ({
|
|
2532
|
+
deliveryData,
|
|
2533
|
+
product,
|
|
2534
|
+
variant,
|
|
2535
|
+
customer,
|
|
2536
|
+
isShowShippingBenefits
|
|
2537
|
+
}) => {
|
|
2538
|
+
const { deliveryCustomData } = deliveryData || {};
|
|
2539
|
+
const { profile } = usePlusMemberContext();
|
|
2540
|
+
const userType = react.useMemo(() => {
|
|
2541
|
+
const customerInfo = customer;
|
|
2542
|
+
if (!customerInfo) {
|
|
2543
|
+
return "new_user_unlogin";
|
|
2544
|
+
}
|
|
2545
|
+
if (customer) {
|
|
2546
|
+
const { orders = {} } = customer;
|
|
2547
|
+
const edgesLength = orders?.edges?.length;
|
|
2548
|
+
if (edgesLength === 1) {
|
|
2549
|
+
return "old_user_orders_once";
|
|
2550
|
+
} else if (edgesLength && edgesLength > 1) {
|
|
2551
|
+
return "old_user_orders_twice";
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
return "new_user_login";
|
|
2555
|
+
}, [customer]);
|
|
2556
|
+
return react.useMemo(() => {
|
|
2557
|
+
const checkoutCustomAttributes = [
|
|
2558
|
+
{
|
|
2559
|
+
key: "_token",
|
|
2560
|
+
value: profile?.token || ""
|
|
2561
|
+
},
|
|
2562
|
+
{
|
|
2563
|
+
key: "_last_url",
|
|
2564
|
+
value: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
|
|
2565
|
+
},
|
|
2566
|
+
{
|
|
2567
|
+
key: "_user_type",
|
|
2568
|
+
value: userType
|
|
2569
|
+
}
|
|
2570
|
+
];
|
|
2571
|
+
if (profile) {
|
|
2572
|
+
checkoutCustomAttributes.push({
|
|
2573
|
+
key: "_login_user",
|
|
2574
|
+
value: "1"
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
if (deliveryCustomData) {
|
|
2578
|
+
checkoutCustomAttributes.push({
|
|
2579
|
+
key: "_checkout_delivery_custom",
|
|
2580
|
+
value: JSON.stringify({
|
|
2581
|
+
...deliveryCustomData,
|
|
2582
|
+
is_prime: profile?.isPlus
|
|
2583
|
+
})
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
if (variant?.metafields?.presell) {
|
|
2587
|
+
checkoutCustomAttributes.push({
|
|
2588
|
+
key: "_presale",
|
|
2589
|
+
value: "true"
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
if (isShowShippingBenefits && !isShowShippingBenefits({ variant, product, setting: {} })) {
|
|
2593
|
+
checkoutCustomAttributes.push({
|
|
2594
|
+
key: "_hide_shipping",
|
|
2595
|
+
value: "true"
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2598
|
+
return checkoutCustomAttributes;
|
|
2599
|
+
}, [deliveryCustomData, product, profile, userType, variant, isShowShippingBenefits]);
|
|
2600
|
+
};
|
|
2601
|
+
function useAutoRemovePlusMemberInCart({
|
|
2602
|
+
metafields,
|
|
2603
|
+
isMonthlyPlus,
|
|
2604
|
+
isAnnualPlus
|
|
2605
|
+
}) {
|
|
2606
|
+
const { plus_monthly_product, plus_annual_product } = metafields || {};
|
|
2607
|
+
const { cart } = useCartContext();
|
|
2608
|
+
const { trigger: removeCartLines2 } = useRemoveCartLines();
|
|
2609
|
+
react.useEffect(() => {
|
|
2610
|
+
if (!cart) return;
|
|
2611
|
+
const removePlusProduct = async (productType) => {
|
|
2612
|
+
if (!productType) return;
|
|
2613
|
+
const product = cart.lineItems?.find(
|
|
2614
|
+
(item) => item.product?.handle === productType?.handle && item.variant?.sku === productType?.sku
|
|
2615
|
+
);
|
|
2616
|
+
if (product) {
|
|
2617
|
+
await removeCartLines2({
|
|
2618
|
+
lineIds: [product.id]
|
|
2619
|
+
});
|
|
2620
|
+
}
|
|
2621
|
+
};
|
|
2622
|
+
if (isMonthlyPlus) {
|
|
2623
|
+
removePlusProduct(plus_monthly_product);
|
|
2624
|
+
}
|
|
2625
|
+
if (isAnnualPlus) {
|
|
2626
|
+
removePlusProduct(plus_annual_product);
|
|
2627
|
+
}
|
|
2628
|
+
}, [
|
|
2629
|
+
cart,
|
|
2630
|
+
plus_annual_product,
|
|
2631
|
+
plus_monthly_product,
|
|
2632
|
+
isAnnualPlus,
|
|
2633
|
+
isMonthlyPlus,
|
|
2634
|
+
removeCartLines2
|
|
2635
|
+
]);
|
|
2636
|
+
}
|
|
2637
|
+
var PlusMemberProvider = ({
|
|
2638
|
+
variant,
|
|
2639
|
+
product,
|
|
2640
|
+
shopCommon,
|
|
2641
|
+
metafields,
|
|
2642
|
+
initialSelectedPlusMemberMode = "free",
|
|
2643
|
+
profile,
|
|
2644
|
+
locale,
|
|
2645
|
+
children
|
|
2646
|
+
}) => {
|
|
2647
|
+
const [zipCode, setZipCode] = react.useState("");
|
|
2648
|
+
const [showTip, setShowTip] = react.useState(false);
|
|
2649
|
+
const [selectedPlusMemberMode, setSelectedPlusMemberMode] = react.useState(
|
|
2650
|
+
initialSelectedPlusMemberMode
|
|
2651
|
+
);
|
|
2652
|
+
const [selectedShippingMethod, setSelectedShippingMethod] = react.useState();
|
|
2653
|
+
const [allowNextDayDelivery, setAllowNextDayDelivery] = react.useState(false);
|
|
2654
|
+
const [allowThirdDayDelivery, setAllowThirdDayDelivery] = react.useState(false);
|
|
2655
|
+
const [showAreaCheckModal, setShowAreaCheckModal] = react.useState(false);
|
|
2656
|
+
const [showMoreShippingMethod, setShowMoreShippingMethod] = react.useState(false);
|
|
2657
|
+
const [showPlusMemberBenefit, setShowPlusMemberBenefit] = react.useState(false);
|
|
2658
|
+
const [deleteMarginBottom, setDeleteMarginBottom] = react.useState(false);
|
|
2659
|
+
const shippingMethodsContext = useShippingMethods({
|
|
2660
|
+
variant,
|
|
2661
|
+
plusMemberMetafields: metafields,
|
|
2662
|
+
selectedPlusMemberMode});
|
|
2663
|
+
const plusMemberHandles = react.useMemo(() => {
|
|
2664
|
+
return [
|
|
2665
|
+
metafields?.plus_monthly_product?.handle,
|
|
2666
|
+
metafields?.plus_annual_product?.handle
|
|
2667
|
+
].filter(Boolean);
|
|
2668
|
+
}, [metafields]);
|
|
2669
|
+
const { data: plusMemberProducts = [] } = useProductsByHandles({
|
|
2670
|
+
handles: plusMemberHandles
|
|
2671
|
+
});
|
|
2672
|
+
const selectedPlusMemberProduct = react.useMemo(() => {
|
|
2673
|
+
if (selectedPlusMemberMode === "free" /* FREE */) {
|
|
2674
|
+
return null;
|
|
2675
|
+
}
|
|
2676
|
+
const handle = selectedPlusMemberMode === "monthly" /* MONTHLY */ ? metafields?.plus_monthly_product?.handle : metafields?.plus_annual_product?.handle;
|
|
2677
|
+
const sku = selectedPlusMemberMode === "monthly" /* MONTHLY */ ? metafields?.plus_monthly_product?.sku : metafields?.plus_annual_product?.sku;
|
|
2678
|
+
const product2 = plusMemberProducts?.find((p) => p.handle === handle);
|
|
2679
|
+
const variant2 = product2?.variants?.find((v) => v.sku === sku);
|
|
2680
|
+
return product2 && variant2 ? { product: product2, variant: variant2 } : null;
|
|
2681
|
+
}, [plusMemberProducts, metafields, selectedPlusMemberMode]);
|
|
2682
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2683
|
+
PlusMemberContext.Provider,
|
|
2684
|
+
{
|
|
2685
|
+
value: {
|
|
2686
|
+
variant,
|
|
2687
|
+
shopCommon,
|
|
2688
|
+
zipCode,
|
|
2689
|
+
setZipCode,
|
|
2690
|
+
allowNextDayDelivery,
|
|
2691
|
+
setAllowNextDayDelivery,
|
|
2692
|
+
allowThirdDayDelivery,
|
|
2693
|
+
setAllowThirdDayDelivery,
|
|
2694
|
+
plusMemberMetafields: metafields,
|
|
2695
|
+
selectedPlusMemberMode,
|
|
2696
|
+
setSelectedPlusMemberMode,
|
|
2697
|
+
showAreaCheckModal,
|
|
2698
|
+
setShowAreaCheckModal,
|
|
2699
|
+
selectedShippingMethod,
|
|
2700
|
+
setSelectedShippingMethod,
|
|
2701
|
+
shippingMethodsContext,
|
|
2702
|
+
showTip,
|
|
2703
|
+
setShowTip,
|
|
2704
|
+
showMoreShippingMethod,
|
|
2705
|
+
setShowMoreShippingMethod,
|
|
2706
|
+
selectedPlusMemberProduct,
|
|
2707
|
+
plusMemberProducts,
|
|
2708
|
+
product,
|
|
2709
|
+
showPlusMemberBenefit,
|
|
2710
|
+
setShowPlusMemberBenefit,
|
|
2711
|
+
deleteMarginBottom,
|
|
2712
|
+
setDeleteMarginBottom,
|
|
2713
|
+
profile,
|
|
2714
|
+
locale
|
|
2715
|
+
},
|
|
2716
|
+
children
|
|
2717
|
+
}
|
|
2718
|
+
);
|
|
2719
|
+
};
|
|
2720
|
+
function useIntersection(targetRef, options) {
|
|
2721
|
+
const {
|
|
2722
|
+
callback,
|
|
2723
|
+
once = false,
|
|
2724
|
+
root = null,
|
|
2725
|
+
rootMargin = "0px",
|
|
2726
|
+
threshold = 0.8
|
|
2727
|
+
} = options;
|
|
2728
|
+
react.useEffect(() => {
|
|
2729
|
+
if (!targetRef?.current) {
|
|
2730
|
+
return;
|
|
2731
|
+
}
|
|
2732
|
+
if (typeof IntersectionObserver === "undefined") {
|
|
2733
|
+
console.warn("[useIntersection] IntersectionObserver is not supported");
|
|
2734
|
+
return;
|
|
2735
|
+
}
|
|
2736
|
+
const current = targetRef.current;
|
|
2737
|
+
const observerOptions = {
|
|
2738
|
+
root,
|
|
2739
|
+
rootMargin,
|
|
2740
|
+
threshold
|
|
2741
|
+
};
|
|
2742
|
+
const observer = new IntersectionObserver((entries) => {
|
|
2743
|
+
entries.forEach((entry) => {
|
|
2744
|
+
if (entry.isIntersecting) {
|
|
2745
|
+
callback();
|
|
2746
|
+
if (once) {
|
|
2747
|
+
observer.disconnect();
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
});
|
|
2751
|
+
}, observerOptions);
|
|
2752
|
+
observer.observe(current);
|
|
2753
|
+
return () => {
|
|
2754
|
+
observer.disconnect();
|
|
2755
|
+
};
|
|
2756
|
+
}, [targetRef, callback, once, root, rootMargin, threshold]);
|
|
2757
|
+
}
|
|
2758
|
+
function useExposure(targetRef, options) {
|
|
2759
|
+
const { threshold = 0.5, duration = 2e3, once = true, onExposure } = options;
|
|
2760
|
+
const [isVisible, setIsVisible] = react.useState(false);
|
|
2761
|
+
const timeoutRef = react.useRef(void 0);
|
|
2762
|
+
const hasTriggeredRef = react.useRef(false);
|
|
2763
|
+
react.useEffect(() => {
|
|
2764
|
+
if (!targetRef?.current || typeof IntersectionObserver === "undefined") {
|
|
2765
|
+
return;
|
|
2766
|
+
}
|
|
2767
|
+
if (once && hasTriggeredRef.current) {
|
|
2768
|
+
return;
|
|
2769
|
+
}
|
|
2770
|
+
const current = targetRef.current;
|
|
2771
|
+
const clearTimer = () => {
|
|
2772
|
+
if (timeoutRef.current) {
|
|
2773
|
+
clearTimeout(timeoutRef.current);
|
|
2774
|
+
timeoutRef.current = void 0;
|
|
2775
|
+
}
|
|
2776
|
+
};
|
|
2777
|
+
const observer = new IntersectionObserver(
|
|
2778
|
+
(entries) => {
|
|
2779
|
+
entries.forEach((entry) => {
|
|
2780
|
+
setIsVisible(entry.isIntersecting);
|
|
2781
|
+
if (entry.isIntersecting) {
|
|
2782
|
+
timeoutRef.current = setTimeout(() => {
|
|
2783
|
+
if (once && hasTriggeredRef.current) {
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
onExposure();
|
|
2787
|
+
hasTriggeredRef.current = true;
|
|
2788
|
+
if (once) {
|
|
2789
|
+
observer.disconnect();
|
|
2790
|
+
}
|
|
2791
|
+
}, duration);
|
|
2792
|
+
} else {
|
|
2793
|
+
clearTimer();
|
|
2794
|
+
}
|
|
2795
|
+
});
|
|
2796
|
+
},
|
|
2797
|
+
{
|
|
2798
|
+
root: null,
|
|
2799
|
+
rootMargin: "0px",
|
|
2800
|
+
threshold
|
|
2801
|
+
}
|
|
2802
|
+
);
|
|
2803
|
+
observer.observe(current);
|
|
2804
|
+
return () => {
|
|
2805
|
+
clearTimer();
|
|
2806
|
+
observer.disconnect();
|
|
2807
|
+
};
|
|
2808
|
+
}, [targetRef, threshold, duration, once, onExposure]);
|
|
2809
|
+
return isVisible;
|
|
2810
|
+
}
|
|
2811
|
+
function determineSuggestedLocale(countryCode, mapping) {
|
|
2812
|
+
if (!countryCode) {
|
|
2813
|
+
return "us";
|
|
2814
|
+
}
|
|
2815
|
+
const upperCode = countryCode.toUpperCase();
|
|
2816
|
+
if (mapping?.customMapping?.[upperCode]) {
|
|
2817
|
+
return mapping.customMapping[upperCode];
|
|
2818
|
+
}
|
|
2819
|
+
if (mapping?.euCountries?.includes(upperCode)) {
|
|
2820
|
+
if (upperCode === "PL") {
|
|
2821
|
+
return "pl";
|
|
2822
|
+
}
|
|
2823
|
+
return "eu";
|
|
2824
|
+
}
|
|
2825
|
+
if (mapping?.auCountries?.includes(upperCode)) {
|
|
2826
|
+
return "au";
|
|
2827
|
+
}
|
|
2828
|
+
if (mapping?.deCountries?.includes(upperCode)) {
|
|
2829
|
+
return "de";
|
|
2830
|
+
}
|
|
2831
|
+
if (mapping?.aeEnCountries?.includes(upperCode)) {
|
|
2832
|
+
return "ae-en";
|
|
2833
|
+
}
|
|
2834
|
+
if (upperCode === "GB") {
|
|
2835
|
+
return "uk";
|
|
2836
|
+
}
|
|
2837
|
+
return countryCode.toLowerCase();
|
|
2838
|
+
}
|
|
2839
|
+
function useGeoLocation(options = {}) {
|
|
2840
|
+
const {
|
|
2841
|
+
endpoint = "/geolocation",
|
|
2842
|
+
cacheKey = "geoLocation",
|
|
2843
|
+
cacheDuration = 1e3 * 60 * 60 * 24,
|
|
2844
|
+
// 24 hours
|
|
2845
|
+
localeMapping,
|
|
2846
|
+
enableCache = true,
|
|
2847
|
+
...swrOptions
|
|
2848
|
+
} = options;
|
|
2849
|
+
const fetcher = async () => {
|
|
2850
|
+
if (enableCache) {
|
|
2851
|
+
const cached = shopifySdk.getLocalStorage(cacheKey);
|
|
2852
|
+
if (cached) {
|
|
2853
|
+
return cached;
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
try {
|
|
2857
|
+
const response = await fetch(endpoint);
|
|
2858
|
+
if (!response.ok) {
|
|
2859
|
+
throw new Error(`Failed to fetch geo location: ${response.status}`);
|
|
2860
|
+
}
|
|
2861
|
+
const result = await response.json();
|
|
2862
|
+
const countryCode = result?.geo?.country?.code;
|
|
2863
|
+
if (!countryCode) {
|
|
2864
|
+
console.warn("[useGeoLocation] No country code in response");
|
|
2865
|
+
return void 0;
|
|
2866
|
+
}
|
|
2867
|
+
const suggestLocale = determineSuggestedLocale(
|
|
2868
|
+
countryCode,
|
|
2869
|
+
localeMapping
|
|
2870
|
+
);
|
|
2871
|
+
const geoData = {
|
|
2872
|
+
geo: result.geo,
|
|
2873
|
+
suggestLocale
|
|
2874
|
+
};
|
|
2875
|
+
if (enableCache) {
|
|
2876
|
+
const expires = new Date(Date.now() + cacheDuration);
|
|
2877
|
+
shopifySdk.setLocalStorage(cacheKey, geoData, { expires });
|
|
2878
|
+
}
|
|
2879
|
+
return geoData;
|
|
2880
|
+
} catch (error) {
|
|
2881
|
+
console.error("[useGeoLocation] Error fetching geo data:", error);
|
|
2882
|
+
return void 0;
|
|
2883
|
+
}
|
|
2884
|
+
};
|
|
2885
|
+
return useSWR__default.default(
|
|
2886
|
+
cacheKey,
|
|
2887
|
+
fetcher,
|
|
2888
|
+
swrOptions
|
|
2889
|
+
);
|
|
2890
|
+
}
|
|
2891
|
+
function getCachedGeoLocation(cacheKey = "geoLocation") {
|
|
2892
|
+
return shopifySdk.getLocalStorage(cacheKey) ?? void 0;
|
|
2893
|
+
}
|
|
2894
|
+
function clearGeoLocationCache(cacheKey = "geoLocation") {
|
|
2895
|
+
if (typeof localStorage !== "undefined") {
|
|
2896
|
+
localStorage.removeItem(cacheKey);
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
var CartContext = react.createContext(null);
|
|
2900
|
+
function CartProvider({
|
|
2901
|
+
children,
|
|
2902
|
+
// swrOptions,
|
|
2903
|
+
autoFreeGiftConfig,
|
|
2904
|
+
gradientGiftsConfig,
|
|
2905
|
+
profile,
|
|
2906
|
+
customer,
|
|
2907
|
+
locale,
|
|
2908
|
+
metafieldIdentifiers,
|
|
2909
|
+
memberSetting
|
|
2910
|
+
}) {
|
|
2911
|
+
const { client, cartCookieAdapter } = useShopify();
|
|
2912
|
+
const [customAttributes, setCustomAttributes] = react.useState([]);
|
|
2913
|
+
const [isCodeChanging, setIsCodeChanging] = react.useState(false);
|
|
2914
|
+
const [loadingState, setLoadingState] = react.useState({
|
|
2915
|
+
editLineQuantityLoading: false,
|
|
2916
|
+
editLineCodeAmountLoading: false,
|
|
2917
|
+
listingAutoCodeApplying: false,
|
|
2918
|
+
userCodeApplying: false
|
|
2919
|
+
});
|
|
2920
|
+
const [scriptAutoFreeGift, setScriptAutoFreeGift] = react.useState([]);
|
|
2921
|
+
const [functionAutoFreeGift, setFunctionAutoFreeGift] = react.useState([]);
|
|
2922
|
+
const {
|
|
2923
|
+
run: fetchCart,
|
|
2924
|
+
data: cart,
|
|
2925
|
+
loading: isCartLoading,
|
|
2926
|
+
mutate: mutateCart
|
|
2927
|
+
} = ahooks.useRequest(
|
|
2928
|
+
async () => {
|
|
2929
|
+
return shopifySdk.getCart(client, {
|
|
2930
|
+
cookieAdapter: cartCookieAdapter,
|
|
2931
|
+
metafieldIdentifiers
|
|
2932
|
+
});
|
|
2933
|
+
},
|
|
2934
|
+
{
|
|
2935
|
+
refreshDeps: [locale]
|
|
2936
|
+
}
|
|
2937
|
+
);
|
|
2938
|
+
const { trigger: updateAttributes } = useUpdateCartAttributes(mutateCart, metafieldIdentifiers);
|
|
2939
|
+
const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
|
|
2940
|
+
ahooks.useRequest(
|
|
2941
|
+
() => {
|
|
2942
|
+
const newAttributes = [...attributes, ...customAttributes];
|
|
2943
|
+
const needUpdate = cart && !isAttributesEqual(cart.customAttributes, newAttributes);
|
|
2944
|
+
if (needUpdate) {
|
|
2945
|
+
return updateAttributes({ attributes: newAttributes });
|
|
2946
|
+
} else {
|
|
2947
|
+
return Promise.resolve(cart);
|
|
2948
|
+
}
|
|
2949
|
+
},
|
|
2950
|
+
{
|
|
2951
|
+
throttleWait: 1e3,
|
|
2952
|
+
// 1 秒内只触发最后一次更新
|
|
2953
|
+
throttleTrailing: true,
|
|
2954
|
+
throttleLeading: false,
|
|
2955
|
+
refreshDeps: [attributes, customAttributes]
|
|
2956
|
+
}
|
|
2957
|
+
);
|
|
2958
|
+
useUpdateLineCodeAmountAttributes({
|
|
2959
|
+
cart,
|
|
2960
|
+
mutateCart,
|
|
2961
|
+
isCartLoading: isCartLoading || isCodeChanging,
|
|
2962
|
+
setLoadingState
|
|
2963
|
+
});
|
|
2964
|
+
const removeCustomAttributes = react.useCallback((attributes2) => {
|
|
2965
|
+
setCustomAttributes(
|
|
2966
|
+
(prev) => prev.filter((attr) => !attributes2.some((a) => a.key === attr.key))
|
|
2967
|
+
);
|
|
2968
|
+
}, []);
|
|
2969
|
+
const addCustomAttributes = react.useCallback(
|
|
2970
|
+
(attributes2) => {
|
|
2971
|
+
const sameAttributes = attributes2.filter(
|
|
2972
|
+
(attr) => customAttributes.some((a) => a.key === attr.key)
|
|
2973
|
+
);
|
|
2974
|
+
if (sameAttributes.length) {
|
|
2975
|
+
setCustomAttributes((prev) => {
|
|
2976
|
+
const removedAttributes = prev.filter(
|
|
2977
|
+
(attr) => !sameAttributes.some((a) => a.key === attr.key)
|
|
2978
|
+
);
|
|
2979
|
+
return [...removedAttributes, ...attributes2];
|
|
2980
|
+
});
|
|
2981
|
+
} else {
|
|
2982
|
+
setCustomAttributes((prev) => [...prev, ...attributes2]);
|
|
2983
|
+
}
|
|
2984
|
+
},
|
|
2985
|
+
[customAttributes]
|
|
2986
|
+
);
|
|
2987
|
+
const functionAutoFreeGiftResult = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer);
|
|
2988
|
+
const scriptAutoFreeGiftResult = useScriptAutoFreeGift({
|
|
2989
|
+
campaign: gradientGiftsConfig || null,
|
|
2990
|
+
_giveaway: CUSTOMER_SCRIPT_GIFT_KEY,
|
|
2991
|
+
cart
|
|
2992
|
+
});
|
|
2993
|
+
const formattedScriptGifts = react.useMemo(() => {
|
|
2994
|
+
return formatScriptAutoFreeGift({
|
|
2995
|
+
scriptAutoFreeGiftResult,
|
|
2996
|
+
gradient_gifts: gradientGiftsConfig,
|
|
2997
|
+
locale
|
|
2998
|
+
});
|
|
2999
|
+
}, [scriptAutoFreeGiftResult, gradientGiftsConfig, locale]);
|
|
3000
|
+
const formattedFunctionGifts = react.useMemo(() => {
|
|
3001
|
+
return formatFunctionAutoFreeGift({
|
|
3002
|
+
qualifyingGift: functionAutoFreeGiftResult?.qualifyingGift || null,
|
|
3003
|
+
giftProductsResult: functionAutoFreeGiftResult?.giftProductsResult || [],
|
|
3004
|
+
locale
|
|
3005
|
+
});
|
|
3006
|
+
}, [functionAutoFreeGiftResult, locale]);
|
|
3007
|
+
react.useEffect(() => {
|
|
3008
|
+
if (loadingState.userCodeApplying || loadingState.editLineQuantityLoading || loadingState.editLineCodeAmountLoading || loadingState.listingAutoCodeApplying) {
|
|
3009
|
+
return;
|
|
3010
|
+
}
|
|
3011
|
+
setScriptAutoFreeGift(formattedScriptGifts);
|
|
3012
|
+
setFunctionAutoFreeGift(formattedFunctionGifts);
|
|
3013
|
+
}, [
|
|
3014
|
+
formattedScriptGifts,
|
|
3015
|
+
formattedFunctionGifts,
|
|
3016
|
+
loadingState.userCodeApplying,
|
|
3017
|
+
loadingState.editLineQuantityLoading,
|
|
3018
|
+
loadingState.editLineCodeAmountLoading,
|
|
3019
|
+
loadingState.listingAutoCodeApplying
|
|
3020
|
+
]);
|
|
3021
|
+
const giftNeedAddToCartLines = react.useMemo(() => {
|
|
3022
|
+
const cartGiftLineItems = cart?.lineItems.filter(
|
|
3023
|
+
(line) => line.customAttributes?.some(
|
|
3024
|
+
(attr) => [CUSTOMER_ATTRIBUTE_KEY, CUSTOMER_SCRIPT_GIFT_KEY].includes(attr.key)
|
|
3025
|
+
)
|
|
3026
|
+
);
|
|
3027
|
+
const result = [...scriptAutoFreeGift, ...functionAutoFreeGift].filter(
|
|
3028
|
+
(item) => (
|
|
3029
|
+
// 如果购物车中已经存在对应赠品,且标记了 function 满赠的属性,则不添加
|
|
3030
|
+
!cartGiftLineItems?.find((line) => {
|
|
3031
|
+
return line.variantId === item.line.variantId && line.customAttributes?.some((attr) => {
|
|
3032
|
+
if (attr.key === "_discounts_function_env") {
|
|
3033
|
+
return getDiscountEnvAttributeValue(line.customAttributes).is_gift;
|
|
3034
|
+
}
|
|
3035
|
+
return false;
|
|
3036
|
+
});
|
|
3037
|
+
})
|
|
3038
|
+
)
|
|
3039
|
+
);
|
|
3040
|
+
return result;
|
|
3041
|
+
}, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
|
|
3042
|
+
const value = react.useMemo(
|
|
3043
|
+
() => ({
|
|
3044
|
+
cart,
|
|
3045
|
+
isCartLoading,
|
|
3046
|
+
triggerFetch: fetchCart,
|
|
3047
|
+
mutateCart,
|
|
3048
|
+
addCustomAttributes,
|
|
3049
|
+
removeCustomAttributes,
|
|
3050
|
+
setCustomAttributes,
|
|
3051
|
+
locale,
|
|
3052
|
+
isCodeChanging,
|
|
3053
|
+
setIsCodeChanging,
|
|
3054
|
+
autoFreeGiftConfig,
|
|
3055
|
+
setLoadingState,
|
|
3056
|
+
loadingState,
|
|
3057
|
+
// function满赠
|
|
3058
|
+
functionAutoFreeGift,
|
|
3059
|
+
functionAutoFreeGiftResult,
|
|
3060
|
+
setFunctionAutoFreeGift,
|
|
3061
|
+
// script满赠
|
|
3062
|
+
scriptAutoFreeGift,
|
|
3063
|
+
scriptAutoFreeGiftResult,
|
|
3064
|
+
setScriptAutoFreeGift,
|
|
3065
|
+
giftNeedAddToCartLines,
|
|
3066
|
+
metafieldIdentifiers
|
|
3067
|
+
}),
|
|
3068
|
+
[
|
|
3069
|
+
cart,
|
|
3070
|
+
isCartLoading,
|
|
3071
|
+
fetchCart,
|
|
3072
|
+
mutateCart,
|
|
3073
|
+
addCustomAttributes,
|
|
3074
|
+
removeCustomAttributes,
|
|
3075
|
+
locale,
|
|
3076
|
+
isCodeChanging,
|
|
3077
|
+
autoFreeGiftConfig,
|
|
3078
|
+
loadingState,
|
|
3079
|
+
// function满赠
|
|
3080
|
+
functionAutoFreeGift,
|
|
3081
|
+
functionAutoFreeGiftResult,
|
|
3082
|
+
setFunctionAutoFreeGift,
|
|
3083
|
+
// script满赠
|
|
3084
|
+
scriptAutoFreeGift,
|
|
3085
|
+
scriptAutoFreeGiftResult,
|
|
3086
|
+
setScriptAutoFreeGift,
|
|
3087
|
+
giftNeedAddToCartLines,
|
|
3088
|
+
metafieldIdentifiers
|
|
3089
|
+
]
|
|
3090
|
+
);
|
|
3091
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
|
|
3092
|
+
}
|
|
3093
|
+
function useCartContext() {
|
|
3094
|
+
const context = react.useContext(CartContext);
|
|
3095
|
+
if (!context) {
|
|
3096
|
+
throw new Error("useCartContext must be used within a CartProvider");
|
|
3097
|
+
}
|
|
3098
|
+
return context;
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
Object.defineProperty(exports, "ShopifyConfig", {
|
|
3102
|
+
enumerable: true,
|
|
3103
|
+
get: function () { return shopifySdk.ShopifyConfig; }
|
|
3104
|
+
});
|
|
3105
|
+
Object.defineProperty(exports, "clearLocalStorage", {
|
|
3106
|
+
enumerable: true,
|
|
3107
|
+
get: function () { return shopifySdk.clearLocalStorage; }
|
|
3108
|
+
});
|
|
3109
|
+
Object.defineProperty(exports, "createShopifyClient", {
|
|
3110
|
+
enumerable: true,
|
|
3111
|
+
get: function () { return shopifySdk.createShopifyClient; }
|
|
3112
|
+
});
|
|
3113
|
+
Object.defineProperty(exports, "getLocalStorage", {
|
|
3114
|
+
enumerable: true,
|
|
3115
|
+
get: function () { return shopifySdk.getLocalStorage; }
|
|
3116
|
+
});
|
|
3117
|
+
Object.defineProperty(exports, "removeLocalStorage", {
|
|
3118
|
+
enumerable: true,
|
|
3119
|
+
get: function () { return shopifySdk.removeLocalStorage; }
|
|
3120
|
+
});
|
|
3121
|
+
Object.defineProperty(exports, "setLocalStorage", {
|
|
3122
|
+
enumerable: true,
|
|
3123
|
+
get: function () { return shopifySdk.setLocalStorage; }
|
|
3124
|
+
});
|
|
3125
|
+
exports.BuyRuleType = BuyRuleType;
|
|
3126
|
+
exports.CODE_AMOUNT_KEY = CODE_AMOUNT_KEY;
|
|
3127
|
+
exports.CUSTOMER_ATTRIBUTE_KEY = CUSTOMER_ATTRIBUTE_KEY;
|
|
3128
|
+
exports.CUSTOMER_SCRIPT_GIFT_KEY = CUSTOMER_SCRIPT_GIFT_KEY;
|
|
3129
|
+
exports.CartProvider = CartProvider;
|
|
3130
|
+
exports.DeliveryPlusType = DeliveryPlusType;
|
|
3131
|
+
exports.MAIN_PRODUCT_CODE = MAIN_PRODUCT_CODE;
|
|
3132
|
+
exports.OrderBasePriceType = OrderBasePriceType;
|
|
3133
|
+
exports.OrderDiscountType = OrderDiscountType;
|
|
3134
|
+
exports.PLUS_MEMBER_TYPE = PLUS_MEMBER_TYPE;
|
|
3135
|
+
exports.PlusMemberContext = PlusMemberContext;
|
|
3136
|
+
exports.PlusMemberMode = PlusMemberMode;
|
|
3137
|
+
exports.PlusMemberProvider = PlusMemberProvider;
|
|
3138
|
+
exports.PriceBasePriceType = PriceBasePriceType;
|
|
3139
|
+
exports.PriceDiscountType = PriceDiscountType;
|
|
3140
|
+
exports.RuleType = RuleType;
|
|
3141
|
+
exports.SCRIPT_CODE_AMOUNT_KEY = SCRIPT_CODE_AMOUNT_KEY;
|
|
3142
|
+
exports.ShippingMethodMode = ShippingMethodMode;
|
|
3143
|
+
exports.ShopifyContext = ShopifyContext;
|
|
3144
|
+
exports.ShopifyProvider = ShopifyProvider;
|
|
3145
|
+
exports.SpendMoneyType = SpendMoneyType;
|
|
3146
|
+
exports.atobID = atobID;
|
|
3147
|
+
exports.browserCartCookieAdapter = browserCartCookieAdapter;
|
|
3148
|
+
exports.browserCookieAdapter = browserCookieAdapter;
|
|
3149
|
+
exports.btoaID = btoaID;
|
|
3150
|
+
exports.clearGeoLocationCache = clearGeoLocationCache;
|
|
3151
|
+
exports.currencyCodeMapping = currencyCodeMapping;
|
|
3152
|
+
exports.defaultSWRMutationConfiguration = defaultSWRMutationConfiguration;
|
|
3153
|
+
exports.formatFunctionAutoFreeGift = formatFunctionAutoFreeGift;
|
|
3154
|
+
exports.formatScriptAutoFreeGift = formatScriptAutoFreeGift;
|
|
3155
|
+
exports.gaTrack = gaTrack;
|
|
3156
|
+
exports.getCachedGeoLocation = getCachedGeoLocation;
|
|
3157
|
+
exports.getDiscountEnvAttributeValue = getDiscountEnvAttributeValue;
|
|
3158
|
+
exports.getMatchedMainProductSubTotal = getMatchedMainProductSubTotal;
|
|
3159
|
+
exports.getQuery = getQuery;
|
|
3160
|
+
exports.getReferralAttributes = getReferralAttributes;
|
|
3161
|
+
exports.isAttributesEqual = isAttributesEqual;
|
|
3162
|
+
exports.preCheck = preCheck;
|
|
3163
|
+
exports.safeParseJson = safeParseJson;
|
|
3164
|
+
exports.trackAddToCartFBQ = trackAddToCartFBQ;
|
|
3165
|
+
exports.trackAddToCartGA = trackAddToCartGA;
|
|
3166
|
+
exports.trackBeginCheckoutGA = trackBeginCheckoutGA;
|
|
3167
|
+
exports.trackBuyNowFBQ = trackBuyNowFBQ;
|
|
3168
|
+
exports.trackBuyNowGA = trackBuyNowGA;
|
|
3169
|
+
exports.useAddCartLines = useAddCartLines;
|
|
3170
|
+
exports.useAddToCart = useAddToCart;
|
|
3171
|
+
exports.useAllBlogs = useAllBlogs;
|
|
3172
|
+
exports.useAllCollections = useAllCollections;
|
|
3173
|
+
exports.useAllProducts = useAllProducts;
|
|
3174
|
+
exports.useApplyCartCodes = useApplyCartCodes;
|
|
3175
|
+
exports.useArticle = useArticle;
|
|
3176
|
+
exports.useArticles = useArticles;
|
|
3177
|
+
exports.useArticlesInBlog = useArticlesInBlog;
|
|
3178
|
+
exports.useAutoRemovePlusMemberInCart = useAutoRemovePlusMemberInCart;
|
|
3179
|
+
exports.useBlog = useBlog;
|
|
3180
|
+
exports.useBuyNow = useBuyNow;
|
|
3181
|
+
exports.useCalcAutoFreeGift = useCalcAutoFreeGift;
|
|
3182
|
+
exports.useCalcOrderDiscount = useCalcOrderDiscount;
|
|
3183
|
+
exports.useCartAttributes = useCartAttributes;
|
|
3184
|
+
exports.useCartContext = useCartContext;
|
|
3185
|
+
exports.useCartItemQuantityLimit = useCartItemQuantityLimit;
|
|
3186
|
+
exports.useCollection = useCollection;
|
|
3187
|
+
exports.useCollections = useCollections;
|
|
3188
|
+
exports.useCreateCart = useCreateCart;
|
|
3189
|
+
exports.useExposure = useExposure;
|
|
3190
|
+
exports.useGeoLocation = useGeoLocation;
|
|
3191
|
+
exports.useHasPlusMemberInCart = useHasPlusMemberInCart;
|
|
3192
|
+
exports.useIntersection = useIntersection;
|
|
3193
|
+
exports.usePlusAnnualProductVariant = usePlusAnnualProductVariant;
|
|
3194
|
+
exports.usePlusMemberCheckoutCustomAttributes = usePlusMemberCheckoutCustomAttributes;
|
|
3195
|
+
exports.usePlusMemberContext = usePlusMemberContext;
|
|
3196
|
+
exports.usePlusMemberDeliveryCodes = usePlusMemberDeliveryCodes;
|
|
3197
|
+
exports.usePlusMemberItemCustomAttributes = usePlusMemberItemCustomAttributes;
|
|
3198
|
+
exports.usePlusMonthlyProductVariant = usePlusMonthlyProductVariant;
|
|
3199
|
+
exports.usePrice = usePrice;
|
|
3200
|
+
exports.useProduct = useProduct;
|
|
3201
|
+
exports.useProductUrl = useProductUrl;
|
|
3202
|
+
exports.useProductsByHandles = useProductsByHandles;
|
|
3203
|
+
exports.useRemoveCartCodes = useRemoveCartCodes;
|
|
3204
|
+
exports.useRemoveCartLines = useRemoveCartLines;
|
|
3205
|
+
exports.useReplaceCartPlusMember = useReplaceCartPlusMember;
|
|
3206
|
+
exports.useScriptAutoFreeGift = useScriptAutoFreeGift;
|
|
3207
|
+
exports.useSearch = useSearch;
|
|
3208
|
+
exports.useSelectedOptions = useSelectedOptions;
|
|
3209
|
+
exports.useShippingMethodAvailableCheck = useShippingMethodAvailableCheck;
|
|
3210
|
+
exports.useShippingMethods = useShippingMethods;
|
|
3211
|
+
exports.useShopify = useShopify;
|
|
3212
|
+
exports.useSite = useSite;
|
|
3213
|
+
exports.useUpdateCartAttributes = useUpdateCartAttributes;
|
|
3214
|
+
exports.useUpdateCartLines = useUpdateCartLines;
|
|
3215
|
+
exports.useUpdateLineCodeAmountAttributes = useUpdateLineCodeAmountAttributes;
|
|
3216
|
+
exports.useUpdateVariantQuery = useUpdateVariantQuery;
|
|
3217
|
+
exports.useVariant = useVariant;
|
|
3218
|
+
exports.useVariantMedia = useVariantMedia;
|
|
3219
|
+
//# sourceMappingURL=index.js.map
|
|
3220
|
+
//# sourceMappingURL=index.js.map
|