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

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,15 +153,16 @@ 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
- totallineItemsDiscount: 0,
165
+ totalLineItemsDiscount: 0,
160
166
  orderDiscounts: 0,
161
167
  lineItemsSubtotalPrice: subtotalPrice,
162
168
  subtotalPrice,
@@ -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,117 +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)
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
- return [
785
- cart?.discountCodes && {
786
- key: "_discounts_function_env",
787
- value: JSON.stringify({
788
- discount_code: cart?.discountCodes.map((item) => item.code),
789
- user_tags: customer?.tags || []
790
- })
791
- }
792
- ];
793
- }, [cart]);
794
- const presellAttributes = useMemo(() => {
795
- return [
796
- {
797
- key: "_presale",
798
- value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
799
- }
800
- ];
801
- }, [cart]);
802
- const weightAttributes = useMemo(() => {
803
- return [
804
- {
805
- key: "_weight",
806
- value: cart?.lineItems.reduce((acc, item) => {
807
- return new Decimal2(acc).plus(item.variant.weight ?? 0).toNumber();
808
- }, 0).toString()
809
- },
810
- {
811
- key: "_app_source_name",
812
- value: "dtc"
813
- }
814
- ];
815
- }, [cart]);
816
- const trackingAttributes = useMemo(() => {
817
- return [
818
- {
819
- key: "utm_params",
820
- value: currentUrl
821
- }
822
- ];
823
- }, [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]);
824
844
  return useMemo(
825
845
  () => ({
826
- attributes: [
827
- ...memberAttributes,
828
- ...functionAttributes,
829
- ...presellAttributes,
830
- ...weightAttributes,
831
- ...trackingAttributes,
832
- ...getReferralAttributes()
833
- ].filter((item) => item?.value)
846
+ attributes
834
847
  }),
835
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
848
+ [attributes]
836
849
  );
837
850
  };
