@anker-in/shopify-react 0.1.1-beta.5 → 0.1.1-beta.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,9 +1,10 @@
1
1
  import { createContext, useMemo, useContext, useRef, useState, useEffect, useCallback } from 'react';
2
- import { createShopifyClient, getProductsByHandles, createCart, updateCartCodes, addCartLines, updateCartLines, removeCartLines, updateCartAttributes, getProduct, getAllProducts, getCollection, getAllCollections, getCollections, getBlog, getAllBlogs, getArticle, getArticles, getArticlesInBlog, getLocalStorage, getCart, setLocalStorage } from '@anker-in/shopify-sdk';
3
- export { ShopifyConfig, clearLocalStorage, createShopifyClient, getLocalStorage, removeLocalStorage, setLocalStorage } from '@anker-in/shopify-sdk';
2
+ import { createShopifyClient, getProductsByHandles, createCart, updateCartCodes, addCartLines, getLocalStorage, updateCartLines, removeCartLines, updateCartAttributes, getProduct, getAllProducts, getCollection, getAllCollections, getCollections, getBlog, getAllBlogs, getArticle, getArticles, getArticlesInBlog, getCart, setLocalStorage } from '@anker-in/shopify-sdk';
3
+ export * from '@anker-in/shopify-sdk';
4
4
  import Cookies5 from 'js-cookie';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
  import Decimal2 from 'decimal.js';
7
+ import { atobID, btoaID } from '@anker-in/shopify-core';
7
8
  import useSWR from 'swr';
8
9
  import useSWRMutation from 'swr/mutation';
9
10
  import { useRequest } from 'ahooks';
@@ -45,6 +46,20 @@ var browserCartCookieAdapter = {
45
46
  Cookies5.remove(getCartCookieName(locale));
46
47
  }
47
48
  };
