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