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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,9 @@
1
1
  import { createContext, useMemo, useContext, useState, useCallback, useEffect, useRef } from 'react';
2
- import { createShopifyClient, getCart, updateCartAttributes, updateCartLines, getProductsByHandles } from '@anker-in/shopify-sdk';
2
+ import { createShopifyClient, getCart, updateCartAttributes, updateCartLines, getProductsByHandles, getLocalStorage } from '@anker-in/shopify-sdk';
3
3
  import Cookies5 from 'js-cookie';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
  import Decimal2 from 'decimal.js';
6
+ import { btoaID, atobID } from '@anker-in/shopify-core';
6
7
  import useSWR from 'swr';
7
8
  import useSWRMutation8 from 'swr/mutation';
8
9
  import { useRequest } from 'ahooks';
@@ -52,7 +53,8 @@ function ShopifyProvider({
52
53
  cartCookieAdapter = browserCartCookieAdapter,
53
54
  routerAdapter,
54
55
  userAdapter,
55
- children
56
+ children,
57
+ performanceAdapter
56
58
  }) {
57
59
  const client = useMemo(() => {
58
60
  return createShopifyClient(config, locale);
@@ -66,7 +68,8 @@ function ShopifyProvider({
66
68
  cookieAdapter,
67
69
  cartCookieAdapter,
68
70
  routerAdapter,
69
- userAdapter
71
+ userAdapter,
72
+ performanceAdapter
70
73
  };
71
74
  }, [
72
75
  client,
@@ -76,6 +79,7 @@ function ShopifyProvider({
76
79
  cookieAdapter,
77
80
  cartCookieAdapter,
78
81
  routerAdapter,
82
+ performanceAdapter,
79
83
  userAdapter
80
84
  ]);
81
85
  return /* @__PURE__ */ jsx(ShopifyContext.Provider, { value, children });
@@ -101,9 +105,10 @@ function normalizeAddToCartLines(lines) {
101
105
  const variant = line.variant;
102
106
  const product = variant.product;
103
107
  const quantity = line.quantity || 1;
104
- const price = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : variant.price?.amount ? Number(variant.price.amount) : 0;
105
- const subtotalAmount = price * quantity;
106
- const totalAmount = subtotalAmount;
108
+ const originalPrice = variant.price?.amount ? Number(variant.price.amount) : 0;
109
+ const finalPrice = variant.finalPrice?.amount === void 0 ? originalPrice : Number(variant.finalPrice?.amount);
110
+ const subtotalAmount = originalPrice * quantity;
111
+ const totalAmount = finalPrice * quantity;
107
112
  return {
108
113
  id: `temp-line-${index}-${variant.id}`,
109
114
  // Temporary ID for pre-cart lines
@@ -117,7 +122,7 @@ function normalizeAddToCartLines(lines) {
117
122
  customAttributes: line.attributes || [],
118
123
  variant: {
119
124
  id: variant.id,
120
- price,
125
+ price: finalPrice,
121
126
  listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
122
127
  sku: variant.sku || "",
123
128
  name: variant.title || "",
@@ -148,12 +153,13 @@ function createMockCartFromLines(lines, existingCart) {
148
153
  const normalizedLines = normalizeAddToCartLines(lines);
149
154
  const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
150
155
  const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
156
+ const currency = lines[0]?.variant?.price?.currencyCode;
151
157
  return {
152
158
  id: existingCart?.id || "temp-cart-id",
153
159
  customerId: existingCart?.customerId,
154
160
  email: existingCart?.email,
155
161
  createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
156
- currency: existingCart?.currency || { code: "USD" },
162
+ currency: existingCart?.currency || { code: currency },
157
163
  taxesIncluded: existingCart?.taxesIncluded,
158
164
  lineItems: normalizedLines,
159
165
  totalLineItemsDiscount: 0,
@@ -187,16 +193,6 @@ var getQuery = () => {
187
193
  }
188
194
  return theRequest;
189
195
  };
190
- function atobID(id) {
191
- if (id && typeof id === "string" && id.includes("/")) {
192
- return id.split("/").pop()?.split("?")?.shift();
193
- } else {
194
- return id;
195
- }
196
- }
197
- function btoaID(id, type = "ProductVariant") {
198
- return `gid://shopify/${type}/${id}`;
199
- }
200
196
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
201
197
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
202
198
  const matchedList = cartData?.lineItems?.filter((line) => {
@@ -220,14 +216,6 @@ var getDiscountEnvAttributeValue = (attributes = []) => {
220
216
  const attr = attributes.find((attr2) => attr2.key === CUSTOMER_ATTRIBUTE_KEY);
221
217
  return safeParse(attr?.value ?? "") ?? {};
222
218
  };
223
- var checkAttributesUpdateNeeded = (oldAttributes, newAttributes, customAttributesNeedRemove) => {
224
- return oldAttributes.some((attr) => {
225
- const newAttr = newAttributes.find((newAttr2) => newAttr2.key === attr.key);
226
- return newAttr ? newAttr.value !== attr.value : true;
227
- }) || newAttributes.some((attr) => !oldAttributes.some((oldAttr) => oldAttr.key === attr.key)) || customAttributesNeedRemove.some(
228
- (removeAttr) => oldAttributes.some((oldAttr) => oldAttr.key === removeAttr.key)
229
- );
230
- };
231
219
  var containsAll = (source, requiredItems = []) => {
232
220
  if (!requiredItems?.length) return true;
233
221
  const sourceSet = new Set(source);
@@ -425,43 +413,29 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
425
413
  }
426
414
  return { activeCampaign: null, subtotal: 0 };
427
415
  }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
428
- const { qualifyingGift, nextTierGoal } = useMemo(() => {
416
+ const { qualifyingTier, nextTierGoal, actualThreshold, currentCurrency } = useMemo(() => {
429
417
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
430
- return { qualifyingGift: null, nextTierGoal: null };
418
+ return { qualifyingTier: null, nextTierGoal: null, actualThreshold: 0, currentCurrency: "" };
431
419
  }
432
420
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
433
- const qualifyingTier = [...giftTiers].sort((a, b) => Number(b.spend_sum_money) - Number(a.spend_sum_money)).find((tier) => subtotal >= Number(tier.spend_sum_money));
434
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
435
- if (!qualifyingTier) {
436
- return { qualifyingGift: null, nextTierGoal: nextGoal || null };
437
- }
438
- const formattedGift = {
439
- tier: qualifyingTier,
440
- itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
441
- const giftProduct = reward?.variant_list?.[0];
442
- if (!giftProduct) return null;
443
- return {
444
- variant: {
445
- id: btoaID(giftProduct.variant_id),
446
- handle: giftProduct.handle,
447
- sku: giftProduct.sku
448
- },
449
- quantity: reward?.get_unit || 1,
450
- attributes: [
451
- {
452
- key: CUSTOMER_ATTRIBUTE_KEY,
453
- value: JSON.stringify({
454
- is_gift: true,
455
- rule_id: activeCampaign.rule_id,
456
- spend_sum_money: qualifyingTier.spend_sum_money
457
- })
458
- }
459
- ]
460
- };
461
- }).filter((item) => item !== null)
421
+ const currentCurrency2 = effectiveCart?.currency?.code || "";
422
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency2);
423
+ const getThresholdAmount = (tier) => {
424
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency2]?.value) {
425
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency2].value);
426
+ }
427
+ return Number(tier.spend_sum_money || 0);
462
428
  };
463
- return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
464
- }, [activeCampaign, subtotal]);
429
+ const qualifyingTier2 = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
430
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
431
+ const actualThreshold2 = qualifyingTier2 ? getThresholdAmount(qualifyingTier2) : 0;
432
+ return {
433
+ qualifyingTier: qualifyingTier2,
434
+ nextTierGoal: nextGoal || null,
435
+ actualThreshold: actualThreshold2,
436
+ currentCurrency: currentCurrency2
437
+ };
438
+ }, [activeCampaign, subtotal, effectiveCart]);
465
439
  const giftHandles = useMemo(() => {
466
440
  const giftVariant = autoFreeGiftConfig.map(
467
441
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -477,24 +451,82 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
477
451
  }
478
452
  return true;
479
453
  }, [giftHandles]);
480
- const { data: giftProductsResult } = useSWR(shouldFetch ? giftHandles : null, async () => {
481
- const res = await getProductsByHandles(client, {
482
- handles: giftHandles,
483
- locale
484
- });
485
- const result = Array.isArray(res) ? res : [];
486
- giftProductsCache.current = {
487
- data: result,
488
- giftHandles: [...giftHandles]
489
- };
490
- return result;
491
- });
454
+ const { data: giftProductsResult } = useSWR(
455
+ shouldFetch ? giftHandles : null,
456
+ async () => {
457
+ const res = await getProductsByHandles(client, {
458
+ handles: giftHandles,
459
+ locale
460
+ });
461
+ const result = Array.isArray(res) ? res : [];
462
+ giftProductsCache.current = {
463
+ data: result,
464
+ giftHandles: [...giftHandles]
465
+ };
466
+ return result;
467
+ },
468
+ {
469
+ revalidateOnFocus: false
470
+ }
471
+ );
492
472
  const finalGiftProductsResult = useMemo(() => {
493
473
  if (giftProductsCache.current && !shouldFetch) {
494
474
  return giftProductsCache.current.data || void 0;
495
475
  }
496
476
  return giftProductsResult;
497
477
  }, [giftProductsResult, shouldFetch]);
478
+ const qualifyingGift = useMemo(() => {
479
+ if (!qualifyingTier || !activeCampaign) {
480
+ return null;
481
+ }
482
+ const itemsToAdd = qualifyingTier.reward_list?.map((reward) => {
483
+ if (!reward.variant_list || reward.variant_list.length === 0) {
484
+ return null;
485
+ }
486
+ let selectedGiftProduct = null;
487
+ for (const giftVariant of reward.variant_list) {
488
+ const productInfo = finalGiftProductsResult?.find(
489
+ (p) => p.handle === giftVariant.handle
490
+ );
491
+ if (productInfo) {
492
+ const variantInfo = productInfo.variants?.find((v) => v.sku === giftVariant.sku);
493
+ if (variantInfo?.availableForSale) {
494
+ selectedGiftProduct = giftVariant;
495
+ break;
496
+ }
497
+ }
498
+ }
499
+ if (!selectedGiftProduct) {
500
+ selectedGiftProduct = reward.variant_list[0];
501
+ }
502
+ return {
503
+ variant: {
504
+ id: btoaID(selectedGiftProduct.variant_id),
505
+ handle: selectedGiftProduct.handle,
506
+ sku: selectedGiftProduct.sku
507
+ },
508
+ quantity: reward?.get_unit || 1,
509
+ attributes: [
510
+ {
511
+ key: CUSTOMER_ATTRIBUTE_KEY,
512
+ value: JSON.stringify({
513
+ is_gift: true,
514
+ rule_id: activeCampaign.rule_id,
515
+ spend_sum_money: actualThreshold,
516
+ // 使用实际的门槛金额(多币种支持)
517
+ currency_code: currentCurrency
518
+ // 记录当前币种
519
+ })
520
+ }
521
+ ]
522
+ };
523
+ }).filter((item) => item !== null);
524
+ const formattedGift = {
525
+ tier: qualifyingTier,
526
+ itemsToAdd
527
+ };
528
+ return formattedGift;
529
+ }, [qualifyingTier, activeCampaign, finalGiftProductsResult, actualThreshold, currentCurrency]);
498
530
  return {
499
531
  qualifyingGift,
500
532
  nextTierGoal,
@@ -508,7 +540,8 @@ var useScriptAutoFreeGift = ({
508
540
  _giveaway,
509
541
  cart,
510
542
  locale: providedLocale,
511
- lines
543
+ lines,
544
+ profile
512
545
  }) => {
513
546
  const { client, locale: contextLocale } = useShopify();
514
547
  const locale = providedLocale || contextLocale;
@@ -532,8 +565,9 @@ var useScriptAutoFreeGift = ({
532
565
  const utmCampaign = Cookies5.get("utm_campaign") || query?.utm_campaign;
533
566
  if (campaign.activityAvailableQuery && !utmCampaign?.includes(campaign.activityAvailableQuery))
534
567
  return false;
568
+ if (campaign.requireLogin && !profile?.email) return false;
535
569
  return true;
536
- }, [campaign]);
570
+ }, [campaign, profile]);
537
571
  const [upgrade_multiple, upgrade_value] = useMemo(() => {
538
572
  let upgrade_multiple2 = 1;
539
573
  let upgrade_value2 = 0;
@@ -541,12 +575,14 @@ var useScriptAutoFreeGift = ({
541
575
  upgrade_multiple2 = 1.2;
542
576
  upgrade_value2 = 40;
543
577
  }
544
- effectiveCart?.lineItems?.forEach(({ customAttributes }) => {
545
- customAttributes?.forEach(({ key, value }) => {
546
- if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
547
- if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
548
- });
549
- });
578
+ effectiveCart?.lineItems?.forEach(
579
+ ({ customAttributes }) => {
580
+ customAttributes?.forEach(({ key, value }) => {
581
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
582
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
583
+ });
584
+ }
585
+ );
550
586
  return [upgrade_multiple2, upgrade_value2];
551
587
  }, [effectiveCart?.lineItems, points_subscribe]);
552
588
  const breakpoints = useMemo(() => {
@@ -611,18 +647,24 @@ var useScriptAutoFreeGift = ({
611
647
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
612
648
  return [currentLevel, nextLevel];
613
649
  }, [breakpoints, involvedSubTotal, involvedLines.length]);
614
- const { data: giftProductsResult } = useSWR(shouldFetch ? giftHandles : null, async () => {
615
- const res = await getProductsByHandles(client, {
616
- handles: giftHandles,
617
- locale
618
- });
619
- const result = Array.isArray(res) ? res : [];
620
- giftProductsCache.current = {
621
- data: result,
622
- giftHandles: [...giftHandles]
623
- };
624
- return result;
625
- });
650
+ const { data: giftProductsResult } = useSWR(
651
+ shouldFetch ? giftHandles : null,
652
+ async () => {
653
+ const res = await getProductsByHandles(client, {
654
+ handles: giftHandles,
655
+ locale
656
+ });
657
+ const result = Array.isArray(res) ? res : [];
658
+ giftProductsCache.current = {
659
+ data: result,
660
+ giftHandles: [...giftHandles]
661
+ };
662
+ return result;
663
+ },
664
+ {
665
+ revalidateOnFocus: false
666
+ }
667
+ );
626
668
  const finalGiftProductsResult = useMemo(() => {
627
669
  if (giftProductsCache.current && !shouldFetch) {
628
670
  return giftProductsCache.current.data || void 0;
@@ -654,62 +696,20 @@ var useScriptAutoFreeGift = ({
654
696
  giftProductsResult: finalGiftProductsResult
655
697
  };
656
698
  };
657
- function useUpdateCartAttributes(mutate, metafieldIdentifiers, options) {
658
- const { client, locale, cartCookieAdapter } = useShopify();
659
- const updateAttributes = useCallback(
660
- async (_key, { arg }) => {
661
- const updatedCart = await updateCartAttributes(client, {
662
- ...arg,
663
- metafieldIdentifiers,
664
- cookieAdapter: cartCookieAdapter
665
- });
666
- console.log("useUpdateCartAttributes updatedCart", updatedCart);
667
- if (updatedCart) {
668
- mutate(updatedCart);
669
- }
670
- return updatedCart;
671
- },
672
- [client, locale, cartCookieAdapter, mutate]
673
- );
674
- return useSWRMutation8("update-cart-attributes", updateAttributes, options);
675
- }
676
- function useHasPlusMemberInCart({
677
- memberSetting,
678
- cart
679
- }) {
680
- const { plus_monthly_product, plus_annual_product } = memberSetting || {};
681
- return useMemo(() => {
682
- if (!cart?.lineItems) {
683
- return {
684
- hasPlusMember: false,
685
- hasMonthlyPlus: false,
686
- hasAnnualPlus: false
687
- };
688
- }
689
- const monthlyPlusItem = cart.lineItems.find(
690
- (item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
691
- );
692
- const annualPlusItem = cart.lineItems.find(
693
- (item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
694
- );
695
- const hasMonthlyPlus = !!monthlyPlusItem;
696
- const hasAnnualPlus = !!annualPlusItem;
697
- const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
698
- return {
699
- hasPlusMember,
700
- hasMonthlyPlus,
701
- hasAnnualPlus,
702
- monthlyPlusItem,
703
- annualPlusItem
704
- };
705
- }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
706
- }
707
699
 
708
- // src/hooks/cart/feature/use-cart-attributes.ts
700
+ // src/hooks/cart/utils/cart-attributes.ts
701
+ var checkAttributesUpdateNeeded = (oldAttributes, newAttributes, customAttributesNeedRemove) => {
702
+ return newAttributes.some((attr) => !oldAttributes.some((oldAttr) => oldAttr.key === attr.key)) || oldAttributes.some((attr) => {
703
+ const newAttr = newAttributes.find((newAttr2) => newAttr2.key === attr.key);
704
+ return newAttr ? newAttr.value !== attr.value : true;
705
+ }) || customAttributesNeedRemove.some(
706
+ (removeAttr) => oldAttributes.some((oldAttr) => oldAttr.key === removeAttr.key)
707
+ );
708
+ };
709
709
  var getReferralAttributes = () => {
710
- const inviteCode = Cookies5.get("invite_code");
711
- const playModeId = Cookies5.get("playModeId");
712
- const popup = Cookies5.get("_popup");
710
+ const inviteCode = getLocalStorage("inviteCode") || Cookies5.get("inviteCode");
711
+ const playModeId = getLocalStorage("playModeId") || Cookies5.get("playModeId");
712
+ const popup = getLocalStorage("_popup") || Cookies5.get("_popup");
713
713
  if (inviteCode && playModeId) {
714
714
  return popup ? [
715
715
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -722,121 +722,130 @@ var getReferralAttributes = () => {
722
722
  }
723
723
  return [];
724
724
  };
725
+ var getUserType = (customer) => {
726
+ let userInfo = Cookies5.get("userInfo");
727
+ if (userInfo) {
728
+ userInfo = JSON.parse(userInfo);
729
+ let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
730
+ userInfo.setId = arr[arr.length - 1];
731
+ }
732
+ const customerInfo = userInfo || customer;
733
+ if (!customerInfo) {
734
+ return "new_user_unlogin";
735
+ }
736
+ if (customer) {
737
+ const { orders = {} } = customer;
738
+ if (orders?.edges?.length === 1) {
739
+ return "old_user_orders_once";
740
+ } else if (orders?.edges?.length > 1) {
741
+ return "old_user_orders_twice";
742
+ }
743
+ }
744
+ return "new_user_login";
745
+ };
746
+ function getCartAttributes({
747
+ profile,
748
+ customer,
749
+ cart,
750
+ memberType,
751
+ currentUrl = ""
752
+ }) {
753
+ const userType = getUserType(customer);
754
+ const memberAttributes = [
755
+ {
756
+ key: "_token",
757
+ value: profile?.token
758
+ },
759
+ {
760
+ key: "_member_type",
761
+ value: memberType ?? String(profile?.memberType ?? 0)
762
+ },
763
+ {
764
+ key: "_user_type",
765
+ value: userType
766
+ },
767
+ {
768
+ key: "_is_login",
769
+ value: profile?.token ? "true" : "false"
770
+ }
771
+ ];
772
+ if (profile?.token) {
773
+ memberAttributes.push({
774
+ key: "_login_user",
775
+ value: "1"
776
+ });
777
+ }
778
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
779
+ const functionAttributes = [
780
+ {
781
+ key: CUSTOMER_ATTRIBUTE_KEY,
782
+ value: JSON.stringify({
783
+ discount_code: discountCodes,
784
+ user_tags: customer?.tags || []
785
+ })
786
+ }
787
+ ];
788
+ const presellAttributes = [
789
+ {
790
+ key: "_presale",
791
+ value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
792
+ }
793
+ ];
794
+ const weightAttributes = [
795
+ {
796
+ key: "_weight",
797
+ value: cart?.lineItems.reduce((acc, item) => {
798
+ return new Decimal2(acc).plus(item.variant.weight ?? 0).toNumber();
799
+ }, 0).toString()
800
+ },
801
+ {
802
+ key: "_app_source_name",
803
+ value: "dtc"
804
+ }
805
+ ];
806
+ const trackingAttributes = [
807
+ {
808
+ key: "utm_params",
809
+ value: currentUrl
810
+ }
811
+ ];
812
+ const commonAttributes = [
813
+ ...memberAttributes,
814
+ ...functionAttributes,
815
+ ...presellAttributes,
816
+ ...weightAttributes,
817
+ ...trackingAttributes,
818
+ ...getReferralAttributes()
819
+ ].filter((item) => item?.value);
820
+ const extraAttributesInCart = cart?.customAttributes?.filter(
821
+ (item) => !commonAttributes.some((attr) => attr.key === item.key)
822
+ ) || [];
823
+ return [...commonAttributes, ...extraAttributesInCart].filter((item) => item?.value);
824
+ }
725
825
  var useCartAttributes = ({
726
826
  profile,
727
827
  customer,
728
828
  cart,
729
- memberSetting
829
+ memberType
730
830
  }) => {
731
831
  const [currentUrl, setCurrentUrl] = useState("");
732
- const { hasPlusMember } = useHasPlusMemberInCart({
733
- memberSetting,
734
- cart
735
- });
736
832
  useEffect(() => {
737
833
  setCurrentUrl(window.location.href);
738
834
  }, []);
739
- const userType = useMemo(() => {
740
- let userInfo = Cookies5.get("userInfo");
741
- if (userInfo) {
742
- userInfo = JSON.parse(userInfo);
743
- let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
744
- userInfo.setId = arr[arr.length - 1];
745
- }
746
- const customerInfo = userInfo || customer;
747
- if (!customerInfo) {
748
- return "new_user_unlogin";
749
- }
750
- if (customer) {
751
- const { orders = {} } = customer;
752
- if (orders?.edges?.length === 1) {
753
- return "old_user_orders_once";
754
- } else if (orders?.edges?.length > 1) {
755
- return "old_user_orders_twice";
756
- }
757
- }
758
- return "new_user_login";
759
- }, [customer]);
760
- const memberAttributes = useMemo(() => {
761
- return [
762
- {
763
- key: "_token",
764
- value: profile?.token
765
- //是否登录
766
- },
767
- {
768
- key: "_member_type",
769
- value: hasPlusMember ? "2" : profile?.memberType
770
- //:0(游客),1(普通会员),2(付费会员)
771
- },
772
- {
773
- key: "_user_type",
774
- value: userType
775
- // n
776
- },
777
- {
778
- key: "_is_login",
779
- value: profile?.token ? "true" : "false"
780
- }
781
- ];
782
- }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
783
- const functionAttributes = useMemo(() => {
784
- const hasFunctionEnvAttribute = cart?.lineItems.some(
785
- (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
786
- );
787
- const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
788
- return hasFunctionEnvAttribute ? [
789
- {
790
- key: "_discounts_function_env",
791
- value: JSON.stringify({
792
- discount_code: discountCodes,
793
- user_tags: customer?.tags || []
794
- })
795
- }
796
- ] : [];
797
- }, [cart]);
798
- const presellAttributes = useMemo(() => {
799
- return [
800
- {
801
- key: "_presale",
802
- value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
803
- }
804
- ];
805
- }, [cart]);
806
- const weightAttributes = useMemo(() => {
807
- return [
808
- {
809
- key: "_weight",
810
- value: cart?.lineItems.reduce((acc, item) => {
811
- return new Decimal2(acc).plus(item.variant.weight ?? 0).toNumber();
812
- }, 0).toString()
813
- },
814
- {
815
- key: "_app_source_name",
816
- value: "dtc"
817
- }
818
- ];
819
- }, [cart]);
820
- const trackingAttributes = useMemo(() => {
821
- return [
822
- {
823
- key: "utm_params",
824
- value: currentUrl
825
- }
826
- ];
827
- }, [currentUrl]);
835
+ const attributes = useMemo(() => {
836
+ return getCartAttributes({
837
+ profile,
838
+ customer,
839
+ cart,
840
+ memberType,
841
+ currentUrl
842
+ });
843
+ }, [profile, customer, cart, memberType, currentUrl]);
828
844
  return useMemo(
829
845
  () => ({
830
- attributes: [
831
- ...memberAttributes,
832
- ...functionAttributes,
833
- ...presellAttributes,
834
- ...weightAttributes,
835
- ...trackingAttributes,
836
- ...getReferralAttributes()
837
- ].filter((item) => item?.value)
846
+ attributes
838
847
  }),
839
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
848
+ [attributes]
840
849
  );
841
850
  };
842
851
  var useUpdateLineCodeAmountAttributes = ({
@@ -865,7 +874,7 @@ var useUpdateLineCodeAmountAttributes = ({
865
874
  );
866
875
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
867
876
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
868
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
877
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
869
878
  attrNeedUpdate.push({
870
879
  key: CUSTOMER_ATTRIBUTE_KEY,
871
880
  value: JSON.stringify({
@@ -904,29 +913,22 @@ var useUpdateLineCodeAmountAttributes = ({
904
913
  }).filter(
905
914
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
906
915
  ).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
916
+ let lineId = line.id;
917
+ let attributes = line.customAttributes || [];
918
+ if (attrNeedDelete.length) {
919
+ attributes = attributes.filter(
920
+ (attr) => !attrNeedDelete.includes(attr.key)
921
+ );
922
+ }
907
923
  if (attrNeedUpdate.length) {
908
- return {
909
- id: line.id,
910
- attributes: [
911
- ...line.customAttributes?.filter(
912
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
913
- ) || [],
914
- ...attrNeedUpdate
915
- ]
916
- };
917
- } else if (attrNeedDelete.length) {
918
- return {
919
- id: line.id,
920
- attributes: line.customAttributes?.filter(
921
- (attr) => !attrNeedDelete.includes(attr.key)
922
- ) || []
923
- };
924
- } else {
925
- return {
926
- id: line.id,
927
- attributes: line.customAttributes || []
928
- };
924
+ attributes = attributes.filter(
925
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
926
+ ).concat(attrNeedUpdate);
929
927
  }
928
+ return {
929
+ id: lineId,
930
+ attributes
931
+ };
930
932
  }),
931
933
  [cart?.lineItems, mainProductDiscountCodes]
932
934
  );
@@ -961,28 +963,13 @@ var useUpdateLineCodeAmountAttributes = ({
961
963
  }, [loading, setLoadingState]);
962
964
  };
963
965
  var createInitialValue = () => ({
964
- zipCode: "",
965
966
  plusMemberMetafields: {},
966
- setZipCode: () => {
967
- },
968
- allowNextDayDelivery: false,
969
- setAllowNextDayDelivery: () => {
970
- },
971
- allowThirdDayDelivery: false,
972
- setAllowThirdDayDelivery: () => {
973
- },
974
967
  selectedPlusMemberMode: "free",
975
968
  setSelectedPlusMemberMode: () => {
976
969
  },
977
- showAreaCheckModal: false,
978
- setShowAreaCheckModal: () => {
979
- },
980
970
  selectedShippingMethod: void 0,
981
971
  setSelectedShippingMethod: () => {
982
972
  },
983
- showTip: false,
984
- setShowTip: () => {
985
- },
986
973
  showMoreShippingMethod: false,
987
974
  setShowMoreShippingMethod: () => {
988
975
  },
@@ -992,20 +979,85 @@ var createInitialValue = () => ({
992
979
  freeShippingMethods: [],
993
980
  paymentShippingMethods: [],
994
981
  nddOverweight: false,
995
- tddOverweight: false
982
+ tddOverweight: false,
983
+ nddCoupon: void 0,
984
+ tddCoupon: void 0,
985
+ isLoadingCoupon: false
996
986
  },
997
- selectedPlusMemberProduct: null,
998
- plusMemberProducts: [],
987
+ selectedPlusMemberVariant: void 0,
999
988
  showPlusMemberBenefit: false,
1000
989
  setShowPlusMemberBenefit: () => {
1001
990
  },
1002
- deleteMarginBottom: false,
1003
- setDeleteMarginBottom: () => {
1004
- },
1005
- profile: void 0,
1006
- locale: void 0
991
+ profile: void 0
1007
992
  });
1008
993
  createContext(createInitialValue());
994
+ function hasPlusMemberInCart({
995
+ memberSetting,
996
+ cart
997
+ }) {
998
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
999
+ if (!cart?.lineItems) {
1000
+ return {
1001
+ hasPlusMember: false,
1002
+ hasMonthlyPlus: false,
1003
+ hasAnnualPlus: false
1004
+ };
1005
+ }
1006
+ const monthlyPlusItem = cart.lineItems.find(
1007
+ (item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
1008
+ );
1009
+ const annualPlusItem = cart.lineItems.find(
1010
+ (item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
1011
+ );
1012
+ const hasMonthlyPlus = !!monthlyPlusItem;
1013
+ const hasAnnualPlus = !!annualPlusItem;
1014
+ const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
1015
+ return {
1016
+ hasPlusMember,
1017
+ hasMonthlyPlus,
1018
+ hasAnnualPlus,
1019
+ monthlyPlusItem,
1020
+ annualPlusItem
1021
+ };
1022
+ }
1023
+ function useHasPlusMemberInCart({
1024
+ memberSetting,
1025
+ cart
1026
+ }) {
1027
+ return useMemo(
1028
+ () => hasPlusMemberInCart({
1029
+ memberSetting,
1030
+ cart
1031
+ }),
1032
+ [memberSetting, cart]
1033
+ );
1034
+ }
1035
+ function useUpdateCartAttributes({
1036
+ mutate,
1037
+ metafieldIdentifiers,
1038
+ disabled = false,
1039
+ swrOptions
1040
+ }) {
1041
+ const { client, locale, cartCookieAdapter } = useShopify();
1042
+ const updateAttributes = useCallback(
1043
+ async (_key, { arg }) => {
1044
+ if (disabled) {
1045
+ return void 0;
1046
+ }
1047
+ const updatedCart = await updateCartAttributes(client, {
1048
+ ...arg,
1049
+ metafieldIdentifiers,
1050
+ cookieAdapter: cartCookieAdapter
1051
+ });
1052
+ if (updatedCart) {
1053
+ mutate(updatedCart);
1054
+ }
1055
+ return updatedCart;
1056
+ },
1057
+ [client, locale, cartCookieAdapter, mutate, metafieldIdentifiers, disabled]
1058
+ );
1059
+ return useSWRMutation8("update-cart-attributes", updateAttributes, swrOptions);
1060
+ }
1009
1061
  var CartContext = createContext(null);
1010
1062
  function CartProvider({
1011
1063
  children,
@@ -1020,7 +1072,7 @@ function CartProvider({
1020
1072
  }) {
1021
1073
  const { client, cartCookieAdapter } = useShopify();
1022
1074
  const [customAttributes, setCustomAttributes] = useState([]);
1023
- const [customAttributesNeedDelete, setCustomAttributesNeedDelete] = useState(
1075
+ const [customAttributesNeedRemove, setCustomAttributesNeedRemove] = useState(
1024
1076
  []
1025
1077
  );
1026
1078
  const [isCodeChanging, setIsCodeChanging] = useState(false);
@@ -1048,15 +1100,34 @@ function CartProvider({
1048
1100
  refreshDeps: [locale]
1049
1101
  }
1050
1102
  );
1051
- const { trigger: updateAttributes } = useUpdateCartAttributes(mutateCart, metafieldIdentifiers);
1052
- const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
1103
+ const { trigger: updateAttributes } = useUpdateCartAttributes({
1104
+ mutate: mutateCart,
1105
+ metafieldIdentifiers,
1106
+ disabled: isCartLoading
1107
+ });
1108
+ const { hasPlusMember } = useHasPlusMemberInCart({
1109
+ memberSetting,
1110
+ cart
1111
+ });
1112
+ const { attributes: commonAttributes } = useCartAttributes({
1113
+ profile,
1114
+ customer,
1115
+ cart,
1116
+ memberType: hasPlusMember ? "2" : String(profile?.memberType ?? 0)
1117
+ });
1053
1118
  useRequest(
1054
1119
  () => {
1055
- const newAttributes = [...attributes, ...customAttributes];
1056
- const needUpdate = cart && !checkAttributesUpdateNeeded(
1120
+ const filteredSameCommonAttributes = commonAttributes.filter(
1121
+ (attr) => !customAttributes.some((a) => a.key === attr.key)
1122
+ );
1123
+ const newAttributes = [
1124
+ ...filteredSameCommonAttributes,
1125
+ ...customAttributes
1126
+ ];
1127
+ const needUpdate = cart && checkAttributesUpdateNeeded(
1057
1128
  cart.customAttributes,
1058
1129
  newAttributes,
1059
- customAttributesNeedDelete
1130
+ customAttributesNeedRemove
1060
1131
  );
1061
1132
  if (needUpdate) {
1062
1133
  return updateAttributes({ attributes: newAttributes });
@@ -1069,44 +1140,39 @@ function CartProvider({
1069
1140
  // 1 秒内只触发最后一次更新
1070
1141
  throttleTrailing: true,
1071
1142
  throttleLeading: false,
1072
- refreshDeps: [attributes, customAttributes]
1143
+ refreshDeps: [commonAttributes, customAttributes, customAttributesNeedRemove]
1073
1144
  }
1074
1145
  );
1075
1146
  useUpdateLineCodeAmountAttributes({
1076
1147
  cart,
1077
1148
  mutateCart,
1078
1149
  isCartLoading: isCartLoading || isCodeChanging,
1079
- setLoadingState
1150
+ setLoadingState,
1151
+ metafieldIdentifiers
1080
1152
  });
1081
1153
  const removeCustomAttributes = useCallback(
1082
- (attributes2) => {
1083
- setCustomAttributesNeedDelete(attributes2);
1154
+ (attributes) => {
1155
+ setCustomAttributesNeedRemove(attributes);
1084
1156
  },
1085
- [setCustomAttributesNeedDelete]
1157
+ [setCustomAttributesNeedRemove]
1086
1158
  );
1087
1159
  const addCustomAttributes = useCallback(
1088
- (attributes2) => {
1089
- const sameAttributes = attributes2.filter(
1090
- (attr) => customAttributes.some((a) => a.key === attr.key)
1091
- );
1092
- if (sameAttributes.length) {
1093
- setCustomAttributes((prev) => {
1094
- const removedAttributes = prev.filter(
1095
- (attr) => !sameAttributes.some((a) => a.key === attr.key)
1096
- );
1097
- return [...removedAttributes, ...attributes2];
1098
- });
1099
- } else {
1100
- setCustomAttributes((prev) => [...prev, ...attributes2]);
1101
- }
1160
+ (attributes) => {
1161
+ setCustomAttributes((oldCustomAttributes) => {
1162
+ const filteredSameAttributes = oldCustomAttributes.filter(
1163
+ (attr) => !attributes.some((a) => a.key === attr.key)
1164
+ );
1165
+ return [...filteredSameAttributes, ...attributes];
1166
+ });
1102
1167
  },
1103
- [customAttributes]
1168
+ [setCustomAttributes]
1104
1169
  );
1105
1170
  const functionAutoFreeGiftResult = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer);
1106
1171
  const scriptAutoFreeGiftResult = useScriptAutoFreeGift({
1107
1172
  campaign: gradientGiftsConfig || null,
1108
1173
  _giveaway: CUSTOMER_SCRIPT_GIFT_KEY,
1109
- cart
1174
+ cart,
1175
+ profile
1110
1176
  });
1111
1177
  const formattedScriptGifts = useMemo(() => {
1112
1178
  return formatScriptAutoFreeGift({
@@ -1157,16 +1223,23 @@ function CartProvider({
1157
1223
  );
1158
1224
  return result;
1159
1225
  }, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
1226
+ const totalQuantity = useMemo(() => {
1227
+ const cartLinesCount = cart?.lineItems.reduce((acc, item) => acc + item.quantity, 0) || 0;
1228
+ const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
1229
+ return cartLinesCount + giftLinesCount;
1230
+ }, [cart?.lineItems, giftNeedAddToCartLines]);
1160
1231
  const value = useMemo(
1161
1232
  () => ({
1233
+ totalQuantity,
1162
1234
  cart,
1163
1235
  isCartLoading,
1164
1236
  triggerFetch: fetchCart,
1165
1237
  mutateCart,
1166
1238
  addCustomAttributes,
1167
1239
  removeCustomAttributes,
1168
- setCustomAttributes,
1169
1240
  locale,
1241
+ profile,
1242
+ customer,
1170
1243
  isCodeChanging,
1171
1244
  setIsCodeChanging,
1172
1245
  autoFreeGiftConfig,
@@ -1182,10 +1255,12 @@ function CartProvider({
1182
1255
  scriptAutoFreeGiftResult,
1183
1256
  setScriptAutoFreeGift,
1184
1257
  giftNeedAddToCartLines,
1185
- metafieldIdentifiers
1258
+ metafieldIdentifiers,
1259
+ memberSetting
1186
1260
  }),
1187
1261
  [
1188
1262
  cart,
1263
+ totalQuantity,
1189
1264
  isCartLoading,
1190
1265
  fetchCart,
1191
1266
  mutateCart,
@@ -1205,14 +1280,17 @@ function CartProvider({
1205
1280
  scriptAutoFreeGiftResult,
1206
1281
  setScriptAutoFreeGift,
1207
1282
  giftNeedAddToCartLines,
1208
- metafieldIdentifiers
1283
+ metafieldIdentifiers,
1284
+ customer,
1285
+ profile,
1286
+ memberSetting
1209
1287
  ]
1210
1288
  );
1211
1289
  return /* @__PURE__ */ jsx(CartContext.Provider, { value, children });
1212
1290
  }
1213
- function useCartContext() {
1291
+ function useCartContext(options) {
1214
1292
  const context = useContext(CartContext);
1215
- if (!context) {
1293
+ if (!context && !options?.optional) {
1216
1294
  throw new Error("useCartContext must be used within a CartProvider");
1217
1295
  }
1218
1296
  return context;