@anker-in/shopify-react 0.1.1-beta.0

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