@anker-in/shopify-react 0.1.1-beta.9 → 0.1.1

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,12 +162,13 @@ 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
174
  totalLineItemsDiscount: 0,
@@ -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,121 +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 ?? 0)
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
- const hasFunctionEnvAttribute = cart?.lineItems.some(
794
- (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
795
- );
796
- const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
797
- return hasFunctionEnvAttribute ? [
798
- {
799
- key: "_discounts_function_env",
800
- value: JSON.stringify({
801
- discount_code: discountCodes,
802
- user_tags: customer?.tags || []
803
- })
804
- }
805
- ] : [];
806
- }, [cart]);
807
- const presellAttributes = react.useMemo(() => {
808
- return [
809
- {
810
- key: "_presale",
811
- value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
812
- }
813
- ];
814
- }, [cart]);
815
- const weightAttributes = react.useMemo(() => {
816
- return [
817
- {
818
- key: "_weight",
819
- value: cart?.lineItems.reduce((acc, item) => {
820
- return new Decimal2__default.default(acc).plus(item.variant.weight ?? 0).toNumber();
821
- }, 0).toString()
822
- },
823
- {
824
- key: "_app_source_name",
825
- value: "dtc"
826
- }
827
- ];
828
- }, [cart]);
829
- const trackingAttributes = react.useMemo(() => {
830
- return [
831
- {
832
- key: "utm_params",
833
- value: currentUrl
834
- }
835
- ];
836
- }, [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]);
837
853
  return react.useMemo(
838
854
  () => ({
839
- attributes: [
840
- ...memberAttributes,
841
- ...functionAttributes,
842
- ...presellAttributes,
843
- ...weightAttributes,
844
- ...trackingAttributes,
845
- ...getReferralAttributes()
846
- ].filter((item) => item?.value)
855
+ attributes
847
856
  }),
848
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
857
+ [attributes]
849
858
  );
850
859
  };
