@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.
@@ -5,6 +5,7 @@ var shopifySdk = require('@anker-in/shopify-sdk');
5
5
  var Cookies5 = require('js-cookie');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var Decimal2 = require('decimal.js');
8
+ var shopifyCore = require('@anker-in/shopify-core');
8
9
  var useSWR = require('swr');
9
10
  var useSWRMutation8 = require('swr/mutation');
10
11
  var ahooks = require('ahooks');
@@ -61,7 +62,8 @@ function ShopifyProvider({
61
62
  cartCookieAdapter = browserCartCookieAdapter,
62
63
  routerAdapter,
63
64
  userAdapter,
64
- children
65
+ children,
66
+ performanceAdapter
65
67
  }) {
66
68
  const client = react.useMemo(() => {
67
69
  return shopifySdk.createShopifyClient(config, locale);
@@ -75,7 +77,8 @@ function ShopifyProvider({
75
77
  cookieAdapter,
76
78
  cartCookieAdapter,
77
79
  routerAdapter,
78
- userAdapter
80
+ userAdapter,
81
+ performanceAdapter
79
82
  };
80
83
  }, [
81
84
  client,
@@ -85,6 +88,7 @@ function ShopifyProvider({
85
88
  cookieAdapter,
86
89
  cartCookieAdapter,
87
90
  routerAdapter,
91
+ performanceAdapter,
88
92
  userAdapter
89
93
  ]);
90
94
  return /* @__PURE__ */ jsxRuntime.jsx(ShopifyContext.Provider, { value, children });
@@ -110,9 +114,10 @@ function normalizeAddToCartLines(lines) {
110
114
  const variant = line.variant;
111
115
  const product = variant.product;
112
116
  const quantity = line.quantity || 1;
113
- const price = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : variant.price?.amount ? Number(variant.price.amount) : 0;
114
- const subtotalAmount = price * quantity;
115
- const totalAmount = subtotalAmount;
117
+ const originalPrice = variant.price?.amount ? Number(variant.price.amount) : 0;
118
+ const finalPrice = variant.finalPrice?.amount === void 0 ? originalPrice : Number(variant.finalPrice?.amount);
119
+ const subtotalAmount = originalPrice * quantity;
120
+ const totalAmount = finalPrice * quantity;
116
121
  return {
117
122
  id: `temp-line-${index}-${variant.id}`,
118
123
  // Temporary ID for pre-cart lines
@@ -126,7 +131,7 @@ function normalizeAddToCartLines(lines) {
126
131
  customAttributes: line.attributes || [],
127
132
  variant: {
128
133
  id: variant.id,
129
- price,
134
+ price: finalPrice,
130
135
  listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
131
136
  sku: variant.sku || "",
132
137
  name: variant.title || "",
@@ -157,15 +162,16 @@ function createMockCartFromLines(lines, existingCart) {
157
162
  const normalizedLines = normalizeAddToCartLines(lines);
158
163
  const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
159
164
  const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
165
+ const currency = lines[0]?.variant?.price?.currencyCode;
160
166
  return {
161
167
  id: existingCart?.id || "temp-cart-id",
162
168
  customerId: existingCart?.customerId,
163
169
  email: existingCart?.email,
164
170
  createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
165
- currency: existingCart?.currency || { code: "USD" },
171
+ currency: existingCart?.currency || { code: currency },
166
172
  taxesIncluded: existingCart?.taxesIncluded,
167
173
  lineItems: normalizedLines,
168
- totallineItemsDiscount: 0,
174
+ totalLineItemsDiscount: 0,
169
175
  orderDiscounts: 0,
170
176
  lineItemsSubtotalPrice: subtotalPrice,
171
177
  subtotalPrice,
@@ -196,22 +202,12 @@ var getQuery = () => {
196
202
  }
197
203
  return theRequest;
198
204
  };
199
- function atobID(id) {
200
- if (id && typeof id === "string" && id.includes("/")) {
201
- return id.split("/").pop()?.split("?")?.shift();
202
- } else {
203
- return id;
204
- }
205
- }
206
- function btoaID(id, type = "ProductVariant") {
207
- return `gid://shopify/${type}/${id}`;
208
- }
209
205
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
210
206
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
211
207
  const matchedList = cartData?.lineItems?.filter((line) => {
212
208
  const { is_gift } = getDiscountEnvAttributeValue(line.customAttributes);
213
209
  return isAllStoreVariant ? !is_gift : variant_list?.find((item) => {
214
- return !is_gift && atobID(line.variantId) === item;
210
+ return !is_gift && shopifyCore.atobID(line.variantId) === item;
215
211
  });
216
212
  });
217
213
  return matchedList?.reduce((acc, line) => {
@@ -229,14 +225,6 @@ var getDiscountEnvAttributeValue = (attributes = []) => {
229
225
  const attr = attributes.find((attr2) => attr2.key === CUSTOMER_ATTRIBUTE_KEY);
230
226
  return safeParse(attr?.value ?? "") ?? {};
231
227
  };
232
- var checkAttributesUpdateNeeded = (oldAttributes, newAttributes, customAttributesNeedRemove) => {
233
- return oldAttributes.some((attr) => {
234
- const newAttr = newAttributes.find((newAttr2) => newAttr2.key === attr.key);
235
- return newAttr ? newAttr.value !== attr.value : true;
236
- }) || newAttributes.some((attr) => !oldAttributes.some((oldAttr) => oldAttr.key === attr.key)) || customAttributesNeedRemove.some(
237
- (removeAttr) => oldAttributes.some((oldAttr) => oldAttr.key === removeAttr.key)
238
- );
239
- };
240
228
  var containsAll = (source, requiredItems = []) => {
241
229
  if (!requiredItems?.length) return true;
242
230
  const sourceSet = new Set(source);
@@ -434,43 +422,29 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
434
422
  }
435
423
  return { activeCampaign: null, subtotal: 0 };
436
424
  }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
437
- const { qualifyingGift, nextTierGoal } = react.useMemo(() => {
425
+ const { qualifyingTier, nextTierGoal, actualThreshold, currentCurrency } = react.useMemo(() => {
438
426
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
439
- return { qualifyingGift: null, nextTierGoal: null };
427
+ return { qualifyingTier: null, nextTierGoal: null, actualThreshold: 0, currentCurrency: "" };
440
428
  }
441
429
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
442
- const qualifyingTier = [...giftTiers].sort((a, b) => Number(b.spend_sum_money) - Number(a.spend_sum_money)).find((tier) => subtotal >= Number(tier.spend_sum_money));
443
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
444
- if (!qualifyingTier) {
445
- return { qualifyingGift: null, nextTierGoal: nextGoal || null };
446
- }
447
- const formattedGift = {
448
- tier: qualifyingTier,
449
- itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
450
- const giftProduct = reward?.variant_list?.[0];
451
- if (!giftProduct) return null;
452
- return {
453
- variant: {
454
- id: btoaID(giftProduct.variant_id),
455
- handle: giftProduct.handle,
456
- sku: giftProduct.sku
457
- },
458
- quantity: reward?.get_unit || 1,
459
- attributes: [
460
- {
461
- key: CUSTOMER_ATTRIBUTE_KEY,
462
- value: JSON.stringify({
463
- is_gift: true,
464
- rule_id: activeCampaign.rule_id,
465
- spend_sum_money: qualifyingTier.spend_sum_money
466
- })
467
- }
468
- ]
469
- };
470
- }).filter((item) => item !== null)
430
+ const currentCurrency2 = effectiveCart?.currency?.code || "";
431
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency2);
432
+ const getThresholdAmount = (tier) => {
433
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency2]?.value) {
434
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency2].value);
435
+ }
436
+ return Number(tier.spend_sum_money || 0);
471
437
  };
472
- return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
473
- }, [activeCampaign, subtotal]);
438
+ const qualifyingTier2 = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
439
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
440
+ const actualThreshold2 = qualifyingTier2 ? getThresholdAmount(qualifyingTier2) : 0;
441
+ return {
442
+ qualifyingTier: qualifyingTier2,
443
+ nextTierGoal: nextGoal || null,
444
+ actualThreshold: actualThreshold2,
445
+ currentCurrency: currentCurrency2
446
+ };
447
+ }, [activeCampaign, subtotal, effectiveCart]);
474
448
  const giftHandles = react.useMemo(() => {
475
449
  const giftVariant = autoFreeGiftConfig.map(
476
450
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -486,24 +460,82 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
486
460
  }
487
461
  return true;
488
462
  }, [giftHandles]);
489
- const { data: giftProductsResult } = useSWR__default.default(shouldFetch ? giftHandles : null, async () => {
490
- const res = await shopifySdk.getProductsByHandles(client, {
491
- handles: giftHandles,
492
- locale
493
- });
494
- const result = Array.isArray(res) ? res : [];
495
- giftProductsCache.current = {
496
- data: result,
497
- giftHandles: [...giftHandles]
498
- };
499
- return result;
500
- });
463
+ const { data: giftProductsResult } = useSWR__default.default(
464
+ shouldFetch ? giftHandles : null,
465
+ async () => {
466
+ const res = await shopifySdk.getProductsByHandles(client, {
467
+ handles: giftHandles,
468
+ locale
469
+ });
470
+ const result = Array.isArray(res) ? res : [];
471
+ giftProductsCache.current = {
472
+ data: result,
473
+ giftHandles: [...giftHandles]
474
+ };
475
+ return result;
476
+ },
477
+ {
478
+ revalidateOnFocus: false
479
+ }
480
+ );
501
481
  const finalGiftProductsResult = react.useMemo(() => {
502
482
  if (giftProductsCache.current && !shouldFetch) {
503
483
  return giftProductsCache.current.data || void 0;
504
484
  }
505
485
  return giftProductsResult;
506
486
  }, [giftProductsResult, shouldFetch]);
487
+ const qualifyingGift = react.useMemo(() => {
488
+ if (!qualifyingTier || !activeCampaign) {
489
+ return null;
490
+ }
491
+ const itemsToAdd = qualifyingTier.reward_list?.map((reward) => {
492
+ if (!reward.variant_list || reward.variant_list.length === 0) {
493
+ return null;
494
+ }
495
+ let selectedGiftProduct = null;
496
+ for (const giftVariant of reward.variant_list) {
497
+ const productInfo = finalGiftProductsResult?.find(
498
+ (p) => p.handle === giftVariant.handle
499
+ );
500
+ if (productInfo) {
501
+ const variantInfo = productInfo.variants?.find((v) => v.sku === giftVariant.sku);
502
+ if (variantInfo?.availableForSale) {
503
+ selectedGiftProduct = giftVariant;
504
+ break;
505
+ }
506
+ }
507
+ }
508
+ if (!selectedGiftProduct) {
509
+ selectedGiftProduct = reward.variant_list[0];
510
+ }
511
+ return {
512
+ variant: {
513
+ id: shopifyCore.btoaID(selectedGiftProduct.variant_id),
514
+ handle: selectedGiftProduct.handle,
515
+ sku: selectedGiftProduct.sku
516
+ },
517
+ quantity: reward?.get_unit || 1,
518
+ attributes: [
519
+ {
520
+ key: CUSTOMER_ATTRIBUTE_KEY,
521
+ value: JSON.stringify({
522
+ is_gift: true,
523
+ rule_id: activeCampaign.rule_id,
524
+ spend_sum_money: actualThreshold,
525
+ // 使用实际的门槛金额(多币种支持)
526
+ currency_code: currentCurrency
527
+ // 记录当前币种
528
+ })
529
+ }
530
+ ]
531
+ };
532
+ }).filter((item) => item !== null);
533
+ const formattedGift = {
534
+ tier: qualifyingTier,
535
+ itemsToAdd
536
+ };
537
+ return formattedGift;
538
+ }, [qualifyingTier, activeCampaign, finalGiftProductsResult, actualThreshold, currentCurrency]);
507
539
  return {
508
540
  qualifyingGift,
509
541
  nextTierGoal,
@@ -517,7 +549,8 @@ var useScriptAutoFreeGift = ({
517
549
  _giveaway,
518
550
  cart,
519
551
  locale: providedLocale,
520
- lines
552
+ lines,
553
+ profile
521
554
  }) => {
522
555
  const { client, locale: contextLocale } = useShopify();
523
556
  const locale = providedLocale || contextLocale;
@@ -541,8 +574,9 @@ var useScriptAutoFreeGift = ({
541
574
  const utmCampaign = Cookies5__default.default.get("utm_campaign") || query?.utm_campaign;
542
575
  if (campaign.activityAvailableQuery && !utmCampaign?.includes(campaign.activityAvailableQuery))
543
576
  return false;
577
+ if (campaign.requireLogin && !profile?.email) return false;
544
578
  return true;
545
- }, [campaign]);
579
+ }, [campaign, profile]);
546
580
  const [upgrade_multiple, upgrade_value] = react.useMemo(() => {
547
581
  let upgrade_multiple2 = 1;
548
582
  let upgrade_value2 = 0;
@@ -550,12 +584,14 @@ var useScriptAutoFreeGift = ({
550
584
  upgrade_multiple2 = 1.2;
551
585
  upgrade_value2 = 40;
552
586
  }
553
- effectiveCart?.lineItems?.forEach(({ customAttributes }) => {
554
- customAttributes?.forEach(({ key, value }) => {
555
- if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
556
- if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
557
- });
558
- });
587
+ effectiveCart?.lineItems?.forEach(
588
+ ({ customAttributes }) => {
589
+ customAttributes?.forEach(({ key, value }) => {
590
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
591
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
592
+ });
593
+ }
594
+ );
559
595
  return [upgrade_multiple2, upgrade_value2];
560
596
  }, [effectiveCart?.lineItems, points_subscribe]);
561
597
  const breakpoints = react.useMemo(() => {
@@ -620,18 +656,24 @@ var useScriptAutoFreeGift = ({
620
656
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
621
657
  return [currentLevel, nextLevel];
622
658
  }, [breakpoints, involvedSubTotal, involvedLines.length]);
623
- const { data: giftProductsResult } = useSWR__default.default(shouldFetch ? giftHandles : null, async () => {
624
- const res = await shopifySdk.getProductsByHandles(client, {
625
- handles: giftHandles,
626
- locale
627
- });
628
- const result = Array.isArray(res) ? res : [];
629
- giftProductsCache.current = {
630
- data: result,
631
- giftHandles: [...giftHandles]
632
- };
633
- return result;
634
- });
659
+ const { data: giftProductsResult } = useSWR__default.default(
660
+ shouldFetch ? giftHandles : null,
661
+ async () => {
662
+ const res = await shopifySdk.getProductsByHandles(client, {
663
+ handles: giftHandles,
664
+ locale
665
+ });
666
+ const result = Array.isArray(res) ? res : [];
667
+ giftProductsCache.current = {
668
+ data: result,
669
+ giftHandles: [...giftHandles]
670
+ };
671
+ return result;
672
+ },
673
+ {
674
+ revalidateOnFocus: false
675
+ }
676
+ );
635
677
  const finalGiftProductsResult = react.useMemo(() => {
636
678
  if (giftProductsCache.current && !shouldFetch) {
637
679
  return giftProductsCache.current.data || void 0;
@@ -663,62 +705,20 @@ var useScriptAutoFreeGift = ({
663
705
  giftProductsResult: finalGiftProductsResult
664
706
  };
665
707
  };
666
- function useUpdateCartAttributes(mutate, metafieldIdentifiers, options) {
667
- const { client, locale, cartCookieAdapter } = useShopify();
668
- const updateAttributes = react.useCallback(
669
- async (_key, { arg }) => {
670
- const updatedCart = await shopifySdk.updateCartAttributes(client, {
671
- ...arg,
672
- metafieldIdentifiers,
673
- cookieAdapter: cartCookieAdapter
674
- });
675
- console.log("useUpdateCartAttributes updatedCart", updatedCart);
676
- if (updatedCart) {
677
- mutate(updatedCart);
678
- }
679
- return updatedCart;
680
- },
681
- [client, locale, cartCookieAdapter, mutate]
682
- );
683
- return useSWRMutation8__default.default("update-cart-attributes", updateAttributes, options);
684
- }
685
- function useHasPlusMemberInCart({
686
- memberSetting,
687
- cart
688
- }) {
689
- const { plus_monthly_product, plus_annual_product } = memberSetting || {};
690
- return react.useMemo(() => {
691
- if (!cart?.lineItems) {
692
- return {
693
- hasPlusMember: false,
694
- hasMonthlyPlus: false,
695
- hasAnnualPlus: false
696
- };
697
- }
698
- const monthlyPlusItem = cart.lineItems.find(
699
- (item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
700
- );
701
- const annualPlusItem = cart.lineItems.find(
702
- (item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
703
- );
704
- const hasMonthlyPlus = !!monthlyPlusItem;
705
- const hasAnnualPlus = !!annualPlusItem;
706
- const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
707
- return {
708
- hasPlusMember,
709
- hasMonthlyPlus,
710
- hasAnnualPlus,
711
- monthlyPlusItem,
712
- annualPlusItem
713
- };
714
- }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
715
- }
716
708
 
717
- // src/hooks/cart/feature/use-cart-attributes.ts
709
+ // src/hooks/cart/utils/cart-attributes.ts
710
+ var checkAttributesUpdateNeeded = (oldAttributes, newAttributes, customAttributesNeedRemove) => {
711
+ return newAttributes.some((attr) => !oldAttributes.some((oldAttr) => oldAttr.key === attr.key)) || oldAttributes.some((attr) => {
712
+ const newAttr = newAttributes.find((newAttr2) => newAttr2.key === attr.key);
713
+ return newAttr ? newAttr.value !== attr.value : true;
714
+ }) || customAttributesNeedRemove.some(
715
+ (removeAttr) => oldAttributes.some((oldAttr) => oldAttr.key === removeAttr.key)
716
+ );
717
+ };
718
718
  var getReferralAttributes = () => {
719
- const inviteCode = Cookies5__default.default.get("invite_code");
720
- const playModeId = Cookies5__default.default.get("playModeId");
721
- const popup = Cookies5__default.default.get("_popup");
719
+ const inviteCode = shopifySdk.getLocalStorage("inviteCode") || Cookies5__default.default.get("inviteCode");
720
+ const playModeId = shopifySdk.getLocalStorage("playModeId") || Cookies5__default.default.get("playModeId");
721
+ const popup = shopifySdk.getLocalStorage("_popup") || Cookies5__default.default.get("_popup");
722
722
  if (inviteCode && playModeId) {
723
723
  return popup ? [
724
724
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -731,117 +731,130 @@ var getReferralAttributes = () => {
731
731
  }
732
732
  return [];
733
733
  };
734
+ var getUserType = (customer) => {
735
+ let userInfo = Cookies5__default.default.get("userInfo");
736
+ if (userInfo) {
737
+ userInfo = JSON.parse(userInfo);
738
+ let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
739
+ userInfo.setId = arr[arr.length - 1];
740
+ }
741
+ const customerInfo = userInfo || customer;
742
+ if (!customerInfo) {
743
+ return "new_user_unlogin";
744
+ }
745
+ if (customer) {
746
+ const { orders = {} } = customer;
747
+ if (orders?.edges?.length === 1) {
748
+ return "old_user_orders_once";
749
+ } else if (orders?.edges?.length > 1) {
750
+ return "old_user_orders_twice";
751
+ }
752
+ }
753
+ return "new_user_login";
754
+ };
755
+ function getCartAttributes({
756
+ profile,
757
+ customer,
758
+ cart,
759
+ memberType,
760
+ currentUrl = ""
761
+ }) {
762
+ const userType = getUserType(customer);
763
+ const memberAttributes = [
764
+ {
765
+ key: "_token",
766
+ value: profile?.token
767
+ },
768
+ {
769
+ key: "_member_type",
770
+ value: memberType ?? String(profile?.memberType)
771
+ },
772
+ {
773
+ key: "_user_type",
774
+ value: userType
775
+ },
776
+ {
777
+ key: "_is_login",
778
+ value: profile?.token ? "true" : "false"
779
+ }
780
+ ];
781
+ if (profile?.token) {
782
+ memberAttributes.push({
783
+ key: "_login_user",
784
+ value: "1"
785
+ });
786
+ }
787
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
788
+ const functionAttributes = [
789
+ {
790
+ key: CUSTOMER_ATTRIBUTE_KEY,
791
+ value: JSON.stringify({
792
+ discount_code: discountCodes,
793
+ user_tags: customer?.tags || []
794
+ })
795
+ }
796
+ ];
797
+ const presellAttributes = [
798
+ {
799
+ key: "_presale",
800
+ value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
801
+ }
802
+ ];
803
+ const weightAttributes = [
804
+ {
805
+ key: "_weight",
806
+ value: cart?.lineItems.reduce((acc, item) => {
807
+ return new Decimal2__default.default(acc).plus(item.variant.weight ?? 0).toNumber();
808
+ }, 0).toString()
809
+ },
810
+ {
811
+ key: "_app_source_name",
812
+ value: "dtc"
813
+ }
814
+ ];
815
+ const trackingAttributes = [
816
+ {
817
+ key: "utm_params",
818
+ value: currentUrl
819
+ }
820
+ ];
821
+ const commonAttributes = [
822
+ ...memberAttributes,
823
+ ...functionAttributes,
824
+ ...presellAttributes,
825
+ ...weightAttributes,
826
+ ...trackingAttributes,
827
+ ...getReferralAttributes()
828
+ ].filter((item) => item?.value);
829
+ const extraAttributesInCart = cart?.customAttributes?.filter(
830
+ (item) => !commonAttributes.some((attr) => attr.key === item.key)
831
+ ) || [];
832
+ return [...commonAttributes, ...extraAttributesInCart].filter((item) => item?.value);
833
+ }
734
834
  var useCartAttributes = ({
735
835
  profile,
736
836
  customer,
737
837
  cart,
738
- memberSetting
838
+ memberType
739
839
  }) => {
740
840
  const [currentUrl, setCurrentUrl] = react.useState("");
741
- const { hasPlusMember } = useHasPlusMemberInCart({
742
- memberSetting,
743
- cart
744
- });
745
841
  react.useEffect(() => {
746
842
  setCurrentUrl(window.location.href);
747
843
  }, []);
748
- const userType = react.useMemo(() => {
749
- let userInfo = Cookies5__default.default.get("userInfo");
750
- if (userInfo) {
751
- userInfo = JSON.parse(userInfo);
752
- let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
753
- userInfo.setId = arr[arr.length - 1];
754
- }
755
- const customerInfo = userInfo || customer;
756
- if (!customerInfo) {
757
- return "new_user_unlogin";
758
- }
759
- if (customer) {
760
- const { orders = {} } = customer;
761
- if (orders?.edges?.length === 1) {
762
- return "old_user_orders_once";
763
- } else if (orders?.edges?.length > 1) {
764
- return "old_user_orders_twice";
765
- }
766
- }
767
- return "new_user_login";
768
- }, [customer]);
769
- const memberAttributes = react.useMemo(() => {
770
- return [
771
- {
772
- key: "_token",
773
- value: profile?.token
774
- //是否登录
775
- },
776
- {
777
- key: "_member_type",
778
- value: hasPlusMember ? "2" : profile?.memberType
779
- //:0(游客),1(普通会员),2(付费会员)
780
- },
781
- {
782
- key: "_user_type",
783
- value: userType
784
- // n
785
- },
786
- {
787
- key: "_is_login",
788
- value: profile?.token ? "true" : "false"
789
- }
790
- ];
791
- }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
792
- const functionAttributes = react.useMemo(() => {
793
- return [
794
- cart?.discountCodes && {
795
- key: "_discounts_function_env",
796
- value: JSON.stringify({
797
- discount_code: cart?.discountCodes.map((item) => item.code),
798
- user_tags: customer?.tags || []
799
- })
800
- }
801
- ];
802
- }, [cart]);
803
- const presellAttributes = react.useMemo(() => {
804
- return [
805
- {
806
- key: "_presale",
807
- value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
808
- }
809
- ];
810
- }, [cart]);
811
- const weightAttributes = react.useMemo(() => {
812
- return [
813
- {
814
- key: "_weight",
815
- value: cart?.lineItems.reduce((acc, item) => {
816
- return new Decimal2__default.default(acc).plus(item.variant.weight ?? 0).toNumber();
817
- }, 0).toString()
818
- },
819
- {
820
- key: "_app_source_name",
821
- value: "dtc"
822
- }
823
- ];
824
- }, [cart]);
825
- const trackingAttributes = react.useMemo(() => {
826
- return [
827
- {
828
- key: "utm_params",
829
- value: currentUrl
830
- }
831
- ];
832
- }, [currentUrl]);
844
+ const attributes = react.useMemo(() => {
845
+ return getCartAttributes({
846
+ profile,
847
+ customer,
848
+ cart,
849
+ memberType,
850
+ currentUrl
851
+ });
852
+ }, [profile, customer, cart, memberType, currentUrl]);
833
853
  return react.useMemo(
834
854
  () => ({
835
- attributes: [
836
- ...memberAttributes,
837
- ...functionAttributes,
838
- ...presellAttributes,
839
- ...weightAttributes,
840
- ...trackingAttributes,
841
- ...getReferralAttributes()
842
- ].filter((item) => item?.value)
855
+ attributes
843
856
  }),
844
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
857
+ [attributes]
845
858
  );
846
859
  };
847
860
  var useUpdateLineCodeAmountAttributes = ({
@@ -870,7 +883,7 @@ var useUpdateLineCodeAmountAttributes = ({
870
883
  );
871
884
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
872
885
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
873
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
886
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
874
887
  attrNeedUpdate.push({
875
888
  key: CUSTOMER_ATTRIBUTE_KEY,
876
889
  value: JSON.stringify({
@@ -909,29 +922,22 @@ var useUpdateLineCodeAmountAttributes = ({
909
922
  }).filter(
910
923
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
911
924
  ).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
925
+ let lineId = line.id;
926
+ let attributes = line.customAttributes || [];
927
+ if (attrNeedDelete.length) {
928
+ attributes = attributes.filter(
929
+ (attr) => !attrNeedDelete.includes(attr.key)
930
+ );
931
+ }
912
932
  if (attrNeedUpdate.length) {
913
- return {
914
- id: line.id,
915
- attributes: [
916
- ...line.customAttributes?.filter(
917
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
918
- ) || [],
919
- ...attrNeedUpdate
920
- ]
921
- };
922
- } else if (attrNeedDelete.length) {
923
- return {
924
- id: line.id,
925
- attributes: line.customAttributes?.filter(
926
- (attr) => !attrNeedDelete.includes(attr.key)
927
- ) || []
928
- };
929
- } else {
930
- return {
931
- id: line.id,
932
- attributes: line.customAttributes || []
933
- };
933
+ attributes = attributes.filter(
934
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
935
+ ).concat(attrNeedUpdate);
934
936
  }
937
+ return {
938
+ id: lineId,
939
+ attributes
940
+ };
935
941
  }),
936
942
  [cart?.lineItems, mainProductDiscountCodes]
937
943
  );
@@ -966,28 +972,13 @@ var useUpdateLineCodeAmountAttributes = ({
966
972
  }, [loading, setLoadingState]);
967
973
  };
968
974
  var createInitialValue = () => ({
969
- zipCode: "",
970
975
  plusMemberMetafields: {},
971
- setZipCode: () => {
972
- },
973
- allowNextDayDelivery: false,
974
- setAllowNextDayDelivery: () => {
975
- },
976
- allowThirdDayDelivery: false,
977
- setAllowThirdDayDelivery: () => {
978
- },
979
976
  selectedPlusMemberMode: "free",
980
977
  setSelectedPlusMemberMode: () => {
981
978
  },
982
- showAreaCheckModal: false,
983
- setShowAreaCheckModal: () => {
984
- },
985
979
  selectedShippingMethod: void 0,
986
980
  setSelectedShippingMethod: () => {
987
981
  },
988
- showTip: false,
989
- setShowTip: () => {
990
- },
991
982
  showMoreShippingMethod: false,
992
983
  setShowMoreShippingMethod: () => {
993
984
  },
@@ -997,20 +988,85 @@ var createInitialValue = () => ({
997
988
  freeShippingMethods: [],
998
989
  paymentShippingMethods: [],
999
990
  nddOverweight: false,
1000
- tddOverweight: false
991
+ tddOverweight: false,
992
+ nddCoupon: void 0,
993
+ tddCoupon: void 0,
994
+ isLoadingCoupon: false
1001
995
  },
1002
- selectedPlusMemberProduct: null,
1003
- plusMemberProducts: [],
996
+ selectedPlusMemberVariant: void 0,
1004
997
  showPlusMemberBenefit: false,
1005
998
  setShowPlusMemberBenefit: () => {
1006
999
  },
1007
- deleteMarginBottom: false,
1008
- setDeleteMarginBottom: () => {
1009
- },
1010
- profile: void 0,
1011
- locale: void 0
1000
+ profile: void 0
1012
1001
  });
1013
1002
  react.createContext(createInitialValue());
1003
+ function hasPlusMemberInCart({
1004
+ memberSetting,
1005
+ cart
1006
+ }) {
1007
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
1008
+ if (!cart?.lineItems) {
1009
+ return {
1010
+ hasPlusMember: false,
1011
+ hasMonthlyPlus: false,
1012
+ hasAnnualPlus: false
1013
+ };
1014
+ }
1015
+ const monthlyPlusItem = cart.lineItems.find(
1016
+ (item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
1017
+ );
1018
+ const annualPlusItem = cart.lineItems.find(
1019
+ (item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
1020
+ );
1021
+ const hasMonthlyPlus = !!monthlyPlusItem;
1022
+ const hasAnnualPlus = !!annualPlusItem;
1023
+ const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
1024
+ return {
1025
+ hasPlusMember,
1026
+ hasMonthlyPlus,
1027
+ hasAnnualPlus,
1028
+ monthlyPlusItem,
1029
+ annualPlusItem
1030
+ };
1031
+ }
1032
+ function useHasPlusMemberInCart({
1033
+ memberSetting,
1034
+ cart
1035
+ }) {
1036
+ return react.useMemo(
1037
+ () => hasPlusMemberInCart({
1038
+ memberSetting,
1039
+ cart
1040
+ }),
1041
+ [memberSetting, cart]
1042
+ );
1043
+ }
1044
+ function useUpdateCartAttributes({
1045
+ mutate,
1046
+ metafieldIdentifiers,
1047
+ disabled = false,
1048
+ swrOptions
1049
+ }) {
1050
+ const { client, locale, cartCookieAdapter } = useShopify();
1051
+ const updateAttributes = react.useCallback(
1052
+ async (_key, { arg }) => {
1053
+ if (disabled) {
1054
+ return void 0;
1055
+ }
1056
+ const updatedCart = await shopifySdk.updateCartAttributes(client, {
1057
+ ...arg,
1058
+ metafieldIdentifiers,
1059
+ cookieAdapter: cartCookieAdapter
1060
+ });
1061
+ if (updatedCart) {
1062
+ mutate(updatedCart);
1063
+ }
1064
+ return updatedCart;
1065
+ },
1066
+ [client, locale, cartCookieAdapter, mutate, metafieldIdentifiers, disabled]
1067
+ );
1068
+ return useSWRMutation8__default.default("update-cart-attributes", updateAttributes, swrOptions);
1069
+ }
1014
1070
  var CartContext = react.createContext(null);
1015
1071
  function CartProvider({
1016
1072
  children,
@@ -1025,7 +1081,7 @@ function CartProvider({
1025
1081
  }) {
1026
1082
  const { client, cartCookieAdapter } = useShopify();
1027
1083
  const [customAttributes, setCustomAttributes] = react.useState([]);
1028
- const [customAttributesNeedDelete, setCustomAttributesNeedDelete] = react.useState(
1084
+ const [customAttributesNeedRemove, setCustomAttributesNeedRemove] = react.useState(
1029
1085
  []
1030
1086
  );
1031
1087
  const [isCodeChanging, setIsCodeChanging] = react.useState(false);
@@ -1053,15 +1109,34 @@ function CartProvider({
1053
1109
  refreshDeps: [locale]
1054
1110
  }
1055
1111
  );
1056
- const { trigger: updateAttributes } = useUpdateCartAttributes(mutateCart, metafieldIdentifiers);
1057
- const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
1112
+ const { trigger: updateAttributes } = useUpdateCartAttributes({
1113
+ mutate: mutateCart,
1114
+ metafieldIdentifiers,
1115
+ disabled: isCartLoading
1116
+ });
1117
+ const { hasPlusMember } = useHasPlusMemberInCart({
1118
+ memberSetting,
1119
+ cart
1120
+ });
1121
+ const { attributes: commonAttributes } = useCartAttributes({
1122
+ profile,
1123
+ customer,
1124
+ cart,
1125
+ memberType: hasPlusMember ? "2" : profile?.memberType
1126
+ });
1058
1127
  ahooks.useRequest(
1059
1128
  () => {
1060
- const newAttributes = [...attributes, ...customAttributes];
1061
- const needUpdate = cart && !checkAttributesUpdateNeeded(
1129
+ const filteredSameCommonAttributes = commonAttributes.filter(
1130
+ (attr) => !customAttributes.some((a) => a.key === attr.key)
1131
+ );
1132
+ const newAttributes = [
1133
+ ...filteredSameCommonAttributes,
1134
+ ...customAttributes
1135
+ ];
1136
+ const needUpdate = cart && checkAttributesUpdateNeeded(
1062
1137
  cart.customAttributes,
1063
1138
  newAttributes,
1064
- customAttributesNeedDelete
1139
+ customAttributesNeedRemove
1065
1140
  );
1066
1141
  if (needUpdate) {
1067
1142
  return updateAttributes({ attributes: newAttributes });
@@ -1074,44 +1149,39 @@ function CartProvider({
1074
1149
  // 1 秒内只触发最后一次更新
1075
1150
  throttleTrailing: true,
1076
1151
  throttleLeading: false,
1077
- refreshDeps: [attributes, customAttributes]
1152
+ refreshDeps: [commonAttributes, customAttributes, customAttributesNeedRemove]
1078
1153
  }
1079
1154
  );
1080
1155
  useUpdateLineCodeAmountAttributes({
1081
1156
  cart,
1082
1157
  mutateCart,
1083
1158
  isCartLoading: isCartLoading || isCodeChanging,
1084
- setLoadingState
1159
+ setLoadingState,
1160
+ metafieldIdentifiers
1085
1161
  });
1086
1162
  const removeCustomAttributes = react.useCallback(
1087
- (attributes2) => {
1088
- setCustomAttributesNeedDelete(attributes2);
1163
+ (attributes) => {
1164
+ setCustomAttributesNeedRemove(attributes);
1089
1165
  },
1090
- [setCustomAttributesNeedDelete]
1166
+ [setCustomAttributesNeedRemove]
1091
1167
  );
1092
1168
  const addCustomAttributes = react.useCallback(
1093
- (attributes2) => {
1094
- const sameAttributes = attributes2.filter(
1095
- (attr) => customAttributes.some((a) => a.key === attr.key)
1096
- );
1097
- if (sameAttributes.length) {
1098
- setCustomAttributes((prev) => {
1099
- const removedAttributes = prev.filter(
1100
- (attr) => !sameAttributes.some((a) => a.key === attr.key)
1101
- );
1102
- return [...removedAttributes, ...attributes2];
1103
- });
1104
- } else {
1105
- setCustomAttributes((prev) => [...prev, ...attributes2]);
1106
- }
1169
+ (attributes) => {
1170
+ setCustomAttributes((oldCustomAttributes) => {
1171
+ const filteredSameAttributes = oldCustomAttributes.filter(
1172
+ (attr) => !attributes.some((a) => a.key === attr.key)
1173
+ );
1174
+ return [...filteredSameAttributes, ...attributes];
1175
+ });
1107
1176
  },
1108
- [customAttributes]
1177
+ [setCustomAttributes]
1109
1178
  );
1110
1179
  const functionAutoFreeGiftResult = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer);
1111
1180
  const scriptAutoFreeGiftResult = useScriptAutoFreeGift({
1112
1181
  campaign: gradientGiftsConfig || null,
1113
1182
  _giveaway: CUSTOMER_SCRIPT_GIFT_KEY,
1114
- cart
1183
+ cart,
1184
+ profile
1115
1185
  });
1116
1186
  const formattedScriptGifts = react.useMemo(() => {
1117
1187
  return formatScriptAutoFreeGift({
@@ -1162,16 +1232,23 @@ function CartProvider({
1162
1232
  );
1163
1233
  return result;
1164
1234
  }, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
1235
+ const totalQuantity = react.useMemo(() => {
1236
+ const cartLinesCount = cart?.lineItems.reduce((acc, item) => acc + item.quantity, 0) || 0;
1237
+ const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
1238
+ return cartLinesCount + giftLinesCount;
1239
+ }, [cart?.lineItems, giftNeedAddToCartLines]);
1165
1240
  const value = react.useMemo(
1166
1241
  () => ({
1242
+ totalQuantity,
1167
1243
  cart,
1168
1244
  isCartLoading,
1169
1245
  triggerFetch: fetchCart,
1170
1246
  mutateCart,
1171
1247
  addCustomAttributes,
1172
1248
  removeCustomAttributes,
1173
- setCustomAttributes,
1174
1249
  locale,
1250
+ profile,
1251
+ customer,
1175
1252
  isCodeChanging,
1176
1253
  setIsCodeChanging,
1177
1254
  autoFreeGiftConfig,
@@ -1187,10 +1264,12 @@ function CartProvider({
1187
1264
  scriptAutoFreeGiftResult,
1188
1265
  setScriptAutoFreeGift,
1189
1266
  giftNeedAddToCartLines,
1190
- metafieldIdentifiers
1267
+ metafieldIdentifiers,
1268
+ memberSetting
1191
1269
  }),
1192
1270
  [
1193
1271
  cart,
1272
+ totalQuantity,
1194
1273
  isCartLoading,
1195
1274
  fetchCart,
1196
1275
  mutateCart,
@@ -1210,14 +1289,17 @@ function CartProvider({
1210
1289
  scriptAutoFreeGiftResult,
1211
1290
  setScriptAutoFreeGift,
1212
1291
  giftNeedAddToCartLines,
1213
- metafieldIdentifiers
1292
+ metafieldIdentifiers,
1293
+ customer,
1294
+ profile,
1295
+ memberSetting
1214
1296
  ]
1215
1297
  );
1216
1298
  return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
1217
1299
  }
1218
- function useCartContext() {
1300
+ function useCartContext(options) {
1219
1301
  const context = react.useContext(CartContext);
1220
- if (!context) {
1302
+ if (!context && !options?.optional) {
1221
1303
  throw new Error("useCartContext must be used within a CartProvider");
1222
1304
  }
1223
1305
  return context;