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