49
+
50
+ // src/adapters/browser-performance.ts
51
+ var BrowserPerformanceAdapter = class {
52
+ /**
53
+ * Start tracking a performance event
54
+ */
55
+ addToCartStart() {
56
+ }
57
+ /**
58
+ * End tracking a performance event
59
+ */
60
+ addToCartEnd() {
61
+ }
62
+ };
48
63
  function ShopifyProvider({
49
64
  config,
50
65
  locale,
@@ -53,7 +68,8 @@ function ShopifyProvider({
53
68
  cartCookieAdapter = browserCartCookieAdapter,
54
69
  routerAdapter,
55
70
  userAdapter,
56
- children
71
+ children,
72
+ performanceAdapter
57
73
  }) {
58
74
  const client = useMemo(() => {
59
75
  return createShopifyClient(config, locale);
@@ -67,7 +83,8 @@ function ShopifyProvider({
67
83
  cookieAdapter,
68
84
  cartCookieAdapter,
69
85
  routerAdapter,
70
- userAdapter
86
+ userAdapter,
87
+ performanceAdapter
71
88
  };
72
89
  }, [
73
90
  client,
@@ -77,6 +94,7 @@ function ShopifyProvider({
77
94
  cookieAdapter,
78
95
  cartCookieAdapter,
79
96
  routerAdapter,
97
+ performanceAdapter,
80
98
  userAdapter
81
99
  ]);
82
100
  return /* @__PURE__ */ jsx(ShopifyContext.Provider, { value, children });
@@ -132,6 +150,7 @@ var CUSTOMER_ATTRIBUTE_KEY = "_discounts_function_env";
132
150
  var CUSTOMER_SCRIPT_GIFT_KEY = "_giveaway_gradient_gifts";
133
151
  var CODE_AMOUNT_KEY = "_sku_code_money";
134
152
  var SCRIPT_CODE_AMOUNT_KEY = "_code_money";
153
+ var MEMBER_PRICE_ATTRIBUTE_KEY = "_member_price";
135
154
  var MAIN_PRODUCT_CODE = ["WS24", "WSTD", "WS7D", "WSCP", "WSPE", "WSPD"];
136
155
 
137
156
  // src/hooks/cart/utils/normalize-add-to-cart-lines.ts
@@ -140,9 +159,10 @@ function normalizeAddToCartLines(lines) {
140
159
  const variant = line.variant;
141
160
  const product = variant.product;
142
161
  const quantity = line.quantity || 1;
143
- const price = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : variant.price?.amount ? Number(variant.price.amount) : 0;
144
- const subtotalAmount = price * quantity;
145
- const totalAmount = subtotalAmount;
162
+ const originalPrice = variant.price?.amount ? Number(variant.price.amount) : 0;
163
+ const finalPrice = variant.finalPrice?.amount === void 0 ? originalPrice : Number(variant.finalPrice?.amount);
164
+ const subtotalAmount = originalPrice * quantity;
165
+ const totalAmount = finalPrice * quantity;
146
166
  return {
147
167
  id: `temp-line-${index}-${variant.id}`,
148
168
  // Temporary ID for pre-cart lines
@@ -156,7 +176,7 @@ function normalizeAddToCartLines(lines) {
156
176
  customAttributes: line.attributes || [],
157
177
  variant: {
158
178
  id: variant.id,
159
- price,
179
+ price: finalPrice,
160
180
  listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
161
181
  sku: variant.sku || "",
162
182
  name: variant.title || "",
@@ -187,15 +207,16 @@ function createMockCartFromLines(lines, existingCart) {
187
207
  const normalizedLines = normalizeAddToCartLines(lines);
188
208
  const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
189
209
  const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
210
+ const currency = lines[0]?.variant?.price?.currencyCode;
190
211
  return {
191
212
  id: existingCart?.id || "temp-cart-id",
192
213
  customerId: existingCart?.customerId,
193
214
  email: existingCart?.email,
194
215
  createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
195
- currency: existingCart?.currency || { code: "USD" },
216
+ currency: existingCart?.currency || { code: currency },
196
217
  taxesIncluded: existingCart?.taxesIncluded,
197
218
  lineItems: normalizedLines,
198
- totallineItemsDiscount: 0,
219
+ totalLineItemsDiscount: 0,
199
220
  orderDiscounts: 0,
200
221
  lineItemsSubtotalPrice: subtotalPrice,
201
222
  subtotalPrice,
@@ -226,16 +247,6 @@ var getQuery = () => {
226
247
  }
227
248
  return theRequest;
228
249
  };
229
- function atobID(id) {
230
- if (id && typeof id === "string" && id.includes("/")) {
231
- return id.split("/").pop()?.split("?")?.shift();
232
- } else {
233
- return id;
234
- }
235
- }
236
- function btoaID(id, type = "ProductVariant") {
237
- return `gid://shopify/${type}/${id}`;
238
- }
239
250
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
240
251
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
241
252
  const matchedList = cartData?.lineItems?.filter((line) => {
@@ -259,14 +270,6 @@ var getDiscountEnvAttributeValue = (attributes = []) => {
259
270
  const attr = attributes.find((attr2) => attr2.key === CUSTOMER_ATTRIBUTE_KEY);
260
271
  return safeParse(attr?.value ?? "") ?? {};
261
272
  };
262
- var checkAttributesUpdateNeeded = (oldAttributes, newAttributes, customAttributesNeedRemove) => {
263
- return oldAttributes.some((attr) => {
264
- const newAttr = newAttributes.find((newAttr2) => newAttr2.key === attr.key);
265
- return newAttr ? newAttr.value !== attr.value : true;
266
- }) || newAttributes.some((attr) => !oldAttributes.some((oldAttr) => oldAttr.key === attr.key)) || customAttributesNeedRemove.some(
267
- (removeAttr) => oldAttributes.some((oldAttr) => oldAttr.key === removeAttr.key)
268
- );
269
- };
270
273
  var containsAll = (source, requiredItems = []) => {
271
274
  if (!requiredItems?.length) return true;
272
275
  const sourceSet = new Set(source);
@@ -467,43 +470,29 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
467
470
  }
468
471
  return { activeCampaign: null, subtotal: 0 };
469
472
  }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
470
- const { qualifyingGift, nextTierGoal } = useMemo(() => {
473
+ const { qualifyingTier, nextTierGoal, actualThreshold, currentCurrency } = useMemo(() => {
471
474
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
472
- return { qualifyingGift: null, nextTierGoal: null };
475
+ return { qualifyingTier: null, nextTierGoal: null, actualThreshold: 0, currentCurrency: "" };
473
476
  }
474
477
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
475
- const qualifyingTier = [...giftTiers].sort((a, b) => Number(b.spend_sum_money) - Number(a.spend_sum_money)).find((tier) => subtotal >= Number(tier.spend_sum_money));
476
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
477
- if (!qualifyingTier) {
478
- return { qualifyingGift: null, nextTierGoal: nextGoal || null };
479
- }
480
- const formattedGift = {
481
- tier: qualifyingTier,
482
- itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
483
- const giftProduct = reward?.variant_list?.[0];
484
- if (!giftProduct) return null;
485
- return {
486
- variant: {
487
- id: btoaID(giftProduct.variant_id),
488
- handle: giftProduct.handle,
489
- sku: giftProduct.sku
490
- },
491
- quantity: reward?.get_unit || 1,
492
- attributes: [
493
- {
494
- key: CUSTOMER_ATTRIBUTE_KEY,
495
- value: JSON.stringify({
496
- is_gift: true,
497
- rule_id: activeCampaign.rule_id,
498
- spend_sum_money: qualifyingTier.spend_sum_money
499
- })
500
- }
501
- ]
502
- };
503
- }).filter((item) => item !== null)
478
+ const currentCurrency2 = effectiveCart?.currency?.code || "";
479
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency2);
480
+ const getThresholdAmount = (tier) => {
481
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency2]?.value) {
482
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency2].value);
483
+ }
484
+ return Number(tier.spend_sum_money || 0);
504
485
  };
505
- return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
506
- }, [activeCampaign, subtotal]);
486
+ const qualifyingTier2 = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
487
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
488
+ const actualThreshold2 = qualifyingTier2 ? getThresholdAmount(qualifyingTier2) : 0;
489
+ return {
490
+ qualifyingTier: qualifyingTier2,
491
+ nextTierGoal: nextGoal || null,
492
+ actualThreshold: actualThreshold2,
493
+ currentCurrency: currentCurrency2
494
+ };
495
+ }, [activeCampaign, subtotal, effectiveCart]);
507
496
  const giftHandles = useMemo(() => {
508
497
  const giftVariant = autoFreeGiftConfig.map(
509
498
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -519,24 +508,82 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
519
508
  }
520
509
  return true;
521
510
  }, [giftHandles]);
522
- const { data: giftProductsResult } = useSWR(shouldFetch ? giftHandles : null, async () => {
523
- const res = await getProductsByHandles(client, {
524
- handles: giftHandles,
525
- locale
526
- });
527
- const result = Array.isArray(res) ? res : [];
528
- giftProductsCache.current = {
529
- data: result,
530
- giftHandles: [...giftHandles]
531
- };
532
- return result;
533
- });
511
+ const { data: giftProductsResult } = useSWR(
512
+ shouldFetch ? giftHandles : null,
513
+ async () => {
514
+ const res = await getProductsByHandles(client, {
515
+ handles: giftHandles,
516
+ locale
517
+ });
518
+ const result = Array.isArray(res) ? res : [];
519
+ giftProductsCache.current = {
520
+ data: result,
521
+ giftHandles: [...giftHandles]
522
+ };
523
+ return result;
524
+ },
525
+ {
526
+ revalidateOnFocus: false
527
+ }
528
+ );
534
529
  const finalGiftProductsResult = useMemo(() => {
535
530
  if (giftProductsCache.current && !shouldFetch) {
536
531
  return giftProductsCache.current.data || void 0;
537
532
  }
538
533
  return giftProductsResult;
539
534
  }, [giftProductsResult, shouldFetch]);
535
+ const qualifyingGift = useMemo(() => {
536
+ if (!qualifyingTier || !activeCampaign) {
537
+ return null;
538
+ }
539
+ const itemsToAdd = qualifyingTier.reward_list?.map((reward) => {
540
+ if (!reward.variant_list || reward.variant_list.length === 0) {
541
+ return null;
542
+ }
543
+ let selectedGiftProduct = null;
544
+ for (const giftVariant of reward.variant_list) {
545
+ const productInfo = finalGiftProductsResult?.find(
546
+ (p) => p.handle === giftVariant.handle
547
+ );
548
+ if (productInfo) {
549
+ const variantInfo = productInfo.variants?.find((v) => v.sku === giftVariant.sku);
550
+ if (variantInfo?.availableForSale) {
551
+ selectedGiftProduct = giftVariant;
552
+ break;
553
+ }
554
+ }
555
+ }
556
+ if (!selectedGiftProduct) {
557
+ selectedGiftProduct = reward.variant_list[0];
558
+ }
559
+ return {
560
+ variant: {
561
+ id: btoaID(selectedGiftProduct.variant_id),
562
+ handle: selectedGiftProduct.handle,
563
+ sku: selectedGiftProduct.sku
564
+ },
565
+ quantity: reward?.get_unit || 1,
566
+ attributes: [
567
+ {
568
+ key: CUSTOMER_ATTRIBUTE_KEY,
569
+ value: JSON.stringify({
570
+ is_gift: true,
571
+ rule_id: activeCampaign.rule_id,
572
+ spend_sum_money: actualThreshold,
573
+ // 使用实际的门槛金额(多币种支持)
574
+ currency_code: currentCurrency
575
+ // 记录当前币种
576
+ })
577
+ }
578
+ ]
579
+ };
580
+ }).filter((item) => item !== null);
581
+ const formattedGift = {
582
+ tier: qualifyingTier,
583
+ itemsToAdd
584
+ };
585
+ return formattedGift;
586
+ }, [qualifyingTier, activeCampaign, finalGiftProductsResult, actualThreshold, currentCurrency]);
540
587
  return {
541
588
  qualifyingGift,
542
589
  nextTierGoal,
@@ -550,7 +597,8 @@ var useScriptAutoFreeGift = ({
550
597
  _giveaway,
551
598
  cart,
552
599
  locale: providedLocale,
553
- lines
600
+ lines,
601
+ profile
554
602
  }) => {
555
603
  const { client, locale: contextLocale } = useShopify();
556
604
  const locale = providedLocale || contextLocale;
@@ -574,8 +622,9 @@ var useScriptAutoFreeGift = ({
574
622
  const utmCampaign = Cookies5.get("utm_campaign") || query?.utm_campaign;
575
623
  if (campaign.activityAvailableQuery && !utmCampaign?.includes(campaign.activityAvailableQuery))
576
624
  return false;
625
+ if (campaign.requireLogin && !profile?.email) return false;
577
626
  return true;
578
- }, [campaign]);
627
+ }, [campaign, profile]);
579
628
  const [upgrade_multiple, upgrade_value] = useMemo(() => {
580
629
  let upgrade_multiple2 = 1;
581
630
  let upgrade_value2 = 0;
@@ -583,12 +632,14 @@ var useScriptAutoFreeGift = ({
583
632
  upgrade_multiple2 = 1.2;
584
633
  upgrade_value2 = 40;
585
634
  }
586
- effectiveCart?.lineItems?.forEach(({ customAttributes }) => {
587
- customAttributes?.forEach(({ key, value }) => {
588
- if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
589
- if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
590
- });
591
- });
635
+ effectiveCart?.lineItems?.forEach(
636
+ ({ customAttributes }) => {
637
+ customAttributes?.forEach(({ key, value }) => {
638
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
639
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
640
+ });
641
+ }
642
+ );
592
643
  return [upgrade_multiple2, upgrade_value2];
593
644
  }, [effectiveCart?.lineItems, points_subscribe]);
594
645
  const breakpoints = useMemo(() => {
@@ -653,18 +704,24 @@ var useScriptAutoFreeGift = ({
653
704
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
654
705
  return [currentLevel, nextLevel];
655
706
  }, [breakpoints, involvedSubTotal, involvedLines.length]);
656
- const { data: giftProductsResult } = useSWR(shouldFetch ? giftHandles : null, async () => {
657
- const res = await getProductsByHandles(client, {
658
- handles: giftHandles,
659
- locale
660
- });
661
- const result = Array.isArray(res) ? res : [];
662
- giftProductsCache.current = {
663
- data: result,
664
- giftHandles: [...giftHandles]
665
- };
666
- return result;
667
- });
707
+ const { data: giftProductsResult } = useSWR(
708
+ shouldFetch ? giftHandles : null,
709
+ async () => {
710
+ const res = await getProductsByHandles(client, {
711
+ handles: giftHandles,
712
+ locale
713
+ });
714
+ const result = Array.isArray(res) ? res : [];
715
+ giftProductsCache.current = {
716
+ data: result,
717
+ giftHandles: [...giftHandles]
718
+ };
719
+ return result;
720
+ },
721
+ {
722
+ revalidateOnFocus: false
723
+ }
724
+ );
668
725
  const finalGiftProductsResult = useMemo(() => {
669
726
  if (giftProductsCache.current && !shouldFetch) {
670
727
  return giftProductsCache.current.data || void 0;
@@ -696,7 +753,20 @@ var useScriptAutoFreeGift = ({
696
753
  giftProductsResult: finalGiftProductsResult
697
754
  };
698
755
  };
699
- function useCreateCart(options) {
756
+
757
+ // src/hooks/cart/utils/cart-attributes.ts
758
+ var checkAttributesUpdateNeeded = (oldAttributes, newAttributes, customAttributesNeedRemove) => {
759
+ return newAttributes.some((attr) => !oldAttributes.some((oldAttr) => oldAttr.key === attr.key)) || oldAttributes.some((attr) => {
760
+ const newAttr = newAttributes.find((newAttr2) => newAttr2.key === attr.key);
761
+ return newAttr ? newAttr.value !== attr.value : true;
762
+ }) || customAttributesNeedRemove.some(
763
+ (removeAttr) => oldAttributes.some((oldAttr) => oldAttr.key === removeAttr.key)
764
+ );
765
+ };
766
+ function useCreateCart({
767
+ updateCookie = false,
768
+ options
769
+ }) {
700
770
  const { client, locale, cartCookieAdapter } = useShopify();
701
771
  const { mutateCart, metafieldIdentifiers } = useCartContext();
702
772
  const createNewCart = useCallback(
@@ -704,7 +774,8 @@ function useCreateCart(options) {
704
774
  let newCart = await createCart(client, {
705
775
  ...arg,
706
776
  metafieldIdentifiers,
707
- cookieAdapter: cartCookieAdapter
777
+ cookieAdapter: cartCookieAdapter,
778
+ updateCookie
708
779
  });
709
780
  if (newCart) {
710
781
  const unApplicableCodes = newCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
@@ -731,11 +802,23 @@ function useAddCartLines(options) {
731
802
  const { mutateCart, metafieldIdentifiers } = useCartContext();
732
803
  const addLines = useCallback(
733
804
  async (_key, { arg }) => {
734
- let updatedCart = await addCartLines(client, {
735
- ...arg,
736
- metafieldIdentifiers,
737
- cookieAdapter: cartCookieAdapter
738
- });
805
+ const { cartId, lines } = arg;
806
+ const id = cartId || cartCookieAdapter?.getCartId(locale);
807
+ let updatedCart;
808
+ if (!id) {
809
+ updatedCart = await createCart(client, {
810
+ lines,
811
+ metafieldIdentifiers,
812
+ cookieAdapter: cartCookieAdapter
813
+ });
814
+ } else {
815
+ updatedCart = await addCartLines(client, {
816
+ cartId: id,
817
+ lines,
818
+ metafieldIdentifiers,
819
+ cookieAdapter: cartCookieAdapter
820
+ });
821
+ }
739
822
  if (updatedCart) {
740
823
  const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
741
824
  if (unApplicableCodes.length > 0) {
@@ -782,7 +865,7 @@ var trackAddToCartGA = ({
782
865
  const currencyCode = variant.product?.price?.currencyCode;
783
866
  const totalPrice = lineItems?.reduce(
784
867
  (prev, { variant: variant2 }) => prev.plus(
785
- variant2?.finalPrice?.amount ?? variant2?.compareAtPrice?.amount ?? variant2?.price?.amount ?? 0
868
+ variant2?.finalPrice?.amount === void 0 ? Number(variant2?.price?.amount) || 0 : Number(variant2?.finalPrice?.amount) || 0
786
869
  ),
787
870
  new Decimal2(0)
788
871
  ).toNumber();
@@ -817,7 +900,7 @@ var trackBeginCheckoutGA = ({
817
900
  }
818
901
  const totalPrice = lineItems?.reduce(
819
902
  (prev, { variant }) => prev.plus(
820
- variant?.finalPrice?.amount ?? variant?.compareAtPrice?.amount ?? variant?.price?.amount ?? 0
903
+ variant?.finalPrice?.amount === void 0 ? Number(variant?.price?.amount) || 0 : Number(variant?.finalPrice?.amount) || 0
821
904
  ),
822
905
  new Decimal2(0)
823
906
  ).toNumber();
@@ -850,10 +933,10 @@ var trackBuyNowGA = ({
850
933
  return;
851
934
  }
852
935
  const { variant } = lineItems[0];
853
- const currencyCode = variant.price?.currencyCode;
936
+ const currencyCode = variant.product?.price?.currencyCode || variant.price?.currencyCode;
854
937
  const totalPrice = lineItems?.reduce(
855
938
  (prev, { variant: variant2 }) => prev.plus(
856
- variant2?.finalPrice?.amount ?? variant2?.compareAtPrice?.amount ?? (variant2?.price?.amount || 0)
939
+ variant2?.finalPrice?.amount === void 0 ? Number(variant2?.price?.amount) || 0 : Number(variant2?.finalPrice?.amount) || 0
857
940
  ),
858
941
  new Decimal2(0)
859
942
  ).toNumber();
@@ -927,7 +1010,7 @@ function useApplyCartCodes(options) {
927
1010
  if (!discountCodes?.length) {
928
1011
  throw new Error("Invalid input used for this operation: Miss discountCode");
929
1012
  }
930
- const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
1013
+ const cartId = providedCartId || cart?.id;
931
1014
  if (!cartId) {
932
1015
  return void 0;
933
1016
  }
@@ -940,12 +1023,18 @@ function useApplyCartCodes(options) {
940
1023
  cookieAdapter: cartCookieAdapter,
941
1024
  metafieldIdentifiers
942
1025
  });
1026
+ const unApplicableCodes = discountCodes.filter(
1027
+ (code) => updatedCart?.discountCodes?.find((item) => item.code === code && !item.applicable)
1028
+ );
1029
+ if (unApplicableCodes.length) {
1030
+ throw new Error(`${unApplicableCodes.join(", ")} is not applicable to the cart`);
1031
+ }
943
1032
  if (updatedCart) {
944
1033
  mutateCart(updatedCart);
945
1034
  }
946
1035
  return updatedCart;
947
1036
  },
948
- [client, locale, cartCookieAdapter, mutateCart, cart]
1037
+ [client, locale, cartCookieAdapter, mutateCart, cart, metafieldIdentifiers]
949
1038
  );
950
1039
  return useSWRMutation("apply-codes", applyCodes, options);
951
1040
  }
@@ -955,7 +1044,7 @@ function useRemoveCartCodes(options) {
955
1044
  const removeCodes = useCallback(
956
1045
  async (_key, { arg }) => {
957
1046
  const { cartId: providedCartId, discountCodes } = arg;
958
- const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
1047
+ const cartId = providedCartId || cart?.id;
959
1048
  const codes = cart?.discountCodes?.filter((code) => !!code.applicable) || [];
960
1049
  const leftCodes = codes.filter((code) => discountCodes?.length ? !discountCodes.includes(code.code) : code.code).map((code) => code.code);
961
1050
  const updatedCart = await updateCartCodes(client, {
@@ -969,225 +1058,96 @@ function useRemoveCartCodes(options) {
969
1058
  }
970
1059
  return updatedCart;
971
1060
  },
972
- [client, locale, cartCookieAdapter, mutateCart, cart]
1061
+ [client, locale, cartCookieAdapter, mutateCart, cart, metafieldIdentifiers]
973
1062
  );
974
1063
  return useSWRMutation("remove-codes", removeCodes, options);
975
1064
  }
976
-
977
- // src/hooks/cart/use-add-to-cart.ts
978
- function useAddToCart({ withTrack = true } = {}, swrOptions) {
979
- const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
980
- const { cart } = useCartContext();
981
- const { trigger: applyCartCodes } = useApplyCartCodes();
982
- const { trigger: removeInvalidCodes } = useRemoveCartCodes();
983
- const { trigger: addCartLines2 } = useAddCartLines();
984
- const addToCart = useCallback(
985
- async (_key, { arg }) => {
986
- const {
987
- lineItems,
988
- cartId: providedCartId,
989
- discountCodes,
990
- gtmParams = {},
991
- buyerIdentity,
992
- needCreateCart = false,
993
- onCodesInvalid,
994
- replaceExistingCodes
995
- } = arg;
996
- if (!lineItems || lineItems.length === 0) {
997
- return;
998
- }
999
- const lines = lineItems.map((item) => ({
1000
- merchandiseId: item.variant?.id || "",
1001
- quantity: item.quantity || 1,
1002
- attributes: item.attributes,
1003
- sellingPlanId: item.sellingPlanId
1004
- })).filter((item) => item.merchandiseId && item.quantity);
1005
- if (lines.length === 0) {
1006
- return;
1007
- }
1008
- const cartId = needCreateCart ? void 0 : providedCartId || cart?.id;
1009
- let resultCart = await addCartLines2({
1010
- cartId,
1011
- lines,
1012
- buyerIdentity
1013
- });
1014
- if (!resultCart) {
1015
- return void 0;
1016
- }
1017
- console.log("npm addCartLines resultCart", resultCart);
1018
- if (resultCart.discountCodes && resultCart.discountCodes.length > 0) {
1019
- const unapplicableCodes = resultCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
1020
- if (unapplicableCodes.length > 0) {
1021
- if (onCodesInvalid) {
1022
- const handledCart = await onCodesInvalid(resultCart, unapplicableCodes);
1023
- if (handledCart) {
1024
- resultCart = handledCart;
1025
- }
1026
- } else {
1027
- await removeInvalidCodes({
1028
- discountCodes: unapplicableCodes
1029
- });
1030
- }
1031
- }
1032
- }
1033
- if (discountCodes && discountCodes.length > 0) {
1034
- applyCartCodes({
1035
- replaceExistingCodes,
1036
- discountCodes
1037
- });
1038
- }
1039
- if (withTrack) {
1040
- trackAddToCartGA({
1041
- lineItems,
1042
- gtmParams: { ...gtmParams, brand: config.getBrand() }
1043
- });
1044
- trackAddToCartFBQ({ lineItems });
1045
- }
1046
- return resultCart;
1047
- },
1048
- [client, locale, cartCookieAdapter, userAdapter, cart, withTrack]
1065
+ var initSameLinesAttributes = ({
1066
+ cart,
1067
+ line
1068
+ }) => {
1069
+ const sameLineInCart = cart?.lineItems.find(
1070
+ (lineInCart) => lineInCart.variant.sku === line.variant?.sku && lineInCart.product?.handle === line.variant?.product?.handle
1049
1071
  );
1050
- return useSWRMutation("add-to-cart", addToCart, swrOptions);
1051
- }
1052
- function useUpdateCartLines(options) {
1053
- const { client, locale, cartCookieAdapter } = useShopify();
1054
- const { mutateCart, metafieldIdentifiers } = useCartContext();
1055
- const updateLines = useCallback(
1056
- async (_key, { arg }) => {
1057
- const updatedCart = await updateCartLines(client, {
1058
- ...arg,
1059
- metafieldIdentifiers,
1060
- cookieAdapter: cartCookieAdapter
1061
- });
1062
- if (updatedCart) {
1063
- mutateCart(updatedCart);
1064
- }
1065
- return updatedCart;
1066
- },
1067
- [client, locale, cartCookieAdapter, mutateCart]
1072
+ const codeAmountAttribute = sameLineInCart?.customAttributes?.find(
1073
+ (attr) => attr.key === CODE_AMOUNT_KEY
1068
1074
  );
1069
- return useSWRMutation("update-cart-lines", updateLines, options);
1070
- }
1071
- function useRemoveCartLines(options) {
1072
- const { client, locale, cartCookieAdapter } = useShopify();
1073
- const { mutateCart, metafieldIdentifiers } = useCartContext();
1074
- const removeLines = useCallback(
1075
- async (_key, { arg }) => {
1076
- const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
1077
- let updatedCart = await removeCartLines(client, {
1078
- cartId,
1079
- lineIds,
1080
- metafieldIdentifiers,
1081
- cookieAdapter: cartCookieAdapter
1082
- });
1083
- if (updatedCart && autoRemoveInvalidCodes) {
1084
- const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
1085
- if (unApplicableCodes.length > 0) {
1086
- if (onCodesRemoved) {
1087
- const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
1088
- if (handledCart) {
1089
- updatedCart = handledCart;
1090
- }
1091
- } else {
1092
- updatedCart = await updateCartCodes(client, {
1093
- cartId: updatedCart.id,
1094
- discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
1095
- metafieldIdentifiers,
1096
- cookieAdapter: cartCookieAdapter
1097
- }) || updatedCart;
1098
- }
1099
- }
1100
- }
1101
- if (updatedCart) {
1102
- mutateCart(updatedCart);
1075
+ const scriptCodeAmountAttribute = sameLineInCart?.customAttributes?.find(
1076
+ (attr) => attr.key === SCRIPT_CODE_AMOUNT_KEY
1077
+ );
1078
+ let functionAttribute = null;
1079
+ try {
1080
+ functionAttribute = sameLineInCart?.customAttributes?.find(
1081
+ (attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY && JSON.parse(attr.value)?.discounted_amount
1082
+ );
1083
+ } catch (error) {
1084
+ }
1085
+ if (codeAmountAttribute || functionAttribute || scriptCodeAmountAttribute) {
1086
+ return {
1087
+ ...line,
1088
+ attributes: [
1089
+ ...line.attributes || [],
1090
+ codeAmountAttribute,
1091
+ functionAttribute,
1092
+ scriptCodeAmountAttribute
1093
+ ].filter(Boolean)
1094
+ };
1095
+ }
1096
+ return line;
1097
+ };
1098
+ var initDiscountAttributes = ({ line }) => {
1099
+ let itemAttributes = line.attributes || [];
1100
+ const functionEnvAttribute = itemAttributes.find((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY);
1101
+ if (!functionEnvAttribute) {
1102
+ itemAttributes = itemAttributes.concat([
1103
+ {
1104
+ key: CUSTOMER_ATTRIBUTE_KEY,
1105
+ value: JSON.stringify({
1106
+ is_gift: false,
1107
+ discounted_amount: line.variant?.finalPrice?.amount === void 0 ? Number(line.variant?.price?.amount) * (line.quantity || 1) : Number(line.variant?.finalPrice?.amount) * (line.quantity || 1)
1108
+ })
1103
1109
  }
1104
- return updatedCart;
1105
- },
1106
- [client, locale, cartCookieAdapter, mutateCart]
1110
+ ]);
1111
+ }
1112
+ const memberPriceAttribute = itemAttributes.find(
1113
+ (attr) => attr.key === MEMBER_PRICE_ATTRIBUTE_KEY
1107
1114
  );
1108
- return useSWRMutation("remove-cart-lines", removeLines, options);
1109
- }
1110
- function useUpdateCartAttributes(mutate, metafieldIdentifiers, options) {
1111
- const { client, locale, cartCookieAdapter } = useShopify();
1112
- const updateAttributes = useCallback(
1113
- async (_key, { arg }) => {
1114
- const updatedCart = await updateCartAttributes(client, {
1115
- ...arg,
1116
- metafieldIdentifiers,
1117
- cookieAdapter: cartCookieAdapter
1118
- });
1119
- console.log("useUpdateCartAttributes updatedCart", updatedCart);
1120
- if (updatedCart) {
1121
- mutate(updatedCart);
1115
+ const coupon = line.coupon;
1116
+ if (!memberPriceAttribute && coupon) {
1117
+ itemAttributes = itemAttributes.concat([
1118
+ {
1119
+ key: MEMBER_PRICE_ATTRIBUTE_KEY,
1120
+ value: JSON.stringify({ code: coupon.code })
1122
1121
  }
1123
- return updatedCart;
1124
- },
1125
- [client, locale, cartCookieAdapter, mutate]
1122
+ ]);
1123
+ }
1124
+ const couponDiscountAttribute = itemAttributes.find(
1125
+ (attr) => attr.key === CODE_AMOUNT_KEY || attr.key === SCRIPT_CODE_AMOUNT_KEY
1126
1126
  );
1127
- return useSWRMutation("update-cart-attributes", updateAttributes, options);
1128
- }
1129
- function useBuyNow({ withTrack = true } = {}, swrOptions) {
1130
- const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
1131
- const isLoggedIn = userAdapter?.isLoggedIn || false;
1132
- const buyNow = useCallback(
1133
- async (_key, { arg }) => {
1134
- const {
1135
- lineItems,
1136
- discountCodes,
1137
- gtmParams = {},
1138
- buyerIdentity,
1139
- fbqTrackConfig,
1140
- customAttributes,
1141
- metafieldIdentifiers,
1142
- redirectToCheckout
1143
- } = arg;
1144
- if (!lineItems || lineItems.length === 0) {
1145
- return;
1146
- }
1147
- const lines = lineItems.map((item) => ({
1148
- merchandiseId: item.variant?.id || "",
1149
- quantity: item.quantity || 1,
1150
- attributes: item.attributes,
1151
- sellingPlanId: item.sellingPlanId
1152
- })).filter((item) => item.merchandiseId && item.quantity);
1153
- if (lines.length === 0) {
1154
- return;
1155
- }
1156
- const resultCart = await createCart(client, {
1157
- lines,
1158
- metafieldIdentifiers,
1159
- cookieAdapter: cartCookieAdapter,
1160
- buyerIdentity,
1161
- discountCodes,
1162
- customAttributes
1163
- });
1164
- if (!resultCart) {
1165
- throw new Error("Failed to create cart for buy now");
1166
- }
1167
- if (withTrack && resultCart.lineItems) {
1168
- trackBuyNowGA({
1169
- lineItems,
1170
- gtmParams: { ...gtmParams, brand: config.getBrand() }
1171
- });
1172
- if (fbqTrackConfig) {
1173
- trackBuyNowFBQ({ trackConfig: fbqTrackConfig });
1174
- }
1175
- }
1176
- if (redirectToCheckout) {
1177
- if (resultCart.url) {
1178
- if (typeof window !== "undefined") {
1179
- window.location.href = resultCart.url;
1180
- }
1181
- } else {
1182
- throw new Error("Failed to get checkout URL");
1183
- }
1127
+ if (!couponDiscountAttribute && coupon && Number(coupon?.amount) > 0) {
1128
+ itemAttributes = itemAttributes.concat([
1129
+ {
1130
+ key: CODE_AMOUNT_KEY,
1131
+ value: new Decimal2(coupon.amount).times(line.quantity || 1).toString()
1132
+ },
1133
+ {
1134
+ key: SCRIPT_CODE_AMOUNT_KEY,
1135
+ value: new Decimal2(coupon.amount).times(line.quantity || 1).toString()
1184
1136
  }
1185
- return resultCart;
1186
- },
1187
- [client, locale, isLoggedIn, cartCookieAdapter, withTrack]
1188
- );
1189
- return useSWRMutation("buy-now", buyNow, swrOptions);
1190
- }
1137
+ ]);
1138
+ }
1139
+ return { ...line, attributes: itemAttributes };
1140
+ };
1141
+ var getLinesWithAttributes = ({
1142
+ cart,
1143
+ lineItems
1144
+ }) => {
1145
+ return lineItems.map((line) => {
1146
+ const sameLine = initSameLinesAttributes({ cart, line });
1147
+ const functionLine = initDiscountAttributes({ line: sameLine });
1148
+ return functionLine;
1149
+ });
1150
+ };
1191
1151
  function useCalcGiftsFromLines({
1192
1152
  lines,
1193
1153
  customer,
@@ -1204,17 +1164,41 @@ function useCalcGiftsFromLines({
1204
1164
  lines
1205
1165
  });
1206
1166
  const allGiftLines = useMemo(() => {
1207
- const functionGiftLines = functionGift.qualifyingGift?.itemsToAdd || [];
1208
- const scriptGiftLines = scriptGift.freeGiftLevel ? scriptGift.freeGiftLevel.giveawayProducts.map((product) => {
1209
- const giftProduct = scriptGift.giftProductsResult?.find(
1210
- (p) => p.handle === product.handle
1167
+ const functionGiftLines = (functionGift.qualifyingGift?.itemsToAdd || []).map((item) => {
1168
+ const product = functionGift.giftProductsResult?.find(
1169
+ (product2) => product2.handle === item.variant.handle
1170
+ );
1171
+ const variants = product?.variants;
1172
+ const variant = Array.isArray(variants) ? variants.find((v) => v.sku === item.variant.sku) : void 0;
1173
+ if (!variant) {
1174
+ console.warn(
1175
+ `Function gift: Variant not found for handle=${item.variant.handle}, sku=${item.variant.sku}`
1176
+ );
1177
+ return null;
1178
+ }
1179
+ return {
1180
+ variant: {
1181
+ ...variant,
1182
+ product
1183
+ },
1184
+ quantity: item.quantity ?? 1,
1185
+ attributes: item.attributes
1186
+ };
1187
+ }).filter((item) => item !== null);
1188
+ const scriptGiftLines = scriptGift.freeGiftLevel ? scriptGift.freeGiftLevel.giveawayProducts.map((item) => {
1189
+ const product = scriptGift.giftProductsResult?.find(
1190
+ (product2) => product2.handle === item.handle
1211
1191
  );
1212
- const variant = giftProduct?.variants?.[0];
1192
+ const variants = product?.variants;
1193
+ const variant = Array.isArray(variants) ? variants.find((v) => v.sku === item.sku) : void 0;
1194
+ if (!variant) {
1195
+ console.warn(`Script gift: Variant not found for handle=${item.handle}, sku=${item.sku}`);
1196
+ return null;
1197
+ }
1213
1198
  return {
1214
1199
  variant: {
1215
- id: variant?.id || "",
1216
- handle: product.handle,
1217
- sku: product.sku
1200
+ ...variant,
1201
+ product
1218
1202
  },
1219
1203
  quantity: 1,
1220
1204
  attributes: [
@@ -1224,10 +1208,11 @@ function useCalcGiftsFromLines({
1224
1208
  }
1225
1209
  ]
1226
1210
  };
1227
- }).filter((item) => item.variant.id) : [];
1211
+ }).filter((item) => item !== null) : [];
1228
1212
  return [...functionGiftLines, ...scriptGiftLines];
1229
1213
  }, [
1230
1214
  functionGift.qualifyingGift,
1215
+ functionGift.giftProductsResult,
1231
1216
  scriptGift.freeGiftLevel,
1232
1217
  scriptGift.giftProductsResult,
1233
1218
  scriptGiveawayKey
@@ -1262,7 +1247,7 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1262
1247
  const isCustomerLoading = useMemo(() => !customer ? true : false, [customer]);
1263
1248
  const dealsType = "";
1264
1249
  const { activeCampaign, subtotal } = useMemo(() => {
1265
- for (const campaign of orderDiscountConfig) {
1250
+ for (const campaign of orderDiscountConfig || []) {
1266
1251
  const { rule_conditions = [], result_detail } = campaign;
1267
1252
  const { main_product, order_discount_conf } = result_detail || {};
1268
1253
  const isPreCheckPassed = preCheck(rule_conditions, tags, []);
@@ -1292,9 +1277,12 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1292
1277
  discountAmount: 0
1293
1278
  };
1294
1279
  }
1295
- const tieredDiscounts = activeCampaign.result_detail.order_discount_conf.tiered_discounts;
1296
- const qualifyingTier = [...tieredDiscounts].reverse().find((tier) => subtotal >= Number(tier.amount));
1297
- const nextGoal = tieredDiscounts.find((tier) => subtotal < Number(tier.amount));
1280
+ const currentCurrency = cart?.currency?.code || "";
1281
+ console.log("currentCurrency", cart, currentCurrency);
1282
+ const orderDiscountConf = activeCampaign.result_detail.order_discount_conf;
1283
+ const tieredDiscounts = orderDiscountConf.tiered_discounts_markets?.[currentCurrency] || orderDiscountConf.tiered_discounts;
1284
+ const qualifyingTier = [...tieredDiscounts].sort((a, b) => Number(b.amount) - Number(a.amount)).find((tier) => subtotal >= Number(tier.amount));
1285
+ const nextGoal = [...tieredDiscounts].sort((a, b) => Number(a.amount) - Number(b.amount)).find((tier) => subtotal < Number(tier.amount));
1298
1286
  if (!qualifyingTier) {
1299
1287
  return {
1300
1288
  qualifyingDiscount: null,
@@ -1331,43 +1319,10 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1331
1319
  isLoading: isCustomerLoading
1332
1320
  };
1333
1321
  };
1334
- function useHasPlusMemberInCart({
1335
- memberSetting,
1336
- cart
1337
- }) {
1338
- const { plus_monthly_product, plus_annual_product } = memberSetting || {};
1339
- return useMemo(() => {
1340
- if (!cart?.lineItems) {
1341
- return {
1342
- hasPlusMember: false,
1343
- hasMonthlyPlus: false,
1344
- hasAnnualPlus: false
1345
- };
1346
- }
1347
- const monthlyPlusItem = cart.lineItems.find(
1348
- (item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
1349
- );
1350
- const annualPlusItem = cart.lineItems.find(
1351
- (item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
1352
- );
1353
- const hasMonthlyPlus = !!monthlyPlusItem;
1354
- const hasAnnualPlus = !!annualPlusItem;
1355
- const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
1356
- return {
1357
- hasPlusMember,
1358
- hasMonthlyPlus,
1359
- hasAnnualPlus,
1360
- monthlyPlusItem,
1361
- annualPlusItem
1362
- };
1363
- }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
1364
- }
1365
-
1366
- // src/hooks/cart/feature/use-cart-attributes.ts
1367
1322
  var getReferralAttributes = () => {
1368
- const inviteCode = Cookies5.get("invite_code");
1369
- const playModeId = Cookies5.get("playModeId");
1370
- const popup = Cookies5.get("_popup");
1323
+ const inviteCode = getLocalStorage("inviteCode") || Cookies5.get("inviteCode");
1324
+ const playModeId = getLocalStorage("playModeId") || Cookies5.get("playModeId");
1325
+ const popup = getLocalStorage("_popup") || Cookies5.get("_popup");
1371
1326
  if (inviteCode && playModeId) {
1372
1327
  return popup ? [
1373
1328
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -1380,117 +1335,130 @@ var getReferralAttributes = () => {
1380
1335
  }
1381
1336
  return [];
1382
1337
  };
1338
+ var getUserType = (customer) => {
1339
+ let userInfo = Cookies5.get("userInfo");
1340
+ if (userInfo) {
1341
+ userInfo = JSON.parse(userInfo);
1342
+ let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
1343
+ userInfo.setId = arr[arr.length - 1];
1344
+ }
1345
+ const customerInfo = userInfo || customer;
1346
+ if (!customerInfo) {
1347
+ return "new_user_unlogin";
1348
+ }
1349
+ if (customer) {
1350
+ const { orders = {} } = customer;
1351
+ if (orders?.edges?.length === 1) {
1352
+ return "old_user_orders_once";
1353
+ } else if (orders?.edges?.length > 1) {
1354
+ return "old_user_orders_twice";
1355
+ }
1356
+ }
1357
+ return "new_user_login";
1358
+ };
1359
+ function getCartAttributes({
1360
+ profile,
1361
+ customer,
1362
+ cart,
1363
+ memberType,
1364
+ currentUrl = ""
1365
+ }) {
1366
+ const userType = getUserType(customer);
1367
+ const memberAttributes = [
1368
+ {
1369
+ key: "_token",
1370
+ value: profile?.token
1371
+ },
1372
+ {
1373
+ key: "_member_type",
1374
+ value: memberType ?? String(profile?.memberType)
1375
+ },
1376
+ {
1377
+ key: "_user_type",
1378
+ value: userType
1379
+ },
1380
+ {
1381
+ key: "_is_login",
1382
+ value: profile?.token ? "true" : "false"
1383
+ }
1384
+ ];
1385
+ if (profile?.token) {
1386
+ memberAttributes.push({
1387
+ key: "_login_user",
1388
+ value: "1"
1389
+ });
1390
+ }
1391
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
1392
+ const functionAttributes = [
1393
+ {
1394
+ key: CUSTOMER_ATTRIBUTE_KEY,
1395
+ value: JSON.stringify({
1396
+ discount_code: discountCodes,
1397
+ user_tags: customer?.tags || []
1398
+ })
1399
+ }
1400
+ ];
1401
+ const presellAttributes = [
1402
+ {
1403
+ key: "_presale",
1404
+ value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
1405
+ }
1406
+ ];
1407
+ const weightAttributes = [
1408
+ {
1409
+ key: "_weight",
1410
+ value: cart?.lineItems.reduce((acc, item) => {
1411
+ return new Decimal2(acc).plus(item.variant.weight ?? 0).toNumber();
1412
+ }, 0).toString()
1413
+ },
1414
+ {
1415
+ key: "_app_source_name",
1416
+ value: "dtc"
1417
+ }
1418
+ ];
1419
+ const trackingAttributes = [
1420
+ {
1421
+ key: "utm_params",
1422
+ value: currentUrl
1423
+ }
1424
+ ];
1425
+ const commonAttributes = [
1426
+ ...memberAttributes,
1427
+ ...functionAttributes,
1428
+ ...presellAttributes,
1429
+ ...weightAttributes,
1430
+ ...trackingAttributes,
1431
+ ...getReferralAttributes()
1432
+ ].filter((item) => item?.value);
1433
+ const extraAttributesInCart = cart?.customAttributes?.filter(
1434
+ (item) => !commonAttributes.some((attr) => attr.key === item.key)
1435
+ ) || [];
1436
+ return [...commonAttributes, ...extraAttributesInCart].filter((item) => item?.value);
1437
+ }
1383
1438
  var useCartAttributes = ({
1384
1439
  profile,
1385
1440
  customer,
1386
1441
  cart,
1387
- memberSetting
1442
+ memberType
1388
1443
  }) => {
1389
1444
  const [currentUrl, setCurrentUrl] = useState("");
1390
- const { hasPlusMember } = useHasPlusMemberInCart({
1391
- memberSetting,
1392
- cart
1393
- });
1394
1445
  useEffect(() => {
1395
1446
  setCurrentUrl(window.location.href);
1396
1447
  }, []);
1397
- const userType = useMemo(() => {
1398
- let userInfo = Cookies5.get("userInfo");
1399
- if (userInfo) {
1400
- userInfo = JSON.parse(userInfo);
1401
- let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
1402
- userInfo.setId = arr[arr.length - 1];
1403
- }
1404
- const customerInfo = userInfo || customer;
1405
- if (!customerInfo) {
1406
- return "new_user_unlogin";
1407
- }
1408
- if (customer) {
1409
- const { orders = {} } = customer;
1410
- if (orders?.edges?.length === 1) {
1411
- return "old_user_orders_once";
1412
- } else if (orders?.edges?.length > 1) {
1413
- return "old_user_orders_twice";
1414
- }
1415
- }
1416
- return "new_user_login";
1417
- }, [customer]);
1418
- const memberAttributes = useMemo(() => {
1419
- return [
1420
- {
1421
- key: "_token",
1422
- value: profile?.token
1423
- //是否登录
1424
- },
1425
- {
1426
- key: "_member_type",
1427
- value: hasPlusMember ? "2" : profile?.memberType
1428
- //:0(游客),1(普通会员),2(付费会员)
1429
- },
1430
- {
1431
- key: "_user_type",
1432
- value: userType
1433
- // n
1434
- },
1435
- {
1436
- key: "_is_login",
1437
- value: profile?.token ? "true" : "false"
1438
- }
1439
- ];
1440
- }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
1441
- const functionAttributes = useMemo(() => {
1442
- return [
1443
- cart?.discountCodes && {
1444
- key: "_discounts_function_env",
1445
- value: JSON.stringify({
1446
- discount_code: cart?.discountCodes.map((item) => item.code),
1447
- user_tags: customer?.tags || []
1448
- })
1449
- }
1450
- ];
1451
- }, [cart]);
1452
- const presellAttributes = useMemo(() => {
1453
- return [
1454
- {
1455
- key: "_presale",
1456
- value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
1457
- }
1458
- ];
1459
- }, [cart]);
1460
- const weightAttributes = useMemo(() => {
1461
- return [
1462
- {
1463
- key: "_weight",
1464
- value: cart?.lineItems.reduce((acc, item) => {
1465
- return new Decimal2(acc).plus(item.variant.weight ?? 0).toNumber();
1466
- }, 0).toString()
1467
- },
1468
- {
1469
- key: "_app_source_name",
1470
- value: "dtc"
1471
- }
1472
- ];
1473
- }, [cart]);
1474
- const trackingAttributes = useMemo(() => {
1475
- return [
1476
- {
1477
- key: "utm_params",
1478
- value: currentUrl
1479
- }
1480
- ];
1481
- }, [currentUrl]);
1448
+ const attributes = useMemo(() => {
1449
+ return getCartAttributes({
1450
+ profile,
1451
+ customer,
1452
+ cart,
1453
+ memberType,
1454
+ currentUrl
1455
+ });
1456
+ }, [profile, customer, cart, memberType, currentUrl]);
1482
1457
  return useMemo(
1483
1458
  () => ({
1484
- attributes: [
1485
- ...memberAttributes,
1486
- ...functionAttributes,
1487
- ...presellAttributes,
1488
- ...weightAttributes,
1489
- ...trackingAttributes,
1490
- ...getReferralAttributes()
1491
- ].filter((item) => item?.value)
1459
+ attributes
1492
1460
  }),
1493
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
1461
+ [attributes]
1494
1462
  );
1495
1463
  };
1496
1464
  var DEFAULT_MIN = 1;
@@ -1553,7 +1521,7 @@ var useUpdateLineCodeAmountAttributes = ({
1553
1521
  );
1554
1522
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
1555
1523
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
1556
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
1524
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
1557
1525
  attrNeedUpdate.push({
1558
1526
  key: CUSTOMER_ATTRIBUTE_KEY,
1559
1527
  value: JSON.stringify({
@@ -1592,29 +1560,22 @@ var useUpdateLineCodeAmountAttributes = ({
1592
1560
  }).filter(
1593
1561
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
1594
1562
  ).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
1563
+ let lineId = line.id;
1564
+ let attributes = line.customAttributes || [];
1565
+ if (attrNeedDelete.length) {
1566
+ attributes = attributes.filter(
1567
+ (attr) => !attrNeedDelete.includes(attr.key)
1568
+ );
1569
+ }
1595
1570
  if (attrNeedUpdate.length) {
1596
- return {
1597
- id: line.id,
1598
- attributes: [
1599
- ...line.customAttributes?.filter(
1600
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
1601
- ) || [],
1602
- ...attrNeedUpdate
1603
- ]
1604
- };
1605
- } else if (attrNeedDelete.length) {
1606
- return {
1607
- id: line.id,
1608
- attributes: line.customAttributes?.filter(
1609
- (attr) => !attrNeedDelete.includes(attr.key)
1610
- ) || []
1611
- };
1612
- } else {
1613
- return {
1614
- id: line.id,
1615
- attributes: line.customAttributes || []
1616
- };
1571
+ attributes = attributes.filter(
1572
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
1573
+ ).concat(attrNeedUpdate);
1617
1574
  }
1575
+ return {
1576
+ id: lineId,
1577
+ attributes
1578
+ };
1618
1579
  }),
1619
1580
  [cart?.lineItems, mainProductDiscountCodes]
1620
1581
  );
@@ -1649,45 +1610,61 @@ var useUpdateLineCodeAmountAttributes = ({
1649
1610
  }, [loading, setLoadingState]);
1650
1611
  };
1651
1612
 
1652
- // src/hooks/cart/types/price-discount.ts
1653
- var PriceDiscountType = /* @__PURE__ */ ((PriceDiscountType2) => {
1654
- PriceDiscountType2[PriceDiscountType2["PERCENTAGE"] = 1] = "PERCENTAGE";
1655
- PriceDiscountType2[PriceDiscountType2["FIXED_AMOUNT"] = 2] = "FIXED_AMOUNT";
1656
- return PriceDiscountType2;
1657
- })(PriceDiscountType || {});
1658
- var PriceBasePriceType = /* @__PURE__ */ ((PriceBasePriceType2) => {
1659
- PriceBasePriceType2[PriceBasePriceType2["MIN_DISCOUNTED_PRICE"] = 1] = "MIN_DISCOUNTED_PRICE";
1660
- PriceBasePriceType2[PriceBasePriceType2["MIN_TOTAL_PRICE"] = 2] = "MIN_TOTAL_PRICE";
1661
- return PriceBasePriceType2;
1662
- })(PriceBasePriceType || {});
1663
- function useProduct(options = {}) {
1664
- const { client, locale } = useShopify();
1665
- const { handle, metafieldIdentifiers, ...swrOptions } = options;
1666
- return useSWR(
1667
- handle ? ["product", locale, handle, metafieldIdentifiers] : null,
1668
- () => getProduct(client, {
1669
- handle,
1670
- locale,
1671
- metafieldIdentifiers
1672
- }),
1673
- swrOptions
1674
- );
1675
- }
1676
- function useAllProducts(options = {}) {
1677
- const { client, locale } = useShopify();
1678
- const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
1679
- return useSWR(
1680
- ["all-products", locale, first, query, sortKey, reverse, metafieldIdentifiers],
1681
- () => getAllProducts(client, {
1682
- locale,
1683
- first,
1684
- query,
1685
- sortKey,
1686
- reverse,
1687
- metafieldIdentifiers
1688
- }),
1689
- swrOptions
1690
- );
1613
+ // src/hooks/member/plus/types.ts
1614
+ var PLUS_MEMBER_TYPE = /* @__PURE__ */ ((PLUS_MEMBER_TYPE2) => {
1615
+ PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["FREE"] = 0] = "FREE";
1616
+ PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["MONTHLY"] = 1] = "MONTHLY";
1617
+ PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["ANNUAL"] = 2] = "ANNUAL";
1618
+ return PLUS_MEMBER_TYPE2;
1619
+ })(PLUS_MEMBER_TYPE || {});
1620
+ var PlusMemberMode = /* @__PURE__ */ ((PlusMemberMode2) => {
1621
+ PlusMemberMode2["MONTHLY"] = "monthly";
1622
+ PlusMemberMode2["ANNUAL"] = "annual";
1623
+ return PlusMemberMode2;
1624
+ })(PlusMemberMode || {});
1625
+ var DeliveryPlusType = /* @__PURE__ */ ((DeliveryPlusType2) => {
1626
+ DeliveryPlusType2["FREE"] = "free";
1627
+ DeliveryPlusType2["MONTHLY"] = "monthly";
1628
+ DeliveryPlusType2["ANNUAL"] = "annual";
1629
+ return DeliveryPlusType2;
1630
+ })(DeliveryPlusType || {});
1631
+ var ShippingMethodMode = /* @__PURE__ */ ((ShippingMethodMode2) => {
1632
+ ShippingMethodMode2["FREE"] = "free";
1633
+ ShippingMethodMode2["TDD"] = "tdd";
1634
+ ShippingMethodMode2["NDD"] = "ndd";
1635
+ return ShippingMethodMode2;
1636
+ })(ShippingMethodMode || {});
1637
+ var createInitialValue = () => ({
1638
+ plusMemberMetafields: {},
1639
+ selectedPlusMemberMode: "free",
1640
+ setSelectedPlusMemberMode: () => {
1641
+ },
1642
+ selectedShippingMethod: void 0,
1643
+ setSelectedShippingMethod: () => {
1644
+ },
1645
+ showMoreShippingMethod: false,
1646
+ setShowMoreShippingMethod: () => {
1647
+ },
1648
+ variant: {},
1649
+ product: {},
1650
+ shippingMethodsContext: {
1651
+ freeShippingMethods: [],
1652
+ paymentShippingMethods: [],
1653
+ nddOverweight: false,
1654
+ tddOverweight: false,
1655
+ nddCoupon: void 0,
1656
+ tddCoupon: void 0,
1657
+ isLoadingCoupon: false
1658
+ },
1659
+ selectedPlusMemberVariant: void 0,
1660
+ showPlusMemberBenefit: false,
1661
+ setShowPlusMemberBenefit: () => {
1662
+ },
1663
+ profile: void 0
1664
+ });
1665
+ var PlusMemberContext = createContext(createInitialValue());
1666
+ function usePlusMemberContext() {
1667
+ return useContext(PlusMemberContext);
1691
1668
  }
1692
1669
  function useProductsByHandles(options = {}) {
1693
1670
  const { client, locale } = useShopify();
@@ -1707,1152 +1684,1349 @@ function useProductsByHandles(options = {}) {
1707
1684
  metafieldIdentifiers
1708
1685
  });
1709
1686
  },
1710
- swrOptions || {
1711
- revalidateOnFocus: false
1687
+ {
1688
+ revalidateOnFocus: false,
1689
+ ...swrOptions
1712
1690
  }
1713
1691
  );
1714
1692
  }
1715
- function getFirstAvailableVariant(product) {
1716
- const availableVariant = product.variants.find((v) => v.availableForSale);
1717
- return availableVariant || product.variants[0];
1718
- }
1719
- function getVariantFromSelectedOptions(product, selectedOptions) {
1720
- return product.variants.find((variant) => {
1721
- return variant.selectedOptions.every((option) => {
1722
- return selectedOptions[option.name] === option.value;
1723
- });
1724
- });
1725
- }
1726
- function useVariant({
1727
- product,
1728
- selectedOptions
1693
+
1694
+ // src/hooks/member/plus/use-plus-member-variants.ts
1695
+ function usePlusMemberVariants({
1696
+ memberSetting
1729
1697
  }) {
1730
- const [variant, setVariant] = useState(
1731
- product ? getFirstAvailableVariant(product) : void 0
1732
- );
1733
- useEffect(() => {
1734
- if (!product) {
1735
- setVariant(void 0);
1736
- return;
1737
- }
1738
- const newVariant = getVariantFromSelectedOptions(product, selectedOptions);
1739
- if (newVariant && newVariant.id !== variant?.id) {
1740
- setVariant(newVariant);
1741
- } else if (!newVariant) {
1742
- setVariant(getFirstAvailableVariant(product));
1743
- }
1744
- }, [selectedOptions, product, variant?.id]);
1745
- return variant;
1746
- }
1747
- var FAKE_PRICE = 999999999e-2;
1748
- function formatPrice({
1749
- amount,
1750
- currencyCode,
1751
- locale,
1752
- maximumFractionDigits,
1753
- minimumFractionDigits,
1754
- removeTrailingZeros
1755
- }) {
1756
- const formatter = new Intl.NumberFormat(locale, {
1757
- style: "currency",
1758
- currency: currencyCode,
1759
- maximumFractionDigits: maximumFractionDigits ?? 2,
1760
- minimumFractionDigits: minimumFractionDigits ?? 2
1698
+ const plusMonthly = memberSetting?.plus_monthly_product;
1699
+ const plusAnnual = memberSetting?.plus_annual_product;
1700
+ const plusMemberHandles = useMemo(() => {
1701
+ return [plusMonthly?.handle, plusAnnual?.handle].filter(Boolean);
1702
+ }, [plusMonthly?.handle, plusAnnual?.handle]);
1703
+ const { data: plusMemberProducts = [] } = useProductsByHandles({
1704
+ handles: plusMemberHandles
1761
1705
  });
1762
- let formatted = formatter.format(amount);
1763
- if (removeTrailingZeros) {
1764
- formatted = formatted.replace(/\.00$/, "");
1765
- }
1766
- return formatted;
1767
- }
1768
- function formatVariantPrice({
1769
- amount,
1770
- baseAmount,
1771
- currencyCode,
1772
- locale,
1773
- maximumFractionDigits,
1774
- minimumFractionDigits,
1775
- removeTrailingZeros
1776
- }) {
1706
+ const monthlyProduct = useMemo(() => {
1707
+ return plusMemberProducts?.find((item) => item?.handle === plusMonthly?.handle);
1708
+ }, [plusMemberProducts, plusMonthly]);
1709
+ const annualProduct = useMemo(() => {
1710
+ return plusMemberProducts?.find((item) => item?.handle === plusAnnual?.handle);
1711
+ }, [plusMemberProducts, plusAnnual]);
1712
+ const monthlyVariant = useMemo(() => {
1713
+ return monthlyProduct?.variants?.find((item) => item.sku === plusMonthly?.sku);
1714
+ }, [monthlyProduct, plusMonthly]);
1715
+ const annualVariant = useMemo(() => {
1716
+ return annualProduct?.variants?.find((item) => item.sku === plusAnnual?.sku);
1717
+ }, [annualProduct, plusAnnual]);
1777
1718
  return {
1778
- price: formatPrice({
1779
- amount,
1780
- currencyCode,
1781
- locale,
1782
- maximumFractionDigits,
1783
- minimumFractionDigits,
1784
- removeTrailingZeros
1785
- }),
1786
- basePrice: formatPrice({
1787
- amount: baseAmount,
1788
- currencyCode,
1789
- locale,
1790
- maximumFractionDigits,
1791
- minimumFractionDigits,
1792
- removeTrailingZeros
1793
- })
1719
+ monthlyVariant: monthlyVariant ? {
1720
+ ...monthlyVariant,
1721
+ product: monthlyProduct
1722
+ } : void 0,
1723
+ annualVariant: annualVariant ? {
1724
+ ...annualVariant,
1725
+ product: annualProduct
1726
+ } : void 0
1794
1727
  };
1795
1728
  }
1796
- function usePrice({
1797
- amount,
1798
- baseAmount,
1799
- currencyCode,
1800
- soldOutDescription = "",
1801
- maximumFractionDigits,
1802
- minimumFractionDigits,
1803
- removeTrailingZeros
1804
- }) {
1805
- const { locale } = useShopify();
1806
- const value = useMemo(() => {
1807
- if (typeof amount !== "number" || !currencyCode) {
1808
- return "";
1809
- }
1810
- if (soldOutDescription && amount >= FAKE_PRICE) {
1811
- return soldOutDescription;
1729
+ var useAvailableDeliveryCoupon = ({
1730
+ profile
1731
+ }) => {
1732
+ const { data: availableDeliveryCoupon, isLoading } = useSWR(
1733
+ profile?.email ? ["/api/multipass/subsrv/v1/prime/delivery_coupons/current/available", profile?.email] : void 0,
1734
+ async ([apiPath]) => {
1735
+ return fetch(apiPath).then((res) => res.json());
1812
1736
  }
1813
- return baseAmount ? formatVariantPrice({
1814
- amount,
1815
- baseAmount,
1816
- currencyCode,
1817
- locale,
1818
- maximumFractionDigits,
1819
- minimumFractionDigits,
1820
- removeTrailingZeros
1821
- }) : formatPrice({
1822
- amount,
1823
- currencyCode,
1824
- locale,
1825
- maximumFractionDigits,
1826
- minimumFractionDigits,
1827
- removeTrailingZeros
1737
+ );
1738
+ console.log("availableDeliveryCoupon", availableDeliveryCoupon);
1739
+ const { ndd_coupon: nddCoupon, tdd_coupon: tddCoupon } = availableDeliveryCoupon?.data?.data || {};
1740
+ return {
1741
+ nddCoupon,
1742
+ tddCoupon,
1743
+ isLoading
1744
+ };
1745
+ };
1746
+
1747
+ // src/hooks/member/plus/use-shipping-methods.ts
1748
+ function useShippingMethods(options) {
1749
+ const { variant, plusMemberMetafields, selectedPlusMemberMode, profile } = options;
1750
+ const isPlus = profile?.isPlus || false;
1751
+ const { nddCoupon, tddCoupon, isLoading } = useAvailableDeliveryCoupon({ profile });
1752
+ const { plus_shipping, shippingMethod } = plusMemberMetafields || {};
1753
+ const nddOverweight = useMemo(() => {
1754
+ return (variant?.weight || 0) > (shippingMethod?.overWeight_ndd || Infinity);
1755
+ }, [shippingMethod?.overWeight_ndd, variant?.weight]);
1756
+ const tddOverweight = useMemo(() => {
1757
+ return (variant?.weight || 0) > (shippingMethod?.overWeight_tdd || Infinity);
1758
+ }, [shippingMethod?.overWeight_tdd, variant?.weight]);
1759
+ const paymentShippingMethods = useMemo(() => {
1760
+ const weight = variant?.weight || 0;
1761
+ const methods = plus_shipping?.shipping_methods?.filter(({ weight_low, weight_high, __mode, __plus }) => {
1762
+ const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
1763
+ return __mode !== "free" /* FREE */ && !__plus && fitWeight;
1764
+ }) || [];
1765
+ return methods.map((method) => {
1766
+ let disabled = false;
1767
+ const selectedFreeMember = selectedPlusMemberMode === "free";
1768
+ if (method.__mode === "ndd" /* NDD */) {
1769
+ disabled = selectedFreeMember || nddOverweight;
1770
+ } else if (method.__mode === "tdd" /* TDD */) {
1771
+ disabled = selectedFreeMember || tddOverweight;
1772
+ }
1773
+ return {
1774
+ ...method,
1775
+ id: method.__mode + method.__code,
1776
+ useCoupon: false,
1777
+ subtitle: plus_shipping?.directly || "",
1778
+ disabled
1779
+ };
1828
1780
  });
1829
1781
  }, [
1830
- amount,
1831
- baseAmount,
1832
- currencyCode,
1833
- locale,
1834
- maximumFractionDigits,
1835
- minimumFractionDigits,
1836
- soldOutDescription,
1837
- removeTrailingZeros
1782
+ nddOverweight,
1783
+ plus_shipping?.directly,
1784
+ plus_shipping?.shipping_methods,
1785
+ selectedPlusMemberMode,
1786
+ tddOverweight,
1787
+ variant?.weight
1838
1788
  ]);
1839
- const result = useMemo(() => {
1840
- const free = Boolean(amount && amount <= 0);
1841
- return typeof value === "string" ? { price: value, basePrice: value, free } : { ...value, free };
1842
- }, [value, amount]);
1843
- return result;
1844
- }
1845
- function optionsConstructor(selectedOptions) {
1846
- return selectedOptions.reduce((acc, option) => {
1847
- acc[option.name] = option.value;
1848
- return acc;
1849
- }, {});
1850
- }
1851
- function decodeShopifyId(gid) {
1852
- try {
1853
- const base64 = gid.split("/").pop() || "";
1854
- return atob(base64);
1855
- } catch {
1856
- return gid;
1857
- }
1858
- }
1859
- function useSelectedOptions(product, sku) {
1860
- const [options, setOptions] = useState({});
1861
- useEffect(() => {
1862
- if (!product || !product.variants.length) {
1863
- setOptions({});
1864
- return;
1865
- }
1866
- let variant = product.variants[0];
1867
- if (typeof window !== "undefined") {
1868
- const searchParams = new URLSearchParams(window.location.search);
1869
- const variantIdParam = searchParams.get("variant");
1870
- if (variantIdParam) {
1871
- const foundVariant = product.variants.find((v) => {
1872
- if (sku) return v.sku === sku;
1873
- return v.id === variantIdParam || v.id.includes(variantIdParam) || decodeShopifyId(v.id) === variantIdParam;
1874
- });
1875
- if (foundVariant) {
1876
- variant = foundVariant;
1877
- }
1789
+ const nddPrice = useMemo(() => {
1790
+ const weight = variant?.weight || 0;
1791
+ const nddMethod = paymentShippingMethods.find(({ __mode, weight_high, weight_low }) => {
1792
+ const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
1793
+ return __mode === "ndd" && fitWeight;
1794
+ });
1795
+ return nddMethod?.price || 0;
1796
+ }, [variant?.weight, paymentShippingMethods]);
1797
+ const tddPrice = useMemo(() => {
1798
+ const weight = variant?.weight || 0;
1799
+ const tddMethod = paymentShippingMethods.find(({ __mode, weight_high, weight_low }) => {
1800
+ const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
1801
+ return __mode === "tdd" && fitWeight;
1802
+ });
1803
+ return tddMethod?.price || 0;
1804
+ }, [variant?.weight, paymentShippingMethods]);
1805
+ const freeShippingMethods = useMemo(() => {
1806
+ const weight = variant?.weight || 0;
1807
+ let methods = plus_shipping?.shipping_methods?.filter(({ __mode, __plus, weight_low, weight_high }) => {
1808
+ if (__mode === "free" /* FREE */) {
1809
+ return true;
1878
1810
  }
1811
+ if (isPlus) {
1812
+ const hasCoupon = isPlus && __mode === "ndd" /* NDD */ && nddCoupon || isPlus && __mode === "tdd" /* TDD */ && (tddCoupon || nddCoupon);
1813
+ const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
1814
+ return hasCoupon && fitWeight && !__plus;
1815
+ } else {
1816
+ return __plus;
1817
+ }
1818
+ }) || [];
1819
+ if (isPlus) {
1820
+ methods = methods.sort((a, b) => {
1821
+ if (b.__mode === "free" /* FREE */) return -1;
1822
+ return 0;
1823
+ });
1879
1824
  }
1880
- if (variant) {
1881
- const newOptions = optionsConstructor(variant.selectedOptions);
1882
- setOptions(newOptions);
1883
- }
1884
- }, [product, sku]);
1885
- return [options, setOptions];
1886
- }
1887
- function decodeShopifyId2(gid) {
1888
- try {
1889
- const parts = gid.split("/");
1890
- return parts[parts.length - 1] || gid;
1891
- } catch {
1892
- return gid;
1893
- }
1894
- }
1895
- function useProductUrl(otherQuery) {
1896
- const { routerAdapter } = useShopify();
1897
- return useCallback(
1898
- ({ product, variant }) => {
1899
- if (!product) return "";
1900
- const queryParams = new URLSearchParams();
1901
- if (variant?.id) {
1902
- const variantId = decodeShopifyId2(variant.id);
1903
- if (variantId) {
1904
- queryParams.set("variant", variantId);
1825
+ return methods.map((method) => {
1826
+ let price = 0;
1827
+ let coupon;
1828
+ let disabled;
1829
+ if (method.__mode !== "free" /* FREE */) {
1830
+ switch (method.__mode) {
1831
+ case "tdd":
1832
+ price = tddPrice;
1833
+ coupon = tddCoupon || nddCoupon;
1834
+ break;
1835
+ case "ndd":
1836
+ price = nddPrice;
1837
+ coupon = nddCoupon;
1838
+ break;
1839
+ }
1840
+ disabled = selectedPlusMemberMode === "free";
1841
+ if (method.__mode === "ndd" /* NDD */) {
1842
+ disabled = disabled || nddOverweight;
1843
+ } else if (method.__mode === "tdd" /* TDD */) {
1844
+ disabled = disabled || tddOverweight;
1905
1845
  }
1906
1846
  }
1907
- if (otherQuery) {
1908
- Object.entries(otherQuery).forEach(([key, value]) => {
1909
- queryParams.set(key, value);
1910
- });
1911
- }
1912
- const queryString = queryParams.toString();
1913
- const path = `/products/${product.handle}${queryString ? `?${queryString}` : ""}`;
1914
- if (routerAdapter?.getLocalizedPath) {
1915
- return routerAdapter.getLocalizedPath(path);
1847
+ return {
1848
+ ...method,
1849
+ id: method.__mode + method.__code,
1850
+ useCoupon: true,
1851
+ disabled,
1852
+ coupon,
1853
+ price
1854
+ };
1855
+ });
1856
+ }, [
1857
+ variant?.weight,
1858
+ plus_shipping?.shipping_methods,
1859
+ isPlus,
1860
+ nddCoupon,
1861
+ tddCoupon,
1862
+ selectedPlusMemberMode,
1863
+ tddPrice,
1864
+ nddPrice,
1865
+ nddOverweight,
1866
+ tddOverweight
1867
+ ]);
1868
+ return {
1869
+ freeShippingMethods,
1870
+ paymentShippingMethods,
1871
+ nddOverweight,
1872
+ tddOverweight,
1873
+ nddCoupon,
1874
+ tddCoupon,
1875
+ isLoadingCoupon: isLoading
1876
+ };
1877
+ }
1878
+ var useReplaceCartPlusMember = () => {
1879
+ const { plusMemberMetafields, selectedPlusMemberMode } = usePlusMemberContext();
1880
+ const { trigger: removeCartLines2 } = useRemoveCartLines();
1881
+ const { cart } = useCartContext();
1882
+ const plusMonthly = plusMemberMetafields?.plus_monthly_product;
1883
+ const plusAnnual = plusMemberMetafields?.plus_annual_product;
1884
+ const handler = useCallback(async () => {
1885
+ const plusMonthlyInCart = cart?.lineItems.find(
1886
+ (item) => item.variant?.sku === plusMonthly?.sku
1887
+ );
1888
+ const plusAnnualInCart = cart?.lineItems.find(
1889
+ (item) => item.variant?.sku === plusAnnual?.sku
1890
+ );
1891
+ if (selectedPlusMemberMode === "annual" /* ANNUAL */ && plusMonthlyInCart) {
1892
+ await removeCartLines2({
1893
+ lineIds: [plusMonthlyInCart.id]
1894
+ });
1895
+ } else if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && plusAnnualInCart) {
1896
+ await removeCartLines2({
1897
+ lineIds: [plusAnnualInCart.id]
1898
+ });
1899
+ }
1900
+ }, [
1901
+ cart?.lineItems,
1902
+ selectedPlusMemberMode,
1903
+ plusMonthly?.sku,
1904
+ plusAnnual?.sku,
1905
+ removeCartLines2
1906
+ ]);
1907
+ return handler;
1908
+ };
1909
+ var usePlusMemberCheckoutCustomAttributes = ({
1910
+ disableShipping = false,
1911
+ isPresaleContains = false
1912
+ }) => {
1913
+ const { profile, selectedShippingMethod, selectedPlusMemberMode } = usePlusMemberContext();
1914
+ return useMemo(() => {
1915
+ const checkoutCustomAttributes = [
1916
+ {
1917
+ key: "_last_url",
1918
+ value: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
1916
1919
  }
1917
- return path;
1920
+ ];
1921
+ checkoutCustomAttributes.push({
1922
+ key: "_checkout_delivery_custom",
1923
+ value: JSON.stringify({
1924
+ allow_nextday_delivery: true,
1925
+ allow_thirdday_delivery: true,
1926
+ selected_delivery_option: {
1927
+ code: selectedShippingMethod?.__code,
1928
+ mode: selectedShippingMethod?.__mode
1929
+ },
1930
+ is_presale: isPresaleContains,
1931
+ discount_code: selectedShippingMethod?.coupon ? [selectedShippingMethod.coupon] : [],
1932
+ plus_type: profile?.isPlus ? "free" /* FREE */ : selectedPlusMemberMode,
1933
+ is_prime: profile?.isPlus
1934
+ })
1935
+ });
1936
+ if (disableShipping) {
1937
+ checkoutCustomAttributes.push({
1938
+ key: "_hide_shipping",
1939
+ value: "true"
1940
+ });
1941
+ }
1942
+ return checkoutCustomAttributes;
1943
+ }, [profile, selectedShippingMethod, selectedPlusMemberMode, isPresaleContains]);
1944
+ };
1945
+ function useRemoveCartLines(options) {
1946
+ const { client, locale, cartCookieAdapter } = useShopify();
1947
+ const { mutateCart, metafieldIdentifiers } = useCartContext();
1948
+ const removeLines = useCallback(
1949
+ async (_key, { arg }) => {
1950
+ const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
1951
+ let updatedCart = await removeCartLines(client, {
1952
+ cartId,
1953
+ lineIds,
1954
+ metafieldIdentifiers,
1955
+ cookieAdapter: cartCookieAdapter
1956
+ });
1957
+ if (updatedCart && autoRemoveInvalidCodes) {
1958
+ const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
1959
+ if (unApplicableCodes.length > 0) {
1960
+ if (onCodesRemoved) {
1961
+ const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
1962
+ if (handledCart) {
1963
+ updatedCart = handledCart;
1964
+ }
1965
+ } else {
1966
+ updatedCart = await updateCartCodes(client, {
1967
+ cartId: updatedCart.id,
1968
+ discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
1969
+ metafieldIdentifiers,
1970
+ cookieAdapter: cartCookieAdapter
1971
+ }) || updatedCart;
1972
+ }
1973
+ }
1974
+ }
1975
+ if (updatedCart) {
1976
+ mutateCart(updatedCart);
1977
+ }
1978
+ return updatedCart;
1918
1979
  },
1919
- [routerAdapter, otherQuery]
1980
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
1920
1981
  );
1982
+ return useSWRMutation("remove-cart-lines", removeLines, options);
1921
1983
  }
1922
- function decodeShopifyId3(gid) {
1923
- try {
1924
- const parts = gid.split("/");
1925
- return parts[parts.length - 1] || gid;
1926
- } catch {
1927
- return gid;
1928
- }
1929
- }
1930
- function useUpdateVariantQuery(variant) {
1984
+
1985
+ // src/hooks/member/plus/use-auto-remove-plus-member-in-cart.ts
1986
+ function useAutoRemovePlusMemberInCart({
1987
+ cart,
1988
+ profile,
1989
+ memberSetting
1990
+ }) {
1991
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
1992
+ const { trigger: removeCartLines2 } = useRemoveCartLines();
1931
1993
  useEffect(() => {
1932
- if (!variant || typeof window === "undefined") {
1933
- return;
1994
+ if (!cart || !plus_monthly_product || !plus_annual_product) return;
1995
+ const removePlusProduct = async (productType) => {
1996
+ if (!productType) return;
1997
+ const product = cart.lineItems?.find(
1998
+ (item) => item.product?.handle === productType?.handle && item.variant?.sku === productType?.sku
1999
+ );
2000
+ if (product) {
2001
+ await removeCartLines2({
2002
+ lineIds: [product.id]
2003
+ });
2004
+ }
2005
+ };
2006
+ if (profile?.isMonthlyPlus) {
2007
+ removePlusProduct(plus_monthly_product);
1934
2008
  }
1935
- const searchParams = new URLSearchParams(window.location.search);
1936
- const currentVariantId = searchParams.get("variant");
1937
- const newVariantId = decodeShopifyId3(variant.id);
1938
- if (newVariantId && currentVariantId !== newVariantId) {
1939
- searchParams.set("variant", newVariantId);
1940
- const newUrl = `${window.location.pathname}?${searchParams.toString()}${window.location.hash}`;
1941
- window.history.replaceState({}, "", newUrl);
2009
+ if (profile?.isAnnualPlus) {
2010
+ removePlusProduct(plus_annual_product);
1942
2011
  }
1943
- }, [variant]);
2012
+ }, [cart, plus_annual_product, plus_monthly_product, profile, removeCartLines2]);
1944
2013
  }
1945
- function getVariantMediaList({
1946
- product,
1947
- variant
2014
+ function hasPlusMemberInCart({
2015
+ memberSetting,
2016
+ cart
1948
2017
  }) {
1949
- if (variant.image?.url) {
1950
- const variantMediaId = variant.image.url;
1951
- const variantMedia = product.media.filter((media) => {
1952
- if (media.mediaContentType === "IMAGE" && media.previewImage) {
1953
- return media.previewImage?.url === variantMediaId;
1954
- }
1955
- return false;
1956
- });
1957
- if (variantMedia.length > 0) {
1958
- const otherMedia = product.media.filter((media) => {
1959
- if (media.mediaContentType === "IMAGE" && media.previewImage) {
1960
- return media.previewImage.url !== variantMediaId;
1961
- }
1962
- return true;
1963
- });
1964
- return [...variantMedia, ...otherMedia];
1965
- }
2018
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
2019
+ if (!cart?.lineItems) {
2020
+ return {
2021
+ hasPlusMember: false,
2022
+ hasMonthlyPlus: false,
2023
+ hasAnnualPlus: false
2024
+ };
1966
2025
  }
1967
- return product.media;
2026
+ const monthlyPlusItem = cart.lineItems.find(
2027
+ (item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
2028
+ );
2029
+ const annualPlusItem = cart.lineItems.find(
2030
+ (item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
2031
+ );
2032
+ const hasMonthlyPlus = !!monthlyPlusItem;
2033
+ const hasAnnualPlus = !!annualPlusItem;
2034
+ const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
2035
+ return {
2036
+ hasPlusMember,
2037
+ hasMonthlyPlus,
2038
+ hasAnnualPlus,
2039
+ monthlyPlusItem,
2040
+ annualPlusItem
2041
+ };
1968
2042
  }
1969
- function useVariantMedia({
1970
- product,
1971
- variant
2043
+ function useHasPlusMemberInCart({
2044
+ memberSetting,
2045
+ cart
1972
2046
  }) {
1973
- const [imageList, setImageList] = useState([]);
1974
- const [sceneList, setSceneList] = useState([]);
1975
- const [videoList, setVideoList] = useState([]);
1976
- useEffect(() => {
1977
- if (!product || !variant) {
1978
- setImageList([]);
1979
- setSceneList([]);
1980
- setVideoList([]);
1981
- return;
1982
- }
1983
- const mediaList = getVariantMediaList({ product, variant });
1984
- const images = mediaList.filter((media) => media.mediaContentType === "IMAGE");
1985
- const videos = mediaList.filter(
1986
- (media) => media.mediaContentType === "VIDEO" || media.mediaContentType === "EXTERNAL_VIDEO"
1987
- );
1988
- setImageList(images.length > 0 && images[0] ? [images[0]] : []);
1989
- setSceneList(images.length > 1 ? images.slice(1) : []);
1990
- setVideoList(videos);
1991
- }, [product, variant]);
2047
+ return useMemo(
2048
+ () => hasPlusMemberInCart({
2049
+ memberSetting,
2050
+ cart
2051
+ }),
2052
+ [memberSetting, cart]
2053
+ );
2054
+ }
2055
+ function hasPlusMemberInLines({
2056
+ memberSetting,
2057
+ lines
2058
+ }) {
2059
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
2060
+ if (!lines || lines.length === 0) {
2061
+ return {
2062
+ hasPlusMember: false,
2063
+ hasMonthlyPlus: false,
2064
+ hasAnnualPlus: false
2065
+ };
2066
+ }
2067
+ const monthlyPlusLine = lines.find((line) => {
2068
+ const variantHandle = line.variant?.product?.handle;
2069
+ const variantSku = line.variant?.sku;
2070
+ return variantHandle === plus_monthly_product?.handle && variantSku === plus_monthly_product?.sku;
2071
+ });
2072
+ const annualPlusLine = lines.find((line) => {
2073
+ const variantHandle = line.variant?.product?.handle;
2074
+ const variantSku = line.variant?.sku;
2075
+ return variantHandle === plus_annual_product?.handle && variantSku === plus_annual_product?.sku;
2076
+ });
2077
+ const hasMonthlyPlus = !!monthlyPlusLine;
2078
+ const hasAnnualPlus = !!annualPlusLine;
2079
+ const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
1992
2080
  return {
1993
- productList: imageList,
1994
- sceneList,
1995
- videoList
2081
+ hasPlusMember,
2082
+ hasMonthlyPlus,
2083
+ hasAnnualPlus,
2084
+ monthlyPlusLine,
2085
+ annualPlusLine
1996
2086
  };
1997
2087
  }
1998
- function useCollection(options = {}) {
1999
- const { client, locale } = useShopify();
2000
- const { handle, metafieldIdentifiers, ...swrOptions } = options;
2001
- return useSWR(
2002
- handle ? ["collection", locale, handle, metafieldIdentifiers] : null,
2003
- () => getCollection(client, {
2004
- handle,
2005
- locale,
2006
- metafieldIdentifiers
2088
+ function useHasPlusMemberInLines({
2089
+ memberSetting,
2090
+ lines
2091
+ }) {
2092
+ return useMemo(
2093
+ () => hasPlusMemberInLines({
2094
+ memberSetting,
2095
+ lines
2007
2096
  }),
2008
- swrOptions
2097
+ [memberSetting, lines]
2009
2098
  );
2010
2099
  }
2011
- function useAllCollections(options = {}) {
2012
- const { client, locale } = useShopify();
2013
- const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2014
- return useSWR(
2015
- ["all-collections", locale, first, query, sortKey, reverse, metafieldIdentifiers],
2016
- () => getAllCollections(client, {
2017
- locale,
2018
- first,
2019
- query,
2020
- sortKey,
2021
- reverse,
2022
- metafieldIdentifiers
2023
- }),
2024
- swrOptions
2025
- );
2026
- }
2027
- function useCollections(options = {}) {
2028
- const { client, locale } = useShopify();
2029
- const { first, after, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2030
- return useSWR(
2031
- ["collections", locale, first, after, query, sortKey, reverse, metafieldIdentifiers],
2032
- () => getCollections(client, {
2033
- locale,
2034
- first,
2035
- after,
2036
- query,
2037
- sortKey,
2038
- reverse,
2039
- metafieldIdentifiers
2040
- }),
2041
- swrOptions
2042
- );
2043
- }
2044
- function useBlog(options = {}) {
2045
- const { client, locale } = useShopify();
2046
- const { handle, metafieldIdentifiers, ...swrOptions } = options;
2047
- return useSWR(
2048
- handle ? ["blog", locale, handle, metafieldIdentifiers] : null,
2049
- () => getBlog(client, { handle, locale, metafieldIdentifiers }),
2050
- swrOptions
2051
- );
2052
- }
2053
- function useAllBlogs(options = {}) {
2054
- const { client, locale } = useShopify();
2055
- const { first, query, metafieldIdentifiers, ...swrOptions } = options;
2056
- return useSWR(
2057
- ["all-blogs", locale, first, query, metafieldIdentifiers],
2058
- () => getAllBlogs(client, {
2059
- locale,
2060
- first,
2061
- query,
2062
- metafieldIdentifiers
2063
- }),
2064
- swrOptions
2065
- );
2066
- }
2067
- function useArticle(options = {}) {
2068
- const { client, locale } = useShopify();
2069
- const { blogHandle, articleHandle, metafieldIdentifiers, ...swrOptions } = options;
2070
- return useSWR(
2071
- blogHandle && articleHandle ? ["article", locale, blogHandle, articleHandle, metafieldIdentifiers] : null,
2072
- () => getArticle(client, {
2073
- blogHandle,
2074
- articleHandle,
2075
- locale,
2076
- metafieldIdentifiers
2077
- }),
2078
- swrOptions
2079
- );
2100
+ function usePlusMemberNeedAddToCart({
2101
+ cart,
2102
+ profile
2103
+ }) {
2104
+ const { selectedPlusMemberMode, selectedPlusMemberVariant, plusMemberMetafields } = usePlusMemberContext();
2105
+ const { hasMonthlyPlus, hasAnnualPlus } = useHasPlusMemberInCart({
2106
+ memberSetting: plusMemberMetafields,
2107
+ cart
2108
+ });
2109
+ const plusMemberVariant = useMemo(() => {
2110
+ if (!selectedPlusMemberVariant || selectedPlusMemberMode === "free" /* FREE */) {
2111
+ return void 0;
2112
+ }
2113
+ if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && hasMonthlyPlus) {
2114
+ return void 0;
2115
+ }
2116
+ if (selectedPlusMemberMode === "annual" /* ANNUAL */ && hasAnnualPlus) {
2117
+ return void 0;
2118
+ }
2119
+ if (profile?.isMonthlyPlus && selectedPlusMemberMode === "monthly" /* MONTHLY */) {
2120
+ return void 0;
2121
+ }
2122
+ if (profile?.isAnnualPlus && selectedPlusMemberMode === "annual" /* ANNUAL */) {
2123
+ return void 0;
2124
+ }
2125
+ return selectedPlusMemberVariant;
2126
+ }, [selectedPlusMemberMode, selectedPlusMemberVariant, hasMonthlyPlus, hasAnnualPlus]);
2127
+ return plusMemberVariant;
2080
2128
  }
2081
- function useArticles(options = {}) {
2082
- const { client, locale } = useShopify();
2083
- const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2084
- return useSWR(
2085
- ["articles", locale, first, query, sortKey, reverse, metafieldIdentifiers],
2086
- () => getArticles(client, {
2087
- locale,
2088
- first,
2089
- query,
2090
- sortKey,
2091
- reverse,
2092
- metafieldIdentifiers
2093
- }),
2094
- swrOptions
2129
+ var PlusMemberProvider = ({
2130
+ variant,
2131
+ product,
2132
+ memberSetting,
2133
+ initialSelectedPlusMemberMode = "free",
2134
+ profile,
2135
+ children
2136
+ }) => {
2137
+ const [selectedPlusMemberMode, setSelectedPlusMemberMode] = useState(
2138
+ initialSelectedPlusMemberMode
2095
2139
  );
2096
- }
2097
- function useArticlesInBlog(options = {}) {
2098
- const { client, locale } = useShopify();
2099
- const { blogHandle, first, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2100
- return useSWR(
2101
- blogHandle ? ["articles-in-blog", locale, blogHandle, first, sortKey, reverse, metafieldIdentifiers] : null,
2102
- () => getArticlesInBlog(client, {
2103
- blogHandle,
2104
- locale,
2105
- first,
2106
- sortKey,
2107
- reverse,
2108
- metafieldIdentifiers
2109
- }),
2110
- swrOptions
2140
+ const [selectedShippingMethod, setSelectedShippingMethod] = useState();
2141
+ const [showMoreShippingMethod, setShowMoreShippingMethod] = useState(false);
2142
+ const [showPlusMemberBenefit, setShowPlusMemberBenefit] = useState(false);
2143
+ const shippingMethodsContext = useShippingMethods({
2144
+ variant,
2145
+ plusMemberMetafields: memberSetting,
2146
+ selectedPlusMemberMode,
2147
+ profile
2148
+ });
2149
+ const { monthlyVariant, annualVariant } = usePlusMemberVariants({
2150
+ memberSetting
2151
+ });
2152
+ const selectedPlusMemberVariant = useMemo(() => {
2153
+ if (selectedPlusMemberMode === "free" /* FREE */) {
2154
+ return void 0;
2155
+ }
2156
+ return selectedPlusMemberMode === "monthly" /* MONTHLY */ ? monthlyVariant : annualVariant;
2157
+ }, [monthlyVariant, annualVariant, selectedPlusMemberMode]);
2158
+ return /* @__PURE__ */ jsx(
2159
+ PlusMemberContext.Provider,
2160
+ {
2161
+ value: {
2162
+ variant,
2163
+ plusMemberMetafields: memberSetting,
2164
+ selectedPlusMemberMode,
2165
+ setSelectedPlusMemberMode,
2166
+ selectedShippingMethod,
2167
+ setSelectedShippingMethod,
2168
+ shippingMethodsContext,
2169
+ showMoreShippingMethod,
2170
+ setShowMoreShippingMethod,
2171
+ selectedPlusMemberVariant,
2172
+ product,
2173
+ showPlusMemberBenefit,
2174
+ setShowPlusMemberBenefit,
2175
+ profile
2176
+ },
2177
+ children
2178
+ }
2111
2179
  );
2112
- }
2113
- async function performSearch(client, locale, searchQuery, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"]) {
2114
- if (!searchQuery) {
2115
- return void 0;
2116
- }
2117
- const query = (
2118
- /* GraphQL */
2119
- `
2120
- query search($query: String!, $first: Int!, $types: [SearchType!])
2121
- @inContext(language: $language) {
2122
- search(query: $query, first: $first, types: $types, unavailableProducts: HIDE) {
2123
- totalCount
2124
- edges {
2125
- node {
2126
- ... on Article {
2127
- __typename
2128
- id
2129
- handle
2130
- title
2131
- excerpt
2132
- image {
2133
- url
2134
- altText
2135
- }
2136
- }
2137
- ... on Page {
2138
- __typename
2139
- id
2140
- handle
2141
- title
2142
- }
2143
- ... on Product {
2144
- __typename
2145
- id
2146
- handle
2147
- title
2148
- description
2149
- featuredImage {
2150
- url
2151
- altText
2180
+ };
2181
+
2182
+ // src/hooks/cart/use-add-to-cart.ts
2183
+ function useAddToCart({ withTrack = true } = {}, swrOptions) {
2184
+ const { client, config, locale, cartCookieAdapter, userAdapter, performanceAdapter } = useShopify();
2185
+ const { cart, addCustomAttributes, memberSetting, profile, customer } = useCartContext();
2186
+ const { trigger: applyCartCodes } = useApplyCartCodes();
2187
+ const { trigger: removeInvalidCodes } = useRemoveCartCodes();
2188
+ const { trigger: addCartLines2 } = useAddCartLines();
2189
+ const { trigger: createCart4 } = useCreateCart({
2190
+ updateCookie: true
2191
+ });
2192
+ const { hasPlusMember } = useHasPlusMemberInCart({
2193
+ memberSetting,
2194
+ cart
2195
+ });
2196
+ const { attributes: cartAttributes } = useCartAttributes({
2197
+ profile,
2198
+ customer,
2199
+ cart,
2200
+ memberType: hasPlusMember ? "2" : String(profile?.memberType ?? 0)
2201
+ });
2202
+ const addToCart = useCallback(
2203
+ async (_key, { arg }) => {
2204
+ const {
2205
+ lineItems,
2206
+ cartId: providedCartId,
2207
+ discountCodes,
2208
+ gtmParams = {},
2209
+ buyerIdentity,
2210
+ needCreateCart = false,
2211
+ onCodesInvalid,
2212
+ replaceExistingCodes,
2213
+ customAttributes
2214
+ } = arg;
2215
+ if (!lineItems || lineItems.length === 0) {
2216
+ return;
2217
+ }
2218
+ performanceAdapter?.addToCartStart();
2219
+ const linesWithFunctionAttributes = getLinesWithAttributes({ cart, lineItems });
2220
+ const lines = linesWithFunctionAttributes.map((item) => ({
2221
+ merchandiseId: item.variant?.id || "",
2222
+ quantity: item.quantity || 1,
2223
+ attributes: item.attributes,
2224
+ sellingPlanId: item.sellingPlanId
2225
+ })).filter((item) => item.merchandiseId && item.quantity);
2226
+ if (lines.length === 0) {
2227
+ return;
2228
+ }
2229
+ let cartId = needCreateCart ? void 0 : providedCartId || cart?.id;
2230
+ let resultCart = null;
2231
+ if (!cartId) {
2232
+ resultCart = await createCart4({
2233
+ lines,
2234
+ buyerIdentity,
2235
+ discountCodes,
2236
+ customAttributes: [...cartAttributes, ...customAttributes || []]
2237
+ // 初次加购时,就把所有 cart attributes 带上
2238
+ });
2239
+ } else {
2240
+ resultCart = await addCartLines2({
2241
+ cartId,
2242
+ lines
2243
+ });
2244
+ console.log("npm addCartLines resultCart", resultCart);
2245
+ if (resultCart && resultCart.discountCodes && resultCart.discountCodes.length > 0) {
2246
+ const unapplicableCodes = resultCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
2247
+ if (unapplicableCodes.length > 0) {
2248
+ if (onCodesInvalid) {
2249
+ const handledCart = await onCodesInvalid(resultCart, unapplicableCodes);
2250
+ if (handledCart) {
2251
+ resultCart = handledCart;
2152
2252
  }
2253
+ } else {
2254
+ await removeInvalidCodes({
2255
+ discountCodes: unapplicableCodes
2256
+ });
2153
2257
  }
2154
2258
  }
2155
2259
  }
2156
- pageInfo {
2157
- hasNextPage
2158
- endCursor
2260
+ if (resultCart && discountCodes && discountCodes.length > 0) {
2261
+ applyCartCodes({
2262
+ replaceExistingCodes,
2263
+ discountCodes
2264
+ });
2265
+ }
2266
+ if (customAttributes && customAttributes.length > 0) {
2267
+ addCustomAttributes(customAttributes);
2159
2268
  }
2160
2269
  }
2161
- }
2162
- `
2270
+ if (withTrack) {
2271
+ trackAddToCartGA({
2272
+ lineItems,
2273
+ gtmParams: { ...gtmParams, brand: config.getBrand() }
2274
+ });
2275
+ trackAddToCartFBQ({ lineItems });
2276
+ }
2277
+ performanceAdapter?.addToCartEnd();
2278
+ return resultCart;
2279
+ },
2280
+ [
2281
+ client,
2282
+ locale,
2283
+ cartCookieAdapter,
2284
+ userAdapter,
2285
+ cart,
2286
+ withTrack,
2287
+ performanceAdapter,
2288
+ createCart4,
2289
+ addCartLines2,
2290
+ applyCartCodes,
2291
+ removeInvalidCodes,
2292
+ addCustomAttributes,
2293
+ config
2294
+ ]
2163
2295
  );
2164
- const data = await client.query(query, {
2165
- query: searchQuery,
2166
- first,
2167
- types
2168
- });
2169
- if (!data || !data.search) {
2170
- return void 0;
2171
- }
2172
- const items = data.search.edges?.map((edge) => {
2173
- const node = edge.node;
2174
- const item = {
2175
- type: node.__typename.toUpperCase(),
2176
- id: node.id,
2177
- handle: node.handle,
2178
- title: node.title
2179
- };
2180
- if (node.__typename === "Product") {
2181
- item.description = node.description;
2182
- item.image = node.featuredImage ? {
2183
- url: node.featuredImage.url,
2184
- altText: node.featuredImage.altText
2185
- } : void 0;
2186
- } else if (node.__typename === "Article") {
2187
- item.description = node.excerpt;
2188
- item.image = node.image ? {
2189
- url: node.image.url,
2190
- altText: node.image.altText
2191
- } : void 0;
2192
- }
2193
- return item;
2194
- }) || [];
2195
- return {
2196
- items,
2197
- totalCount: data.search.totalCount || 0,
2198
- pageInfo: data.search.pageInfo
2199
- };
2296
+ return useSWRMutation("add-to-cart", addToCart, swrOptions);
2200
2297
  }
2201
- function useSearch(options = {}) {
2202
- const { client, locale } = useShopify();
2203
- const { query, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"], ...swrOptions } = options;
2204
- return useSWR(
2205
- query ? ["search", locale, query, first, types] : null,
2206
- () => performSearch(client, locale, query, first, types),
2207
- swrOptions
2298
+ function useUpdateCartLines(options) {
2299
+ const { client, locale, cartCookieAdapter } = useShopify();
2300
+ const { mutateCart, metafieldIdentifiers } = useCartContext();
2301
+ const updateLines = useCallback(
2302
+ async (_key, { arg }) => {
2303
+ const updatedCart = await updateCartLines(client, {
2304
+ ...arg,
2305
+ metafieldIdentifiers,
2306
+ cookieAdapter: cartCookieAdapter
2307
+ });
2308
+ if (updatedCart) {
2309
+ mutateCart(updatedCart);
2310
+ }
2311
+ console.log("use-update-cart-lines updatedCart", metafieldIdentifiers, updatedCart);
2312
+ return updatedCart;
2313
+ },
2314
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
2208
2315
  );
2316
+ return useSWRMutation("update-cart-lines", updateLines, options);
2209
2317
  }
2210
- async function getSiteInfo(client, locale, metafieldIdentifiers) {
2211
- const hasMetafields = metafieldIdentifiers && metafieldIdentifiers.length > 0;
2212
- const query = (
2213
- /* GraphQL */
2214
- `
2215
- query getSiteInfo(
2216
- ${hasMetafields ? "$shopMetafieldIdentifiers: [HasMetafieldsIdentifier!]!" : ""}
2217
- ) @inContext(language: $language) {
2218
- shop {
2219
- name
2220
- description
2221
- primaryDomain {
2222
- url
2223
- host
2318
+ function useUpdateCartAttributes({
2319
+ mutate,
2320
+ metafieldIdentifiers,
2321
+ disabled = false,
2322
+ swrOptions
2323
+ }) {
2324
+ const { client, locale, cartCookieAdapter } = useShopify();
2325
+ const updateAttributes = useCallback(
2326
+ async (_key, { arg }) => {
2327
+ if (disabled) {
2328
+ return void 0;
2329
+ }
2330
+ const updatedCart = await updateCartAttributes(client, {
2331
+ ...arg,
2332
+ metafieldIdentifiers,
2333
+ cookieAdapter: cartCookieAdapter
2334
+ });
2335
+ if (updatedCart) {
2336
+ mutate(updatedCart);
2337
+ }
2338
+ return updatedCart;
2339
+ },
2340
+ [client, locale, cartCookieAdapter, mutate, metafieldIdentifiers, disabled]
2341
+ );
2342
+ return useSWRMutation("update-cart-attributes", updateAttributes, swrOptions);
2343
+ }
2344
+ function useBuyNow({ withTrack = true } = {}, swrOptions) {
2345
+ const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
2346
+ const { profile, customer, memberSetting } = useCartContext();
2347
+ const isLoggedIn = userAdapter?.isLoggedIn || false;
2348
+ const buyNow = useCallback(
2349
+ async (_key, { arg }) => {
2350
+ const {
2351
+ lineItems,
2352
+ discountCodes,
2353
+ gtmParams = {},
2354
+ buyerIdentity,
2355
+ fbqTrackConfig,
2356
+ customAttributes,
2357
+ metafieldIdentifiers,
2358
+ redirectToCheckout
2359
+ } = arg;
2360
+ if (!lineItems || lineItems.length === 0) {
2361
+ return;
2362
+ }
2363
+ const { hasPlusMember } = hasPlusMemberInLines({
2364
+ memberSetting,
2365
+ lines: lineItems
2366
+ });
2367
+ const memberType = hasPlusMember ? "2" : String(profile?.memberType ?? 0);
2368
+ const cartAttributes = getCartAttributes({
2369
+ profile,
2370
+ customer,
2371
+ memberType,
2372
+ currentUrl: window.location.href
2373
+ });
2374
+ const linesWithFunctionAttributes = getLinesWithAttributes({
2375
+ lineItems
2376
+ });
2377
+ const lines = linesWithFunctionAttributes.map((item) => ({
2378
+ merchandiseId: item.variant?.id || "",
2379
+ quantity: item.quantity || 1,
2380
+ attributes: item.attributes,
2381
+ sellingPlanId: item.sellingPlanId
2382
+ })).filter((item) => item.merchandiseId);
2383
+ if (lines.length === 0) {
2384
+ return;
2385
+ }
2386
+ const resultCart = await createCart(client, {
2387
+ lines,
2388
+ metafieldIdentifiers,
2389
+ cookieAdapter: cartCookieAdapter,
2390
+ buyerIdentity,
2391
+ discountCodes,
2392
+ customAttributes: [...cartAttributes, ...customAttributes || []]
2393
+ });
2394
+ if (!resultCart) {
2395
+ throw new Error("Failed to create cart for buy now");
2396
+ }
2397
+ if (withTrack && resultCart.lineItems) {
2398
+ trackBuyNowGA({
2399
+ lineItems,
2400
+ gtmParams: { ...gtmParams, brand: config.getBrand() }
2401
+ });
2402
+ if (fbqTrackConfig) {
2403
+ trackBuyNowFBQ({ trackConfig: fbqTrackConfig });
2224
2404
  }
2225
- brand {
2226
- logo {
2227
- image {
2228
- url
2229
- }
2230
- }
2231
- colors {
2232
- primary {
2233
- background
2234
- }
2235
- secondary {
2236
- background
2237
- }
2405
+ }
2406
+ if (redirectToCheckout) {
2407
+ if (resultCart.url) {
2408
+ if (typeof window !== "undefined") {
2409
+ window.location.href = resultCart.url;
2238
2410
  }
2411
+ } else {
2412
+ throw new Error("Failed to get checkout URL");
2239
2413
  }
2240
- ${hasMetafields ? "metafields(identifiers: $shopMetafieldIdentifiers) { key value }" : ""}
2241
2414
  }
2242
- }
2243
- `
2415
+ return resultCart;
2416
+ },
2417
+ [client, locale, isLoggedIn, cartCookieAdapter, withTrack, customer, profile, memberSetting]
2244
2418
  );
2245
- const variables = {};
2246
- if (hasMetafields) {
2247
- variables.shopMetafieldIdentifiers = metafieldIdentifiers;
2248
- }
2249
- const data = await client.query(query, variables);
2250
- if (!data || !data.shop) {
2251
- return void 0;
2252
- }
2253
- const shop = data.shop;
2254
- const metafields = shop.metafields?.reduce((acc, mf) => {
2255
- if (mf && mf.key) {
2256
- acc[mf.key] = mf.value;
2257
- }
2258
- return acc;
2259
- }, {});
2260
- return {
2261
- name: shop.name,
2262
- description: shop.description,
2263
- primaryDomain: shop.primaryDomain,
2264
- brand: shop.brand ? {
2265
- logo: shop.brand.logo,
2266
- colors: shop.brand.colors ? {
2267
- primary: shop.brand.colors.primary?.background,
2268
- secondary: shop.brand.colors.secondary?.background
2269
- } : void 0
2270
- } : void 0,
2271
- metafields
2272
- };
2419
+ return useSWRMutation("buy-now", buyNow, swrOptions);
2273
2420
  }
2274
- function useSite(options = {}) {
2421
+
2422
+ // src/hooks/cart/types/price-discount.ts
2423
+ var PriceDiscountType = /* @__PURE__ */ ((PriceDiscountType2) => {
2424
+ PriceDiscountType2[PriceDiscountType2["PERCENTAGE"] = 1] = "PERCENTAGE";
2425
+ PriceDiscountType2[PriceDiscountType2["FIXED_AMOUNT"] = 2] = "FIXED_AMOUNT";
2426
+ return PriceDiscountType2;
2427
+ })(PriceDiscountType || {});
2428
+ var PriceBasePriceType = /* @__PURE__ */ ((PriceBasePriceType2) => {
2429
+ PriceBasePriceType2[PriceBasePriceType2["MIN_DISCOUNTED_PRICE"] = 1] = "MIN_DISCOUNTED_PRICE";
2430
+ PriceBasePriceType2[PriceBasePriceType2["MIN_TOTAL_PRICE"] = 2] = "MIN_TOTAL_PRICE";
2431
+ return PriceBasePriceType2;
2432
+ })(PriceBasePriceType || {});
2433
+ function useProduct(options = {}) {
2275
2434
  const { client, locale } = useShopify();
2276
- const { metafieldIdentifiers, ...swrOptions } = options;
2435
+ const { handle, metafieldIdentifiers, ...swrOptions } = options;
2277
2436
  return useSWR(
2278
- ["site", locale, metafieldIdentifiers],
2279
- () => getSiteInfo(client, locale, metafieldIdentifiers),
2437
+ handle ? ["product", locale, handle, metafieldIdentifiers] : null,
2438
+ () => getProduct(client, {
2439
+ handle,
2440
+ locale,
2441
+ metafieldIdentifiers
2442
+ }),
2280
2443
  swrOptions
2281
2444
  );
2282
2445
  }
2283
-
2284
- // src/hooks/member/plus/types.ts
2285
- var PLUS_MEMBER_TYPE = /* @__PURE__ */ ((PLUS_MEMBER_TYPE2) => {
2286
- PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["FREE"] = 0] = "FREE";
2287
- PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["MONTHLY"] = 1] = "MONTHLY";
2288
- PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["ANNUAL"] = 2] = "ANNUAL";
2289
- return PLUS_MEMBER_TYPE2;
2290
- })(PLUS_MEMBER_TYPE || {});
2291
- var PlusMemberMode = /* @__PURE__ */ ((PlusMemberMode2) => {
2292
- PlusMemberMode2["MONTHLY"] = "monthly";
2293
- PlusMemberMode2["ANNUAL"] = "annual";
2294
- return PlusMemberMode2;
2295
- })(PlusMemberMode || {});
2296
- var DeliveryPlusType = /* @__PURE__ */ ((DeliveryPlusType2) => {
2297
- DeliveryPlusType2["FREE"] = "free";
2298
- DeliveryPlusType2["MONTHLY"] = "monthly";
2299
- DeliveryPlusType2["ANNUAL"] = "annual";
2300
- return DeliveryPlusType2;
2301
- })(DeliveryPlusType || {});
2302
- var ShippingMethodMode = /* @__PURE__ */ ((ShippingMethodMode2) => {
2303
- ShippingMethodMode2["FREE"] = "free";
2304
- ShippingMethodMode2["TDD"] = "tdd";
2305
- ShippingMethodMode2["NDD"] = "ndd";
2306
- return ShippingMethodMode2;
2307
- })(ShippingMethodMode || {});
2308
- var createInitialValue = () => ({
2309
- zipCode: "",
2310
- plusMemberMetafields: {},
2311
- setZipCode: () => {
2312
- },
2313
- allowNextDayDelivery: false,
2314
- setAllowNextDayDelivery: () => {
2315
- },
2316
- allowThirdDayDelivery: false,
2317
- setAllowThirdDayDelivery: () => {
2318
- },
2319
- selectedPlusMemberMode: "free",
2320
- setSelectedPlusMemberMode: () => {
2321
- },
2322
- showAreaCheckModal: false,
2323
- setShowAreaCheckModal: () => {
2324
- },
2325
- selectedShippingMethod: void 0,
2326
- setSelectedShippingMethod: () => {
2327
- },
2328
- showTip: false,
2329
- setShowTip: () => {
2330
- },
2331
- showMoreShippingMethod: false,
2332
- setShowMoreShippingMethod: () => {
2333
- },
2334
- variant: {},
2335
- product: {},
2336
- shippingMethodsContext: {
2337
- freeShippingMethods: [],
2338
- paymentShippingMethods: [],
2339
- nddOverweight: false,
2340
- tddOverweight: false
2341
- },
2342
- selectedPlusMemberProduct: null,
2343
- plusMemberProducts: [],
2344
- showPlusMemberBenefit: false,
2345
- setShowPlusMemberBenefit: () => {
2346
- },
2347
- deleteMarginBottom: false,
2348
- setDeleteMarginBottom: () => {
2349
- },
2350
- profile: void 0,
2351
- locale: void 0
2352
- });
2353
- var PlusMemberContext = createContext(createInitialValue());
2354
- function usePlusMemberContext() {
2355
- return useContext(PlusMemberContext);
2356
- }
2357
- function usePlusMonthlyProductVariant() {
2358
- const { plusMemberProducts, plusMemberMetafields } = usePlusMemberContext();
2359
- const plusMonthly = plusMemberMetafields?.plus_monthly_product;
2360
- const plusMonthlyProductVariant = useMemo(() => {
2361
- const product = plusMemberProducts?.find(
2362
- (item) => item?.handle === plusMonthly?.handle
2363
- );
2364
- const productVariant = product?.variants?.find(
2365
- (item) => item.sku === plusMonthly?.sku
2366
- );
2367
- return productVariant;
2368
- }, [plusMemberProducts, plusMonthly]);
2369
- return plusMonthlyProductVariant;
2446
+ function useAllProducts(options = {}) {
2447
+ const { client, locale } = useShopify();
2448
+ const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2449
+ return useSWR(
2450
+ ["all-products", locale, first, query, sortKey, reverse, metafieldIdentifiers],
2451
+ () => getAllProducts(client, {
2452
+ locale,
2453
+ first,
2454
+ query,
2455
+ sortKey,
2456
+ reverse,
2457
+ metafieldIdentifiers
2458
+ }),
2459
+ swrOptions
2460
+ );
2370
2461
  }
2371
- function usePlusAnnualProductVariant() {
2372
- const { plusMemberProducts, plusMemberMetafields } = usePlusMemberContext();
2373
- const plusAnnual = plusMemberMetafields?.plus_annual_product;
2374
- const plusAnnualProductVariant = useMemo(() => {
2375
- const product = plusMemberProducts?.find(
2376
- (item) => item?.handle === plusAnnual?.handle
2377
- );
2378
- const productVariant = product?.variants?.find(
2379
- (item) => item.sku === plusAnnual?.sku
2380
- );
2381
- return productVariant;
2382
- }, [plusMemberProducts, plusAnnual]);
2383
- return plusAnnualProductVariant;
2462
+ function getFirstAvailableVariant(product) {
2463
+ const availableVariant = product.variants.find((v) => v.availableForSale);
2464
+ return availableVariant || product.variants[0];
2384
2465
  }
2385
- function useShippingMethods(options) {
2386
- const {
2387
- variant,
2388
- plusMemberMetafields,
2389
- selectedPlusMemberMode,
2390
- isPlus = false,
2391
- nddCoupon,
2392
- tddCoupon
2393
- } = options;
2394
- const { plus_shipping, shippingMethod } = plusMemberMetafields || {};
2395
- const nddOverweight = useMemo(() => {
2396
- return (variant?.weight || 0) > (shippingMethod?.overWeight_ndd || Infinity);
2397
- }, [shippingMethod?.overWeight_ndd, variant?.weight]);
2398
- const tddOverweight = useMemo(() => {
2399
- return (variant?.weight || 0) > (shippingMethod?.overWeight_tdd || Infinity);
2400
- }, [shippingMethod?.overWeight_tdd, variant?.weight]);
2401
- const paymentShippingMethods = useMemo(() => {
2402
- const weight = variant?.weight || 0;
2403
- const methods = plus_shipping?.shipping_methods?.filter(
2404
- ({ weight_low, weight_high, __mode, __plus }) => {
2405
- const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
2406
- return __mode !== "free" /* FREE */ && !__plus && fitWeight;
2407
- }
2408
- ) || [];
2409
- return methods.map((method) => {
2410
- let disabled = false;
2411
- const selectedFreeMember = selectedPlusMemberMode === "free";
2412
- if (method.__mode === "ndd" /* NDD */) {
2413
- disabled = selectedFreeMember || nddOverweight;
2414
- } else if (method.__mode === "tdd" /* TDD */) {
2415
- disabled = selectedFreeMember || tddOverweight;
2416
- }
2417
- return {
2418
- ...method,
2419
- id: method.__mode + method.__code,
2420
- useCoupon: false,
2421
- subtitle: plus_shipping?.directly || "",
2422
- disabled
2423
- };
2466
+ function getVariantFromSelectedOptions(product, selectedOptions) {
2467
+ return product.variants.find((variant) => {
2468
+ return variant.selectedOptions.every((option) => {
2469
+ return selectedOptions[option.name] === option.value;
2424
2470
  });
2425
- }, [
2426
- nddOverweight,
2427
- plus_shipping?.directly,
2428
- plus_shipping?.shipping_methods,
2429
- selectedPlusMemberMode,
2430
- tddOverweight,
2431
- variant?.weight
2432
- ]);
2433
- const nddPrice = useMemo(() => {
2434
- const weight = variant?.weight || 0;
2435
- const nddMethod = paymentShippingMethods.find(
2436
- ({ __mode, weight_high, weight_low }) => {
2437
- const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
2438
- return __mode === "ndd" && fitWeight;
2439
- }
2440
- );
2441
- return nddMethod?.price || 0;
2442
- }, [variant?.weight, paymentShippingMethods]);
2443
- const tddPrice = useMemo(() => {
2444
- const weight = variant?.weight || 0;
2445
- const tddMethod = paymentShippingMethods.find(
2446
- ({ __mode, weight_high, weight_low }) => {
2447
- const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
2448
- return __mode === "tdd" && fitWeight;
2449
- }
2450
- );
2451
- return tddMethod?.price || 0;
2452
- }, [variant?.weight, paymentShippingMethods]);
2453
- const freeShippingMethods = useMemo(() => {
2454
- const weight = variant?.weight || 0;
2455
- let methods = plus_shipping?.shipping_methods?.filter(
2456
- ({ __mode, __plus, weight_low, weight_high }) => {
2457
- if (__mode === "free" /* FREE */) {
2458
- return true;
2459
- }
2460
- if (isPlus) {
2461
- const hasCoupon = isPlus && __mode === "ndd" /* NDD */ && nddCoupon || isPlus && __mode === "tdd" /* TDD */ && (tddCoupon || nddCoupon);
2462
- const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
2463
- return hasCoupon && fitWeight && !__plus;
2464
- } else {
2465
- return __plus;
2466
- }
2467
- }
2468
- ) || [];
2469
- if (isPlus) {
2470
- methods = methods.sort((a, b) => {
2471
- if (b.__mode === "free" /* FREE */) return -1;
2472
- return 0;
2473
- });
2471
+ });
2472
+ }
2473
+ function useVariant({
2474
+ product,
2475
+ selectedOptions
2476
+ }) {
2477
+ const [variant, setVariant] = useState(
2478
+ product ? getFirstAvailableVariant(product) : void 0
2479
+ );
2480
+ useEffect(() => {
2481
+ if (!product) {
2482
+ setVariant(void 0);
2483
+ return;
2474
2484
  }
2475
- return methods.map((method) => {
2476
- let price = 0;
2477
- let coupon;
2478
- let disabled;
2479
- if (method.__mode !== "free" /* FREE */) {
2480
- switch (method.__mode) {
2481
- case "tdd":
2482
- price = tddPrice;
2483
- coupon = tddCoupon || nddCoupon;
2484
- break;
2485
- case "ndd":
2486
- price = nddPrice;
2487
- coupon = nddCoupon;
2488
- break;
2489
- }
2490
- disabled = selectedPlusMemberMode === "free";
2491
- if (method.__mode === "ndd" /* NDD */) {
2492
- disabled = disabled || nddOverweight;
2493
- } else if (method.__mode === "tdd" /* TDD */) {
2494
- disabled = disabled || tddOverweight;
2495
- }
2496
- }
2497
- return {
2498
- ...method,
2499
- id: method.__mode + method.__code,
2500
- useCoupon: true,
2501
- disabled,
2502
- coupon,
2503
- price
2504
- };
2505
- });
2506
- }, [
2507
- variant?.weight,
2508
- plus_shipping?.shipping_methods,
2509
- isPlus,
2510
- nddCoupon,
2511
- tddCoupon,
2512
- selectedPlusMemberMode,
2513
- tddPrice,
2514
- nddPrice,
2515
- nddOverweight,
2516
- tddOverweight
2517
- ]);
2485
+ const newVariant = getVariantFromSelectedOptions(product, selectedOptions);
2486
+ if (newVariant && newVariant.id !== variant?.id) {
2487
+ setVariant(newVariant);
2488
+ } else if (!newVariant) {
2489
+ setVariant(getFirstAvailableVariant(product));
2490
+ }
2491
+ }, [selectedOptions, product, variant?.id]);
2492
+ return variant;
2493
+ }
2494
+ var FAKE_PRICE = 999999999e-2;
2495
+ function formatPrice({
2496
+ amount,
2497
+ currencyCode,
2498
+ locale,
2499
+ maximumFractionDigits,
2500
+ minimumFractionDigits,
2501
+ removeTrailingZeros
2502
+ }) {
2503
+ const formatter = new Intl.NumberFormat(locale, {
2504
+ style: "currency",
2505
+ currency: currencyCode,
2506
+ maximumFractionDigits: maximumFractionDigits ?? 2,
2507
+ minimumFractionDigits: minimumFractionDigits ?? 2
2508
+ });
2509
+ let formatted = formatter.format(amount);
2510
+ if (removeTrailingZeros) {
2511
+ formatted = formatted.replace(/\.00$/, "");
2512
+ }
2513
+ return formatted;
2514
+ }
2515
+ function formatVariantPrice({
2516
+ amount,
2517
+ baseAmount,
2518
+ currencyCode,
2519
+ locale,
2520
+ maximumFractionDigits,
2521
+ minimumFractionDigits,
2522
+ removeTrailingZeros
2523
+ }) {
2518
2524
  return {
2519
- freeShippingMethods,
2520
- paymentShippingMethods,
2521
- nddOverweight,
2522
- tddOverweight
2525
+ price: formatPrice({
2526
+ amount,
2527
+ currencyCode,
2528
+ locale,
2529
+ maximumFractionDigits,
2530
+ minimumFractionDigits,
2531
+ removeTrailingZeros
2532
+ }),
2533
+ basePrice: formatPrice({
2534
+ amount: baseAmount,
2535
+ currencyCode,
2536
+ locale,
2537
+ maximumFractionDigits,
2538
+ minimumFractionDigits,
2539
+ removeTrailingZeros
2540
+ })
2523
2541
  };
2524
2542
  }
2525
- function useShippingMethodAvailableCheck() {
2526
- const {
2527
- zipCode,
2528
- allowNextDayDelivery,
2529
- allowThirdDayDelivery,
2530
- selectedShippingMethod,
2531
- setSelectedShippingMethod,
2532
- setShowTip,
2533
- shippingMethodsContext
2534
- } = usePlusMemberContext();
2535
- useEffect(() => {
2536
- const freeShippingMethod = shippingMethodsContext.freeShippingMethods[0];
2537
- const standardShippingMethod = shippingMethodsContext.freeShippingMethods?.find(
2538
- (item) => item.__mode === "free" /* FREE */
2539
- );
2540
- const freeTDD = shippingMethodsContext.freeShippingMethods.find(
2541
- (item) => item.__mode === "tdd" /* TDD */
2542
- );
2543
- const paymentTDD = shippingMethodsContext.paymentShippingMethods.find(
2544
- (item) => item.__mode === "tdd" /* TDD */
2545
- );
2546
- if (zipCode) {
2547
- console.log(
2548
- "allowNextDayDelivery, allowThirdDayDelivery:",
2549
- allowNextDayDelivery,
2550
- allowThirdDayDelivery
2551
- );
2552
- if (!allowNextDayDelivery && !allowThirdDayDelivery) {
2553
- setShowTip(true);
2554
- setSelectedShippingMethod(standardShippingMethod);
2555
- } else {
2556
- if (selectedShippingMethod?.__mode === "ndd" /* NDD */ && !allowNextDayDelivery) {
2557
- setShowTip(true);
2558
- if (allowThirdDayDelivery) {
2559
- if (selectedShippingMethod.useCoupon) {
2560
- const method = freeTDD || freeShippingMethod;
2561
- if (method) setSelectedShippingMethod(method);
2562
- } else {
2563
- const method = paymentTDD || freeShippingMethod;
2564
- if (method) setSelectedShippingMethod(method);
2565
- }
2566
- } else {
2567
- if (freeShippingMethod) setSelectedShippingMethod(freeShippingMethod);
2568
- }
2569
- } else if (
2570
- // TDD 无法使用
2571
- selectedShippingMethod?.__mode === "tdd" /* TDD */ && !allowThirdDayDelivery
2572
- ) {
2573
- setShowTip(true);
2574
- if (freeShippingMethod) setSelectedShippingMethod(freeShippingMethod);
2575
- }
2576
- }
2543
+ function usePrice({
2544
+ amount,
2545
+ baseAmount,
2546
+ currencyCode,
2547
+ soldOutDescription = "",
2548
+ maximumFractionDigits,
2549
+ minimumFractionDigits,
2550
+ removeTrailingZeros
2551
+ }) {
2552
+ const { locale } = useShopify();
2553
+ const value = useMemo(() => {
2554
+ if (typeof amount !== "number" || !currencyCode) {
2555
+ return "";
2577
2556
  }
2578
- }, [
2579
- allowNextDayDelivery,
2580
- allowThirdDayDelivery,
2581
- zipCode,
2582
- shippingMethodsContext,
2583
- selectedShippingMethod,
2584
- setSelectedShippingMethod,
2585
- setShowTip
2586
- ]);
2587
- }
2588
- var useReplaceCartPlusMember = () => {
2589
- const { plusMemberMetafields, selectedPlusMemberMode } = usePlusMemberContext();
2590
- const { trigger: removeCartLines2 } = useRemoveCartLines();
2591
- const { cart } = useCartContext();
2592
- const plusMonthly = plusMemberMetafields?.plus_monthly_product;
2593
- const plusAnnual = plusMemberMetafields?.plus_annual_product;
2594
- const handler = useCallback(async () => {
2595
- const plusMonthlyInCart = cart?.lineItems.find(
2596
- (item) => item.variant?.sku === plusMonthly?.sku
2597
- );
2598
- const plusAnnualInCart = cart?.lineItems.find(
2599
- (item) => item.variant?.sku === plusAnnual?.sku
2600
- );
2601
- if (selectedPlusMemberMode === "annual" /* ANNUAL */ && plusMonthlyInCart) {
2602
- await removeCartLines2({
2603
- lineIds: [plusMonthlyInCart.id]
2604
- });
2605
- } else if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && plusAnnualInCart) {
2606
- await removeCartLines2({
2607
- lineIds: [plusAnnualInCart.id]
2608
- });
2557
+ if (soldOutDescription && amount >= FAKE_PRICE) {
2558
+ return soldOutDescription;
2609
2559
  }
2560
+ return baseAmount ? formatVariantPrice({
2561
+ amount,
2562
+ baseAmount,
2563
+ currencyCode,
2564
+ locale,
2565
+ maximumFractionDigits,
2566
+ minimumFractionDigits,
2567
+ removeTrailingZeros
2568
+ }) : formatPrice({
2569
+ amount,
2570
+ currencyCode,
2571
+ locale,
2572
+ maximumFractionDigits,
2573
+ minimumFractionDigits,
2574
+ removeTrailingZeros
2575
+ });
2610
2576
  }, [
2611
- cart?.lineItems,
2612
- selectedPlusMemberMode,
2613
- plusMonthly?.sku,
2614
- plusAnnual?.sku,
2615
- removeCartLines2
2577
+ amount,
2578
+ baseAmount,
2579
+ currencyCode,
2580
+ locale,
2581
+ maximumFractionDigits,
2582
+ minimumFractionDigits,
2583
+ soldOutDescription,
2584
+ removeTrailingZeros
2616
2585
  ]);
2617
- return handler;
2618
- };
2619
- var usePlusMemberDeliveryCodes = ({
2620
- deliveryData
2621
- }) => {
2622
- return useMemo(
2623
- () => deliveryData?.deliveryCustomData?.discount_code,
2624
- [deliveryData]
2625
- );
2626
- };
2627
- var usePlusMemberItemCustomAttributes = ({
2628
- deliveryData
2629
- }) => {
2630
- const { deliveryCustomData } = deliveryData || {};
2631
- return useMemo(() => {
2632
- const itemCustomAttributes = [];
2633
- if (deliveryCustomData?.is_presale) {
2634
- itemCustomAttributes.push({
2635
- key: "_is_presale",
2636
- value: "true"
2637
- });
2638
- }
2639
- return itemCustomAttributes;
2640
- }, [deliveryCustomData]);
2641
- };
2642
- var usePlusMemberCheckoutCustomAttributes = ({
2643
- deliveryData,
2644
- product,
2645
- variant,
2646
- customer,
2647
- isShowShippingBenefits
2648
- }) => {
2649
- const { deliveryCustomData } = deliveryData || {};
2650
- const { profile } = usePlusMemberContext();
2651
- const userType = useMemo(() => {
2652
- const customerInfo = customer;
2653
- if (!customerInfo) {
2654
- return "new_user_unlogin";
2655
- }
2656
- if (customer) {
2657
- const { orders = {} } = customer;
2658
- const edgesLength = orders?.edges?.length;
2659
- if (edgesLength === 1) {
2660
- return "old_user_orders_once";
2661
- } else if (edgesLength && edgesLength > 1) {
2662
- return "old_user_orders_twice";
2663
- }
2586
+ const result = useMemo(() => {
2587
+ const free = Boolean(amount && amount <= 0);
2588
+ return typeof value === "string" ? { price: value, basePrice: value, free } : { ...value, free };
2589
+ }, [value, amount]);
2590
+ return result;
2591
+ }
2592
+ function optionsConstructor(selectedOptions) {
2593
+ return selectedOptions.reduce((acc, option) => {
2594
+ acc[option.name] = option.value;
2595
+ return acc;
2596
+ }, {});
2597
+ }
2598
+ function decodeShopifyId(gid) {
2599
+ try {
2600
+ const base64 = gid.split("/").pop() || "";
2601
+ return atob(base64);
2602
+ } catch {
2603
+ return gid;
2604
+ }
2605
+ }
2606
+ function useSelectedOptions(product, sku) {
2607
+ const [options, setOptions] = useState({});
2608
+ useEffect(() => {
2609
+ if (!product || !product.variants.length) {
2610
+ setOptions({});
2611
+ return;
2664
2612
  }
2665
- return "new_user_login";
2666
- }, [customer]);
2667
- return useMemo(() => {
2668
- const checkoutCustomAttributes = [
2669
- {
2670
- key: "_token",
2671
- value: profile?.token || ""
2672
- },
2673
- {
2674
- key: "_last_url",
2675
- value: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
2676
- },
2677
- {
2678
- key: "_user_type",
2679
- value: userType
2613
+ let variant = product.variants[0];
2614
+ if (typeof window !== "undefined") {
2615
+ const searchParams = new URLSearchParams(window.location.search);
2616
+ const variantIdParam = searchParams.get("variant");
2617
+ if (variantIdParam) {
2618
+ const foundVariant = product.variants.find((v) => {
2619
+ if (sku) return v.sku === sku;
2620
+ return v.id === variantIdParam || v.id.includes(variantIdParam) || decodeShopifyId(v.id) === variantIdParam;
2621
+ });
2622
+ if (foundVariant) {
2623
+ variant = foundVariant;
2624
+ }
2680
2625
  }
2681
- ];
2682
- if (profile) {
2683
- checkoutCustomAttributes.push({
2684
- key: "_login_user",
2685
- value: "1"
2686
- });
2687
2626
  }
2688
- if (deliveryCustomData) {
2689
- checkoutCustomAttributes.push({
2690
- key: "_checkout_delivery_custom",
2691
- value: JSON.stringify({
2692
- ...deliveryCustomData,
2693
- is_prime: profile?.isPlus
2694
- })
2695
- });
2627
+ if (variant) {
2628
+ const newOptions = optionsConstructor(variant.selectedOptions);
2629
+ setOptions(newOptions);
2696
2630
  }
2697
- if (variant?.metafields?.presell) {
2698
- checkoutCustomAttributes.push({
2699
- key: "_presale",
2700
- value: "true"
2701
- });
2631
+ }, [product, sku]);
2632
+ return [options, setOptions];
2633
+ }
2634
+ function decodeShopifyId2(gid) {
2635
+ try {
2636
+ const parts = gid.split("/");
2637
+ return parts[parts.length - 1] || gid;
2638
+ } catch {
2639
+ return gid;
2640
+ }
2641
+ }
2642
+ function useProductUrl(otherQuery) {
2643
+ const { routerAdapter } = useShopify();
2644
+ return useCallback(
2645
+ ({ product, variant }) => {
2646
+ if (!product) return "";
2647
+ const queryParams = new URLSearchParams();
2648
+ if (variant?.id) {
2649
+ const variantId = decodeShopifyId2(variant.id);
2650
+ if (variantId) {
2651
+ queryParams.set("variant", variantId);
2652
+ }
2653
+ }
2654
+ if (otherQuery) {
2655
+ Object.entries(otherQuery).forEach(([key, value]) => {
2656
+ queryParams.set(key, value);
2657
+ });
2658
+ }
2659
+ const queryString = queryParams.toString();
2660
+ const path = `/products/${product.handle}${queryString ? `?${queryString}` : ""}`;
2661
+ if (routerAdapter?.getLocalizedPath) {
2662
+ return routerAdapter.getLocalizedPath(path);
2663
+ }
2664
+ return path;
2665
+ },
2666
+ [routerAdapter, otherQuery]
2667
+ );
2668
+ }
2669
+ function decodeShopifyId3(gid) {
2670
+ try {
2671
+ const parts = gid.split("/");
2672
+ return parts[parts.length - 1] || gid;
2673
+ } catch {
2674
+ return gid;
2675
+ }
2676
+ }
2677
+ function useUpdateVariantQuery(variant) {
2678
+ useEffect(() => {
2679
+ if (!variant || typeof window === "undefined") {
2680
+ return;
2702
2681
  }
2703
- if (isShowShippingBenefits && !isShowShippingBenefits({ variant, product, setting: {} })) {
2704
- checkoutCustomAttributes.push({
2705
- key: "_hide_shipping",
2706
- value: "true"
2682
+ const searchParams = new URLSearchParams(window.location.search);
2683
+ const currentVariantId = searchParams.get("variant");
2684
+ const newVariantId = decodeShopifyId3(variant.id);
2685
+ if (newVariantId && currentVariantId !== newVariantId) {
2686
+ searchParams.set("variant", newVariantId);
2687
+ const newUrl = `${window.location.pathname}?${searchParams.toString()}${window.location.hash}`;
2688
+ window.history.replaceState({}, "", newUrl);
2689
+ }
2690
+ }, [variant]);
2691
+ }
2692
+ function getVariantMediaList({
2693
+ product,
2694
+ variant
2695
+ }) {
2696
+ if (variant.image?.url) {
2697
+ const variantMediaId = variant.image.url;
2698
+ const variantMedia = product.media.filter((media) => {
2699
+ if (media.mediaContentType === "IMAGE" && media.previewImage) {
2700
+ return media.previewImage?.url === variantMediaId;
2701
+ }
2702
+ return false;
2703
+ });
2704
+ if (variantMedia.length > 0) {
2705
+ const otherMedia = product.media.filter((media) => {
2706
+ if (media.mediaContentType === "IMAGE" && media.previewImage) {
2707
+ return media.previewImage.url !== variantMediaId;
2708
+ }
2709
+ return true;
2707
2710
  });
2711
+ return [...variantMedia, ...otherMedia];
2708
2712
  }
2709
- return checkoutCustomAttributes;
2710
- }, [deliveryCustomData, product, profile, userType, variant, isShowShippingBenefits]);
2711
- };
2712
- function useAutoRemovePlusMemberInCart({
2713
- cart,
2714
- profile,
2715
- memberSetting
2713
+ }
2714
+ return product.media;
2715
+ }
2716
+ function useVariantMedia({
2717
+ product,
2718
+ variant
2716
2719
  }) {
2717
- const { plus_monthly_product, plus_annual_product } = memberSetting || {};
2718
- const { trigger: removeCartLines2 } = useRemoveCartLines();
2720
+ const [imageList, setImageList] = useState([]);
2721
+ const [sceneList, setSceneList] = useState([]);
2722
+ const [videoList, setVideoList] = useState([]);
2719
2723
  useEffect(() => {
2720
- if (!cart || !plus_monthly_product || !plus_annual_product) return;
2721
- const removePlusProduct = async (productType) => {
2722
- if (!productType) return;
2723
- const product = cart.lineItems?.find(
2724
- (item) => item.product?.handle === productType?.handle && item.variant?.sku === productType?.sku
2725
- );
2726
- if (product) {
2727
- await removeCartLines2({
2728
- lineIds: [product.id]
2729
- });
2724
+ if (!product || !variant) {
2725
+ setImageList([]);
2726
+ setSceneList([]);
2727
+ setVideoList([]);
2728
+ return;
2729
+ }
2730
+ const mediaList = getVariantMediaList({ product, variant });
2731
+ const images = mediaList.filter((media) => media.mediaContentType === "IMAGE");
2732
+ const videos = mediaList.filter(
2733
+ (media) => media.mediaContentType === "VIDEO" || media.mediaContentType === "EXTERNAL_VIDEO"
2734
+ );
2735
+ setImageList(images.length > 0 && images[0] ? [images[0]] : []);
2736
+ setSceneList(images.length > 1 ? images.slice(1) : []);
2737
+ setVideoList(videos);
2738
+ }, [product, variant]);
2739
+ return {
2740
+ productList: imageList,
2741
+ sceneList,
2742
+ videoList
2743
+ };
2744
+ }
2745
+ function useCollection(options = {}) {
2746
+ const { client, locale } = useShopify();
2747
+ const { handle, metafieldIdentifiers, ...swrOptions } = options;
2748
+ return useSWR(
2749
+ handle ? ["collection", locale, handle, metafieldIdentifiers] : null,
2750
+ () => getCollection(client, {
2751
+ handle,
2752
+ locale,
2753
+ metafieldIdentifiers
2754
+ }),
2755
+ swrOptions
2756
+ );
2757
+ }
2758
+ function useAllCollections(options = {}) {
2759
+ const { client, locale } = useShopify();
2760
+ const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2761
+ return useSWR(
2762
+ ["all-collections", locale, first, query, sortKey, reverse, metafieldIdentifiers],
2763
+ () => getAllCollections(client, {
2764
+ locale,
2765
+ first,
2766
+ query,
2767
+ sortKey,
2768
+ reverse,
2769
+ metafieldIdentifiers
2770
+ }),
2771
+ swrOptions
2772
+ );
2773
+ }
2774
+ function useCollections(options = {}) {
2775
+ const { client, locale } = useShopify();
2776
+ const { first, after, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2777
+ return useSWR(
2778
+ ["collections", locale, first, after, query, sortKey, reverse, metafieldIdentifiers],
2779
+ () => getCollections(client, {
2780
+ locale,
2781
+ first,
2782
+ after,
2783
+ query,
2784
+ sortKey,
2785
+ reverse,
2786
+ metafieldIdentifiers
2787
+ }),
2788
+ swrOptions
2789
+ );
2790
+ }
2791
+ function useBlog(options = {}) {
2792
+ const { client, locale } = useShopify();
2793
+ const { handle, metafieldIdentifiers, ...swrOptions } = options;
2794
+ return useSWR(
2795
+ handle ? ["blog", locale, handle, metafieldIdentifiers] : null,
2796
+ () => getBlog(client, { handle, locale, metafieldIdentifiers }),
2797
+ swrOptions
2798
+ );
2799
+ }
2800
+ function useAllBlogs(options = {}) {
2801
+ const { client, locale } = useShopify();
2802
+ const { first, query, metafieldIdentifiers, ...swrOptions } = options;
2803
+ return useSWR(
2804
+ ["all-blogs", locale, first, query, metafieldIdentifiers],
2805
+ () => getAllBlogs(client, {
2806
+ locale,
2807
+ first,
2808
+ query,
2809
+ metafieldIdentifiers
2810
+ }),
2811
+ swrOptions
2812
+ );
2813
+ }
2814
+ function useArticle(options = {}) {
2815
+ const { client, locale } = useShopify();
2816
+ const { blogHandle, articleHandle, metafieldIdentifiers, ...swrOptions } = options;
2817
+ return useSWR(
2818
+ blogHandle && articleHandle ? ["article", locale, blogHandle, articleHandle, metafieldIdentifiers] : null,
2819
+ () => getArticle(client, {
2820
+ blogHandle,
2821
+ articleHandle,
2822
+ locale,
2823
+ metafieldIdentifiers
2824
+ }),
2825
+ swrOptions
2826
+ );
2827
+ }
2828
+ function useArticles(options = {}) {
2829
+ const { client, locale } = useShopify();
2830
+ const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2831
+ return useSWR(
2832
+ ["articles", locale, first, query, sortKey, reverse, metafieldIdentifiers],
2833
+ () => getArticles(client, {
2834
+ locale,
2835
+ first,
2836
+ query,
2837
+ sortKey,
2838
+ reverse,
2839
+ metafieldIdentifiers
2840
+ }),
2841
+ swrOptions
2842
+ );
2843
+ }
2844
+ function useArticlesInBlog(options = {}) {
2845
+ const { client, locale } = useShopify();
2846
+ const { blogHandle, first, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2847
+ return useSWR(
2848
+ blogHandle ? ["articles-in-blog", locale, blogHandle, first, sortKey, reverse, metafieldIdentifiers] : null,
2849
+ () => getArticlesInBlog(client, {
2850
+ blogHandle,
2851
+ locale,
2852
+ first,
2853
+ sortKey,
2854
+ reverse,
2855
+ metafieldIdentifiers
2856
+ }),
2857
+ swrOptions
2858
+ );
2859
+ }
2860
+ async function performSearch(client, locale, searchQuery, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"]) {
2861
+ if (!searchQuery) {
2862
+ return void 0;
2863
+ }
2864
+ const query = (
2865
+ /* GraphQL */
2866
+ `
2867
+ query search($query: String!, $first: Int!, $types: [SearchType!])
2868
+ @inContext(language: $language) {
2869
+ search(query: $query, first: $first, types: $types, unavailableProducts: HIDE) {
2870
+ totalCount
2871
+ edges {
2872
+ node {
2873
+ ... on Article {
2874
+ __typename
2875
+ id
2876
+ handle
2877
+ title
2878
+ excerpt
2879
+ image {
2880
+ url
2881
+ altText
2882
+ }
2883
+ }
2884
+ ... on Page {
2885
+ __typename
2886
+ id
2887
+ handle
2888
+ title
2889
+ }
2890
+ ... on Product {
2891
+ __typename
2892
+ id
2893
+ handle
2894
+ title
2895
+ description
2896
+ featuredImage {
2897
+ url
2898
+ altText
2899
+ }
2900
+ }
2901
+ }
2902
+ }
2903
+ pageInfo {
2904
+ hasNextPage
2905
+ endCursor
2906
+ }
2730
2907
  }
2731
- };
2732
- if (profile?.isMonthlyPlus) {
2733
- removePlusProduct(plus_monthly_product);
2734
2908
  }
2735
- if (profile?.isAnnualPlus) {
2736
- removePlusProduct(plus_annual_product);
2737
- }
2738
- }, [cart, plus_annual_product, plus_monthly_product, profile, removeCartLines2]);
2739
- }
2740
- function useAddPlusMemberProductsToCart({
2741
- cart,
2742
- profile
2743
- }) {
2744
- const { selectedPlusMemberMode, selectedPlusMemberProduct, plusMemberMetafields } = usePlusMemberContext();
2745
- const { hasMonthlyPlus, hasAnnualPlus } = useHasPlusMemberInCart({
2746
- memberSetting: plusMemberMetafields,
2747
- cart
2909
+ `
2910
+ );
2911
+ const data = await client.query(query, {
2912
+ query: searchQuery,
2913
+ first,
2914
+ types
2748
2915
  });
2749
- const plusMemberProduct = useMemo(() => {
2750
- if (!selectedPlusMemberProduct || selectedPlusMemberMode === "free" /* FREE */) {
2751
- return void 0;
2752
- }
2753
- if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && hasMonthlyPlus) {
2754
- return void 0;
2755
- }
2756
- if (selectedPlusMemberMode === "annual" /* ANNUAL */ && hasAnnualPlus) {
2757
- return void 0;
2758
- }
2759
- if (profile.isMonthlyPlus && selectedPlusMemberMode === "monthly" /* MONTHLY */) {
2760
- return void 0;
2761
- }
2762
- if (!profile.isAnnualPlus && selectedPlusMemberMode === "annual" /* ANNUAL */) {
2763
- return void 0;
2916
+ if (!data || !data.search) {
2917
+ return void 0;
2918
+ }
2919
+ const items = data.search.edges?.map((edge) => {
2920
+ const node = edge.node;
2921
+ const item = {
2922
+ type: node.__typename.toUpperCase(),
2923
+ id: node.id,
2924
+ handle: node.handle,
2925
+ title: node.title
2926
+ };
2927
+ if (node.__typename === "Product") {
2928
+ item.description = node.description;
2929
+ item.image = node.featuredImage ? {
2930
+ url: node.featuredImage.url,
2931
+ altText: node.featuredImage.altText
2932
+ } : void 0;
2933
+ } else if (node.__typename === "Article") {
2934
+ item.description = node.excerpt;
2935
+ item.image = node.image ? {
2936
+ url: node.image.url,
2937
+ altText: node.image.altText
2938
+ } : void 0;
2764
2939
  }
2765
- return selectedPlusMemberProduct;
2766
- }, [
2767
- selectedPlusMemberMode,
2768
- selectedPlusMemberProduct?.variant,
2769
- selectedPlusMemberProduct?.product,
2770
- hasMonthlyPlus,
2771
- hasAnnualPlus
2772
- ]);
2773
- return plusMemberProduct;
2940
+ return item;
2941
+ }) || [];
2942
+ return {
2943
+ items,
2944
+ totalCount: data.search.totalCount || 0,
2945
+ pageInfo: data.search.pageInfo
2946
+ };
2774
2947
  }
2775
- var PlusMemberProvider = ({
2776
- variant,
2777
- product,
2778
- memberSetting,
2779
- initialSelectedPlusMemberMode = "free",
2780
- profile,
2781
- locale,
2782
- children
2783
- }) => {
2784
- const [zipCode, setZipCode] = useState("");
2785
- const [showTip, setShowTip] = useState(false);
2786
- const [selectedPlusMemberMode, setSelectedPlusMemberMode] = useState(
2787
- initialSelectedPlusMemberMode
2948
+ function useSearch(options = {}) {
2949
+ const { client, locale } = useShopify();
2950
+ const { query, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"], ...swrOptions } = options;
2951
+ return useSWR(
2952
+ query ? ["search", locale, query, first, types] : null,
2953
+ () => performSearch(client, locale, query, first, types),
2954
+ swrOptions
2788
2955
  );
2789
- const [selectedShippingMethod, setSelectedShippingMethod] = useState();
2790
- const [allowNextDayDelivery, setAllowNextDayDelivery] = useState(false);
2791
- const [allowThirdDayDelivery, setAllowThirdDayDelivery] = useState(false);
2792
- const [showAreaCheckModal, setShowAreaCheckModal] = useState(false);
2793
- const [showMoreShippingMethod, setShowMoreShippingMethod] = useState(false);
2794
- const [showPlusMemberBenefit, setShowPlusMemberBenefit] = useState(false);
2795
- const [deleteMarginBottom, setDeleteMarginBottom] = useState(false);
2796
- const shippingMethodsContext = useShippingMethods({
2797
- variant,
2798
- plusMemberMetafields: memberSetting,
2799
- selectedPlusMemberMode});
2800
- const plusMemberHandles = useMemo(() => {
2801
- return [
2802
- memberSetting?.plus_monthly_product?.handle,
2803
- memberSetting?.plus_annual_product?.handle
2804
- ].filter(Boolean);
2805
- }, [memberSetting]);
2806
- const { data: plusMemberProducts = [] } = useProductsByHandles({
2807
- handles: plusMemberHandles
2808
- });
2809
- const selectedPlusMemberProduct = useMemo(() => {
2810
- if (selectedPlusMemberMode === "free" /* FREE */) {
2811
- return null;
2956
+ }
2957
+ async function getSiteInfo(client, locale, metafieldIdentifiers) {
2958
+ const hasMetafields = metafieldIdentifiers && metafieldIdentifiers.length > 0;
2959
+ const query = (
2960
+ /* GraphQL */
2961
+ `
2962
+ query getSiteInfo(
2963
+ ${hasMetafields ? "$shopMetafieldIdentifiers: [HasMetafieldsIdentifier!]!" : ""}
2964
+ ) @inContext(language: $language) {
2965
+ shop {
2966
+ name
2967
+ description
2968
+ primaryDomain {
2969
+ url
2970
+ host
2971
+ }
2972
+ brand {
2973
+ logo {
2974
+ image {
2975
+ url
2976
+ }
2977
+ }
2978
+ colors {
2979
+ primary {
2980
+ background
2981
+ }
2982
+ secondary {
2983
+ background
2984
+ }
2985
+ }
2986
+ }
2987
+ ${hasMetafields ? "metafields(identifiers: $shopMetafieldIdentifiers) { key value }" : ""}
2988
+ }
2812
2989
  }
2813
- const handle = selectedPlusMemberMode === "monthly" /* MONTHLY */ ? memberSetting?.plus_monthly_product?.handle : memberSetting?.plus_annual_product?.handle;
2814
- const sku = selectedPlusMemberMode === "monthly" /* MONTHLY */ ? memberSetting?.plus_monthly_product?.sku : memberSetting?.plus_annual_product?.sku;
2815
- const product2 = plusMemberProducts?.find((p) => p.handle === handle);
2816
- const variant2 = product2?.variants?.find((v) => v.sku === sku);
2817
- return product2 && variant2 ? { product: product2, variant: variant2 } : null;
2818
- }, [plusMemberProducts, memberSetting, selectedPlusMemberMode]);
2819
- return /* @__PURE__ */ jsx(
2820
- PlusMemberContext.Provider,
2821
- {
2822
- value: {
2823
- variant,
2824
- zipCode,
2825
- setZipCode,
2826
- allowNextDayDelivery,
2827
- setAllowNextDayDelivery,
2828
- allowThirdDayDelivery,
2829
- setAllowThirdDayDelivery,
2830
- plusMemberMetafields: memberSetting,
2831
- selectedPlusMemberMode,
2832
- setSelectedPlusMemberMode,
2833
- showAreaCheckModal,
2834
- setShowAreaCheckModal,
2835
- selectedShippingMethod,
2836
- setSelectedShippingMethod,
2837
- shippingMethodsContext,
2838
- showTip,
2839
- setShowTip,
2840
- showMoreShippingMethod,
2841
- setShowMoreShippingMethod,
2842
- selectedPlusMemberProduct,
2843
- plusMemberProducts,
2844
- product,
2845
- showPlusMemberBenefit,
2846
- setShowPlusMemberBenefit,
2847
- deleteMarginBottom,
2848
- setDeleteMarginBottom,
2849
- profile,
2850
- locale
2851
- },
2852
- children
2990
+ `
2991
+ );
2992
+ const variables = {};
2993
+ if (hasMetafields) {
2994
+ variables.shopMetafieldIdentifiers = metafieldIdentifiers;
2995
+ }
2996
+ const data = await client.query(query, variables);
2997
+ if (!data || !data.shop) {
2998
+ return void 0;
2999
+ }
3000
+ const shop = data.shop;
3001
+ const metafields = shop.metafields?.reduce((acc, mf) => {
3002
+ if (mf && mf.key) {
3003
+ acc[mf.key] = mf.value;
2853
3004
  }
3005
+ return acc;
3006
+ }, {});
3007
+ return {
3008
+ name: shop.name,
3009
+ description: shop.description,
3010
+ primaryDomain: shop.primaryDomain,
3011
+ brand: shop.brand ? {
3012
+ logo: shop.brand.logo,
3013
+ colors: shop.brand.colors ? {
3014
+ primary: shop.brand.colors.primary?.background,
3015
+ secondary: shop.brand.colors.secondary?.background
3016
+ } : void 0
3017
+ } : void 0,
3018
+ metafields
3019
+ };
3020
+ }
3021
+ function useSite(options = {}) {
3022
+ const { client, locale } = useShopify();
3023
+ const { metafieldIdentifiers, ...swrOptions } = options;
3024
+ return useSWR(
3025
+ ["site", locale, metafieldIdentifiers],
3026
+ () => getSiteInfo(client, locale, metafieldIdentifiers),
3027
+ swrOptions
2854
3028
  );
2855
- };
3029
+ }
2856
3030
  function useIntersection(targetRef, options) {
2857
3031
  const {
2858
3032
  callback,
@@ -3046,7 +3220,7 @@ function CartProvider({
3046
3220
  }) {
3047
3221
  const { client, cartCookieAdapter } = useShopify();
3048
3222
  const [customAttributes, setCustomAttributes] = useState([]);
3049
- const [customAttributesNeedDelete, setCustomAttributesNeedDelete] = useState(
3223
+ const [customAttributesNeedRemove, setCustomAttributesNeedRemove] = useState(
3050
3224
  []
3051
3225
  );
3052
3226
  const [isCodeChanging, setIsCodeChanging] = useState(false);
@@ -3074,15 +3248,34 @@ function CartProvider({
3074
3248
  refreshDeps: [locale]
3075
3249
  }
3076
3250
  );
3077
- const { trigger: updateAttributes } = useUpdateCartAttributes(mutateCart, metafieldIdentifiers);
3078
- const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
3251
+ const { trigger: updateAttributes } = useUpdateCartAttributes({
3252
+ mutate: mutateCart,
3253
+ metafieldIdentifiers,
3254
+ disabled: isCartLoading
3255
+ });
3256
+ const { hasPlusMember } = useHasPlusMemberInCart({
3257
+ memberSetting,
3258
+ cart
3259
+ });
3260
+ const { attributes: commonAttributes } = useCartAttributes({
3261
+ profile,
3262
+ customer,
3263
+ cart,
3264
+ memberType: hasPlusMember ? "2" : profile?.memberType
3265
+ });
3079
3266
  useRequest(
3080
3267
  () => {
3081
- const newAttributes = [...attributes, ...customAttributes];
3082
- const needUpdate = cart && !checkAttributesUpdateNeeded(
3268
+ const filteredSameCommonAttributes = commonAttributes.filter(
3269
+ (attr) => !customAttributes.some((a) => a.key === attr.key)
3270
+ );
3271
+ const newAttributes = [
3272
+ ...filteredSameCommonAttributes,
3273
+ ...customAttributes
3274
+ ];
3275
+ const needUpdate = cart && checkAttributesUpdateNeeded(
3083
3276
  cart.customAttributes,
3084
3277
  newAttributes,
3085
- customAttributesNeedDelete
3278
+ customAttributesNeedRemove
3086
3279
  );
3087
3280
  if (needUpdate) {
3088
3281
  return updateAttributes({ attributes: newAttributes });
@@ -3095,44 +3288,39 @@ function CartProvider({
3095
3288
  // 1 秒内只触发最后一次更新
3096
3289
  throttleTrailing: true,
3097
3290
  throttleLeading: false,
3098
- refreshDeps: [attributes, customAttributes]
3291
+ refreshDeps: [commonAttributes, customAttributes, customAttributesNeedRemove]
3099
3292
  }
3100
3293
  );
3101
3294
  useUpdateLineCodeAmountAttributes({
3102
3295
  cart,
3103
3296
  mutateCart,
3104
3297
  isCartLoading: isCartLoading || isCodeChanging,
3105
- setLoadingState
3298
+ setLoadingState,
3299
+ metafieldIdentifiers
3106
3300
  });
3107
3301
  const removeCustomAttributes = useCallback(
3108
- (attributes2) => {
3109
- setCustomAttributesNeedDelete(attributes2);
3302
+ (attributes) => {
3303
+ setCustomAttributesNeedRemove(attributes);
3110
3304
  },
3111
- [setCustomAttributesNeedDelete]
3305
+ [setCustomAttributesNeedRemove]
3112
3306
  );
3113
3307
  const addCustomAttributes = useCallback(
3114
- (attributes2) => {
3115
- const sameAttributes = attributes2.filter(
3116
- (attr) => customAttributes.some((a) => a.key === attr.key)
3117
- );
3118
- if (sameAttributes.length) {
3119
- setCustomAttributes((prev) => {
3120
- const removedAttributes = prev.filter(
3121
- (attr) => !sameAttributes.some((a) => a.key === attr.key)
3122
- );
3123
- return [...removedAttributes, ...attributes2];
3124
- });
3125
- } else {
3126
- setCustomAttributes((prev) => [...prev, ...attributes2]);
3127
- }
3308
+ (attributes) => {
3309
+ setCustomAttributes((oldCustomAttributes) => {
3310
+ const filteredSameAttributes = oldCustomAttributes.filter(
3311
+ (attr) => !attributes.some((a) => a.key === attr.key)
3312
+ );
3313
+ return [...filteredSameAttributes, ...attributes];
3314
+ });
3128
3315
  },
3129
- [customAttributes]
3316
+ [setCustomAttributes]
3130
3317
  );
3131
3318
  const functionAutoFreeGiftResult = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer);
3132
3319
  const scriptAutoFreeGiftResult = useScriptAutoFreeGift({
3133
3320
  campaign: gradientGiftsConfig || null,
3134
3321
  _giveaway: CUSTOMER_SCRIPT_GIFT_KEY,
3135
- cart
3322
+ cart,
3323
+ profile
3136
3324
  });
3137
3325
  const formattedScriptGifts = useMemo(() => {
3138
3326
  return formatScriptAutoFreeGift({
@@ -3183,16 +3371,23 @@ function CartProvider({
3183
3371
  );
3184
3372
  return result;
3185
3373
  }, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
3374
+ const totalQuantity = useMemo(() => {
3375
+ const cartLinesCount = cart?.lineItems.reduce((acc, item) => acc + item.quantity, 0) || 0;
3376
+ const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
3377
+ return cartLinesCount + giftLinesCount;
3378
+ }, [cart?.lineItems, giftNeedAddToCartLines]);
3186
3379
  const value = useMemo(
3187
3380
  () => ({
3381
+ totalQuantity,
3188
3382
  cart,
3189
3383
  isCartLoading,
3190
3384
  triggerFetch: fetchCart,
3191
3385
  mutateCart,
3192
3386
  addCustomAttributes,
3193
3387
  removeCustomAttributes,
3194
- setCustomAttributes,
3195
3388
  locale,
3389
+ profile,
3390
+ customer,
3196
3391
  isCodeChanging,
3197
3392
  setIsCodeChanging,
3198
3393
  autoFreeGiftConfig,
@@ -3208,10 +3403,12 @@ function CartProvider({
3208
3403
  scriptAutoFreeGiftResult,
3209
3404
  setScriptAutoFreeGift,
3210
3405
  giftNeedAddToCartLines,
3211
- metafieldIdentifiers
3406
+ metafieldIdentifiers,
3407
+ memberSetting
3212
3408
  }),
3213
3409
  [
3214
3410
  cart,
3411
+ totalQuantity,
3215
3412
  isCartLoading,
3216
3413
  fetchCart,
3217
3414
  mutateCart,
@@ -3231,19 +3428,22 @@ function CartProvider({
3231
3428
  scriptAutoFreeGiftResult,
3232
3429
  setScriptAutoFreeGift,
3233
3430
  giftNeedAddToCartLines,
3234
- metafieldIdentifiers
3431
+ metafieldIdentifiers,
3432
+ customer,
3433
+ profile,
3434
+ memberSetting
3235
3435
  ]
3236
3436
  );
3237
3437
  return /* @__PURE__ */ jsx(CartContext.Provider, { value, children });
3238
3438
  }
3239
- function useCartContext() {
3439
+ function useCartContext(options) {
3240
3440
  const context = useContext(CartContext);
3241
- if (!context) {
3441
+ if (!context && !options?.optional) {
3242
3442
  throw new Error("useCartContext must be used within a CartProvider");
3243
3443
  }
3244
3444
  return context;
3245
3445
  }
3246
3446
 
3247
- export { BuyRuleType, CODE_AMOUNT_KEY, CUSTOMER_ATTRIBUTE_KEY, CUSTOMER_SCRIPT_GIFT_KEY, CartProvider, DeliveryPlusType, MAIN_PRODUCT_CODE, OrderBasePriceType, OrderDiscountType, PLUS_MEMBER_TYPE, PlusMemberContext, PlusMemberMode, PlusMemberProvider, PriceBasePriceType, PriceDiscountType, RuleType, SCRIPT_CODE_AMOUNT_KEY, ShippingMethodMode, ShopifyContext, ShopifyProvider, SpendMoneyType, atobID, browserCartCookieAdapter, browserCookieAdapter, btoaID, checkAttributesUpdateNeeded, clearGeoLocationCache, createMockCartFromLines, currencyCodeMapping, defaultSWRMutationConfiguration, formatFunctionAutoFreeGift, formatScriptAutoFreeGift, gaTrack, getCachedGeoLocation, getDiscountEnvAttributeValue, getMatchedMainProductSubTotal, getQuery, getReferralAttributes, normalizeAddToCartLines, preCheck, safeParse, trackAddToCartFBQ, trackAddToCartGA, trackBeginCheckoutGA, trackBuyNowFBQ, trackBuyNowGA, useAddCartLines, useAddPlusMemberProductsToCart, useAddToCart, useAllBlogs, useAllCollections, useAllProducts, useApplyCartCodes, useArticle, useArticles, useArticlesInBlog, useAutoRemovePlusMemberInCart, useBlog, useBuyNow, useCalcAutoFreeGift, useCalcGiftsFromLines, useCalcOrderDiscount, useCartAttributes, useCartContext, useCartItemQuantityLimit, useCollection, useCollections, useCreateCart, useExposure, useGeoLocation, useHasPlusMemberInCart, useIntersection, usePlusAnnualProductVariant, usePlusMemberCheckoutCustomAttributes, usePlusMemberContext, usePlusMemberDeliveryCodes, usePlusMemberItemCustomAttributes, usePlusMonthlyProductVariant, usePrice, useProduct, useProductUrl, useProductsByHandles, useRemoveCartCodes, useRemoveCartLines, useReplaceCartPlusMember, useScriptAutoFreeGift, useSearch, useSelectedOptions, useShippingMethodAvailableCheck, useShippingMethods, useShopify, useSite, useUpdateCartAttributes, useUpdateCartLines, useUpdateLineCodeAmountAttributes, useUpdateVariantQuery, useVariant, useVariantMedia };
3447
+ export { BrowserPerformanceAdapter, BuyRuleType, CODE_AMOUNT_KEY, CUSTOMER_ATTRIBUTE_KEY, CUSTOMER_SCRIPT_GIFT_KEY, CartProvider, DeliveryPlusType, MAIN_PRODUCT_CODE, MEMBER_PRICE_ATTRIBUTE_KEY, OrderBasePriceType, OrderDiscountType, PLUS_MEMBER_TYPE, PlusMemberContext, PlusMemberMode, PlusMemberProvider, PriceBasePriceType, PriceDiscountType, RuleType, SCRIPT_CODE_AMOUNT_KEY, ShippingMethodMode, ShopifyContext, ShopifyProvider, SpendMoneyType, browserCartCookieAdapter, browserCookieAdapter, clearGeoLocationCache, createMockCartFromLines, currencyCodeMapping, defaultSWRMutationConfiguration, formatFunctionAutoFreeGift, formatScriptAutoFreeGift, gaTrack, getCachedGeoLocation, getCartAttributes, getDiscountEnvAttributeValue, getMatchedMainProductSubTotal, getQuery, getReferralAttributes, getUserType, hasPlusMemberInCart, hasPlusMemberInLines, normalizeAddToCartLines, preCheck, safeParse, trackAddToCartFBQ, trackAddToCartGA, trackBeginCheckoutGA, trackBuyNowFBQ, trackBuyNowGA, useAddCartLines, useAddToCart, useAllBlogs, useAllCollections, useAllProducts, useApplyCartCodes, useArticle, useArticles, useArticlesInBlog, useAutoRemovePlusMemberInCart, useAvailableDeliveryCoupon, useBlog, useBuyNow, useCalcAutoFreeGift, useCalcGiftsFromLines, useCalcOrderDiscount, useCartAttributes, useCartContext, useCartItemQuantityLimit, useCollection, useCollections, useCreateCart, useExposure, useGeoLocation, useHasPlusMemberInCart, useHasPlusMemberInLines, useIntersection, usePlusMemberCheckoutCustomAttributes, usePlusMemberContext, usePlusMemberNeedAddToCart, usePlusMemberVariants, usePrice, useProduct, useProductUrl, useProductsByHandles, useRemoveCartCodes, useRemoveCartLines, useReplaceCartPlusMember, useScriptAutoFreeGift, useSearch, useSelectedOptions, useShippingMethods, useShopify, useSite, useUpdateCartAttributes, useUpdateCartLines, useUpdateLineCodeAmountAttributes, useUpdateVariantQuery, useVariant, useVariantMedia };
3248
3448
  //# sourceMappingURL=index.mjs.map
3249
3449
  //# sourceMappingURL=index.mjs.map