851
860
  var useUpdateLineCodeAmountAttributes = ({
@@ -874,7 +883,7 @@ var useUpdateLineCodeAmountAttributes = ({
874
883
  );
875
884
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
876
885
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
877
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
886
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
878
887
  attrNeedUpdate.push({
879
888
  key: CUSTOMER_ATTRIBUTE_KEY,
880
889
  value: JSON.stringify({
@@ -913,29 +922,22 @@ var useUpdateLineCodeAmountAttributes = ({
913
922
  }).filter(
914
923
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
915
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
+ }
916
932
  if (attrNeedUpdate.length) {
917
- return {
918
- id: line.id,
919
- attributes: [
920
- ...line.customAttributes?.filter(
921
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
922
- ) || [],
923
- ...attrNeedUpdate
924
- ]
925
- };
926
- } else if (attrNeedDelete.length) {
927
- return {
928
- id: line.id,
929
- attributes: line.customAttributes?.filter(
930
- (attr) => !attrNeedDelete.includes(attr.key)
931
- ) || []
932
- };
933
- } else {
934
- return {
935
- id: line.id,
936
- attributes: line.customAttributes || []
937
- };
933
+ attributes = attributes.filter(
934
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
935
+ ).concat(attrNeedUpdate);
938
936
  }
937
+ return {
938
+ id: lineId,
939
+ attributes
940
+ };
939
941
  }),
940
942
  [cart?.lineItems, mainProductDiscountCodes]
941
943
  );
@@ -970,28 +972,13 @@ var useUpdateLineCodeAmountAttributes = ({
970
972
  }, [loading, setLoadingState]);
971
973
  };
972
974
  var createInitialValue = () => ({
973
- zipCode: "",
974
975
  plusMemberMetafields: {},
975
- setZipCode: () => {
976
- },
977
- allowNextDayDelivery: false,
978
- setAllowNextDayDelivery: () => {
979
- },
980
- allowThirdDayDelivery: false,
981
- setAllowThirdDayDelivery: () => {
982
- },
983
976
  selectedPlusMemberMode: "free",
984
977
  setSelectedPlusMemberMode: () => {
985
978
  },
986
- showAreaCheckModal: false,
987
- setShowAreaCheckModal: () => {
988
- },
989
979
  selectedShippingMethod: void 0,
990
980
  setSelectedShippingMethod: () => {
991
981
  },
992
- showTip: false,
993
- setShowTip: () => {
994
- },
995
982
  showMoreShippingMethod: false,
996
983
  setShowMoreShippingMethod: () => {
997
984
  },
@@ -1001,20 +988,85 @@ var createInitialValue = () => ({
1001
988
  freeShippingMethods: [],
1002
989
  paymentShippingMethods: [],
1003
990
  nddOverweight: false,
1004
- tddOverweight: false
991
+ tddOverweight: false,
992
+ nddCoupon: void 0,
993
+ tddCoupon: void 0,
994
+ isLoadingCoupon: false
1005
995
  },
1006
- selectedPlusMemberProduct: null,
1007
- plusMemberProducts: [],
996
+ selectedPlusMemberVariant: void 0,
1008
997
  showPlusMemberBenefit: false,
1009
998
  setShowPlusMemberBenefit: () => {
1010
999
  },
1011
- deleteMarginBottom: false,
1012
- setDeleteMarginBottom: () => {
1013
- },
1014
- profile: void 0,
1015
- locale: void 0
1000
+ profile: void 0
1016
1001
  });
1017
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
+ }
1018
1070
  var CartContext = react.createContext(null);
1019
1071
  function CartProvider({
1020
1072
  children,
@@ -1029,7 +1081,7 @@ function CartProvider({
1029
1081
  }) {
1030
1082
  const { client, cartCookieAdapter } = useShopify();
1031
1083
  const [customAttributes, setCustomAttributes] = react.useState([]);
1032
- const [customAttributesNeedDelete, setCustomAttributesNeedDelete] = react.useState(
1084
+ const [customAttributesNeedRemove, setCustomAttributesNeedRemove] = react.useState(
1033
1085
  []
1034
1086
  );
1035
1087
  const [isCodeChanging, setIsCodeChanging] = react.useState(false);
@@ -1057,15 +1109,34 @@ function CartProvider({
1057
1109
  refreshDeps: [locale]
1058
1110
  }
1059
1111
  );
1060
- const { trigger: updateAttributes } = useUpdateCartAttributes(mutateCart, metafieldIdentifiers);
1061
- 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" : String(profile?.memberType ?? 0)
1126
+ });
1062
1127
  ahooks.useRequest(
1063
1128
  () => {
1064
- const newAttributes = [...attributes, ...customAttributes];
1065
- 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(
1066
1137
  cart.customAttributes,
1067
1138
  newAttributes,
1068
- customAttributesNeedDelete
1139
+ customAttributesNeedRemove
1069
1140
  );
1070
1141
  if (needUpdate) {
1071
1142
  return updateAttributes({ attributes: newAttributes });
@@ -1078,44 +1149,39 @@ function CartProvider({
1078
1149
  // 1 秒内只触发最后一次更新
1079
1150
  throttleTrailing: true,
1080
1151
  throttleLeading: false,
1081
- refreshDeps: [attributes, customAttributes]
1152
+ refreshDeps: [commonAttributes, customAttributes, customAttributesNeedRemove]
1082
1153
  }
1083
1154
  );
1084
1155
  useUpdateLineCodeAmountAttributes({
1085
1156
  cart,
1086
1157
  mutateCart,
1087
1158
  isCartLoading: isCartLoading || isCodeChanging,
1088
- setLoadingState
1159
+ setLoadingState,
1160
+ metafieldIdentifiers
1089
1161
  });
1090
1162
  const removeCustomAttributes = react.useCallback(
1091
- (attributes2) => {
1092
- setCustomAttributesNeedDelete(attributes2);
1163
+ (attributes) => {
1164
+ setCustomAttributesNeedRemove(attributes);
1093
1165
  },
1094
- [setCustomAttributesNeedDelete]
1166
+ [setCustomAttributesNeedRemove]
1095
1167
  );
1096
1168
  const addCustomAttributes = react.useCallback(
1097
- (attributes2) => {
1098
- const sameAttributes = attributes2.filter(
1099
- (attr) => customAttributes.some((a) => a.key === attr.key)
1100
- );
1101
- if (sameAttributes.length) {
1102
- setCustomAttributes((prev) => {
1103
- const removedAttributes = prev.filter(
1104
- (attr) => !sameAttributes.some((a) => a.key === attr.key)
1105
- );
1106
- return [...removedAttributes, ...attributes2];
1107
- });
1108
- } else {
1109
- setCustomAttributes((prev) => [...prev, ...attributes2]);
1110
- }
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
+ });
1111
1176
  },
1112
- [customAttributes]
1177
+ [setCustomAttributes]
1113
1178
  );
1114
1179
  const functionAutoFreeGiftResult = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer);
1115
1180
  const scriptAutoFreeGiftResult = useScriptAutoFreeGift({
1116
1181
  campaign: gradientGiftsConfig || null,
1117
1182
  _giveaway: CUSTOMER_SCRIPT_GIFT_KEY,
1118
- cart
1183
+ cart,
1184
+ profile
1119
1185
  });
1120
1186
  const formattedScriptGifts = react.useMemo(() => {
1121
1187
  return formatScriptAutoFreeGift({
@@ -1166,16 +1232,23 @@ function CartProvider({
1166
1232
  );
1167
1233
  return result;
1168
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]);
1169
1240
  const value = react.useMemo(
1170
1241
  () => ({
1242
+ totalQuantity,
1171
1243
  cart,
1172
1244
  isCartLoading,
1173
1245
  triggerFetch: fetchCart,
1174
1246
  mutateCart,
1175
1247
  addCustomAttributes,
1176
1248
  removeCustomAttributes,
1177
- setCustomAttributes,
1178
1249
  locale,
1250
+ profile,
1251
+ customer,
1179
1252
  isCodeChanging,
1180
1253
  setIsCodeChanging,
1181
1254
  autoFreeGiftConfig,
@@ -1191,10 +1264,12 @@ function CartProvider({
1191
1264
  scriptAutoFreeGiftResult,
1192
1265
  setScriptAutoFreeGift,
1193
1266
  giftNeedAddToCartLines,
1194
- metafieldIdentifiers
1267
+ metafieldIdentifiers,
1268
+ memberSetting
1195
1269
  }),
1196
1270
  [
1197
1271
  cart,
1272
+ totalQuantity,
1198
1273
  isCartLoading,
1199
1274
  fetchCart,
1200
1275
  mutateCart,
@@ -1214,14 +1289,17 @@ function CartProvider({
1214
1289
  scriptAutoFreeGiftResult,
1215
1290
  setScriptAutoFreeGift,
1216
1291
  giftNeedAddToCartLines,
1217
- metafieldIdentifiers
1292
+ metafieldIdentifiers,
1293
+ customer,
1294
+ profile,
1295
+ memberSetting
1218
1296
  ]
1219
1297
  );
1220
1298
  return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
1221
1299
  }
1222
- function useCartContext() {
1300
+ function useCartContext(options) {
1223
1301
  const context = react.useContext(CartContext);
1224
- if (!context) {
1302
+ if (!context && !options?.optional) {
1225
1303
  throw new Error("useCartContext must be used within a CartProvider");
1226
1304
  }
1227
1305
  return context;