838
851
  var useUpdateLineCodeAmountAttributes = ({
@@ -861,7 +874,7 @@ var useUpdateLineCodeAmountAttributes = ({
861
874
  );
862
875
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
863
876
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
864
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
877
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
865
878
  attrNeedUpdate.push({
866
879
  key: CUSTOMER_ATTRIBUTE_KEY,
867
880
  value: JSON.stringify({
@@ -900,29 +913,22 @@ var useUpdateLineCodeAmountAttributes = ({
900
913
  }).filter(
901
914
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
902
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
+ }
903
923
  if (attrNeedUpdate.length) {
904
- return {
905
- id: line.id,
906
- attributes: [
907
- ...line.customAttributes?.filter(
908
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
909
- ) || [],
910
- ...attrNeedUpdate
911
- ]
912
- };
913
- } else if (attrNeedDelete.length) {
914
- return {
915
- id: line.id,
916
- attributes: line.customAttributes?.filter(
917
- (attr) => !attrNeedDelete.includes(attr.key)
918
- ) || []
919
- };
920
- } else {
921
- return {
922
- id: line.id,
923
- attributes: line.customAttributes || []
924
- };
924
+ attributes = attributes.filter(
925
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
926
+ ).concat(attrNeedUpdate);
925
927
  }
928
+ return {
929
+ id: lineId,
930
+ attributes
931
+ };
926
932
  }),
927
933
  [cart?.lineItems, mainProductDiscountCodes]
928
934
  );
@@ -957,28 +963,13 @@ var useUpdateLineCodeAmountAttributes = ({
957
963
  }, [loading, setLoadingState]);
958
964
  };
959
965
  var createInitialValue = () => ({
960
- zipCode: "",
961
966
  plusMemberMetafields: {},
962
- setZipCode: () => {
963
- },
964
- allowNextDayDelivery: false,
965
- setAllowNextDayDelivery: () => {
966
- },
967
- allowThirdDayDelivery: false,
968
- setAllowThirdDayDelivery: () => {
969
- },
970
967
  selectedPlusMemberMode: "free",
971
968
  setSelectedPlusMemberMode: () => {
972
969
  },
973
- showAreaCheckModal: false,
974
- setShowAreaCheckModal: () => {
975
- },
976
970
  selectedShippingMethod: void 0,
977
971
  setSelectedShippingMethod: () => {
978
972
  },
979
- showTip: false,
980
- setShowTip: () => {
981
- },
982
973
  showMoreShippingMethod: false,
983
974
  setShowMoreShippingMethod: () => {
984
975
  },
@@ -988,20 +979,85 @@ var createInitialValue = () => ({
988
979
  freeShippingMethods: [],
989
980
  paymentShippingMethods: [],
990
981
  nddOverweight: false,
991
- tddOverweight: false
982
+ tddOverweight: false,
983
+ nddCoupon: void 0,
984
+ tddCoupon: void 0,
985
+ isLoadingCoupon: false
992
986
  },
993
- selectedPlusMemberProduct: null,
994
- plusMemberProducts: [],
987
+ selectedPlusMemberVariant: void 0,
995
988
  showPlusMemberBenefit: false,
996
989
  setShowPlusMemberBenefit: () => {
997
990
  },
998
- deleteMarginBottom: false,
999
- setDeleteMarginBottom: () => {
1000
- },
1001
- profile: void 0,
1002
- locale: void 0
991
+ profile: void 0
1003
992
  });
1004
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
+ }
1005
1061
  var CartContext = createContext(null);
1006
1062
  function CartProvider({
1007
1063
  children,
@@ -1016,7 +1072,7 @@ function CartProvider({
1016
1072
  }) {
1017
1073
  const { client, cartCookieAdapter } = useShopify();
1018
1074
  const [customAttributes, setCustomAttributes] = useState([]);
1019
- const [customAttributesNeedDelete, setCustomAttributesNeedDelete] = useState(
1075
+ const [customAttributesNeedRemove, setCustomAttributesNeedRemove] = useState(
1020
1076
  []
1021
1077
  );
1022
1078
  const [isCodeChanging, setIsCodeChanging] = useState(false);
@@ -1044,15 +1100,34 @@ function CartProvider({
1044
1100
  refreshDeps: [locale]
1045
1101
  }
1046
1102
  );
1047
- const { trigger: updateAttributes } = useUpdateCartAttributes(mutateCart, metafieldIdentifiers);
1048
- 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" : profile?.memberType
1117
+ });
1049
1118
  useRequest(
1050
1119
  () => {
1051
- const newAttributes = [...attributes, ...customAttributes];
1052
- 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(
1053
1128
  cart.customAttributes,
1054
1129
  newAttributes,
1055
- customAttributesNeedDelete
1130
+ customAttributesNeedRemove
1056
1131
  );
1057
1132
  if (needUpdate) {
1058
1133
  return updateAttributes({ attributes: newAttributes });
@@ -1065,44 +1140,39 @@ function CartProvider({
1065
1140
  // 1 秒内只触发最后一次更新
1066
1141
  throttleTrailing: true,
1067
1142
  throttleLeading: false,
1068
- refreshDeps: [attributes, customAttributes]
1143
+ refreshDeps: [commonAttributes, customAttributes, customAttributesNeedRemove]
1069
1144
  }
1070
1145
  );
1071
1146
  useUpdateLineCodeAmountAttributes({
1072
1147
  cart,
1073
1148
  mutateCart,
1074
1149
  isCartLoading: isCartLoading || isCodeChanging,
1075
- setLoadingState
1150
+ setLoadingState,
1151
+ metafieldIdentifiers
1076
1152
  });
1077
1153
  const removeCustomAttributes = useCallback(
1078
- (attributes2) => {
1079
- setCustomAttributesNeedDelete(attributes2);
1154
+ (attributes) => {
1155
+ setCustomAttributesNeedRemove(attributes);
1080
1156
  },
1081
- [setCustomAttributesNeedDelete]
1157
+ [setCustomAttributesNeedRemove]
1082
1158
  );
1083
1159
  const addCustomAttributes = useCallback(
1084
- (attributes2) => {
1085
- const sameAttributes = attributes2.filter(
1086
- (attr) => customAttributes.some((a) => a.key === attr.key)
1087
- );
1088
- if (sameAttributes.length) {
1089
- setCustomAttributes((prev) => {
1090
- const removedAttributes = prev.filter(
1091
- (attr) => !sameAttributes.some((a) => a.key === attr.key)
1092
- );
1093
- return [...removedAttributes, ...attributes2];
1094
- });
1095
- } else {
1096
- setCustomAttributes((prev) => [...prev, ...attributes2]);
1097
- }
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
+ });
1098
1167
  },
1099
- [customAttributes]
1168
+ [setCustomAttributes]
1100
1169
  );
1101
1170
  const functionAutoFreeGiftResult = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer);
1102
1171
  const scriptAutoFreeGiftResult = useScriptAutoFreeGift({
1103
1172
  campaign: gradientGiftsConfig || null,
1104
1173
  _giveaway: CUSTOMER_SCRIPT_GIFT_KEY,
1105
- cart
1174
+ cart,
1175
+ profile
1106
1176
  });
1107
1177
  const formattedScriptGifts = useMemo(() => {
1108
1178
  return formatScriptAutoFreeGift({
@@ -1153,16 +1223,23 @@ function CartProvider({
1153
1223
  );
1154
1224
  return result;
1155
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]);
1156
1231
  const value = useMemo(
1157
1232
  () => ({
1233
+ totalQuantity,
1158
1234
  cart,
1159
1235
  isCartLoading,
1160
1236
  triggerFetch: fetchCart,
1161
1237
  mutateCart,
1162
1238
  addCustomAttributes,
1163
1239
  removeCustomAttributes,
1164
- setCustomAttributes,
1165
1240
  locale,
1241
+ profile,
1242
+ customer,
1166
1243
  isCodeChanging,
1167
1244
  setIsCodeChanging,
1168
1245
  autoFreeGiftConfig,
@@ -1178,10 +1255,12 @@ function CartProvider({
1178
1255
  scriptAutoFreeGiftResult,
1179
1256
  setScriptAutoFreeGift,
1180
1257
  giftNeedAddToCartLines,
1181
- metafieldIdentifiers
1258
+ metafieldIdentifiers,
1259
+ memberSetting
1182
1260
  }),
1183
1261
  [
1184
1262
  cart,
1263
+ totalQuantity,
1185
1264
  isCartLoading,
1186
1265
  fetchCart,
1187
1266
  mutateCart,
@@ -1201,14 +1280,17 @@ function CartProvider({
1201
1280
  scriptAutoFreeGiftResult,
1202
1281
  setScriptAutoFreeGift,
1203
1282
  giftNeedAddToCartLines,
1204
- metafieldIdentifiers
1283
+ metafieldIdentifiers,
1284
+ customer,
1285
+ profile,
1286
+ memberSetting
1205
1287
  ]
1206
1288
  );
1207
1289
  return /* @__PURE__ */ jsx(CartContext.Provider, { value, children });
1208
1290
  }
1209
- function useCartContext() {
1291
+ function useCartContext(options) {
1210
1292
  const context = useContext(CartContext);
1211
- if (!context) {
1293
+ if (!context && !options?.optional) {
1212
1294
  throw new Error("useCartContext must be used within a CartProvider");
1213
1295
  }
1214
1296
  return context;