@anker-in/shopify-react 0.1.1-beta.3 → 0.1.1-beta.30

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,11 +1,10 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
- import { ShopifyClient, ShopifyConfig, CartCookieAdapter as CartCookieAdapter$1, NormalizedCart, HasMetafieldsIdentifier } from '@anker-in/shopify-sdk';
4
- import { C as CookieAdapter, b as CartCookieAdapter, R as RouterAdapter, U as UserContextAdapter } from '../types-BLMoxbOk.mjs';
3
+ import { ShopifyClient, ShopifyConfig, CartCookieAdapter, NormalizedCart, AttributeInput, HasMetafieldsIdentifier } from '@anker-in/shopify-sdk';
4
+ import { C as CookieAdapter, R as RouterAdapter, U as UserContextAdapter } from '../types-Dt0DUG00.mjs';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
  import { SWRConfiguration } from 'swr';
7
- import { e as PlusMemberSettingsMetafields } from '../types-CICUnw0v.mjs';
8
- import 'swr/mutation';
7
+ import { e as PlusMemberSettingsMetafields } from '../types-BSsb8OPm.mjs';
9
8
 
10
9
  interface ShopifyContextValue {
11
10
  client: ShopifyClient;
@@ -24,7 +23,7 @@ interface ShopifyProviderProps {
24
23
  locale: string;
25
24
  locales?: string[];
26
25
  cookieAdapter?: CookieAdapter;
27
- cartCookieAdapter?: CartCookieAdapter$1;
26
+ cartCookieAdapter?: CartCookieAdapter;
28
27
  routerAdapter?: RouterAdapter;
29
28
  userAdapter?: UserContextAdapter;
30
29
  children: React__default.ReactNode;
@@ -41,10 +40,6 @@ declare function ShopifyProvider({ config, locale, locales, cookieAdapter, cartC
41
40
  */
42
41
  declare function useShopify(): ShopifyContextValue;
43
42
 
44
- type AttributeInput = {
45
- key: string;
46
- value: string;
47
- };
48
43
  type LoadingState = {
49
44
  editLineQuantityLoading: boolean;
50
45
  editLineCodeAmountLoading: boolean;
@@ -54,6 +49,8 @@ type LoadingState = {
54
49
  interface CartContextValue {
55
50
  /** Current cart data */
56
51
  cart: NormalizedCart | undefined;
52
+ /** Total quantity of items in cart */
53
+ totalQuantity: number;
57
54
  /** Whether cart is loading */
58
55
  isCartLoading: boolean;
59
56
  /** Manually trigger cart fetch */
@@ -161,4 +158,4 @@ declare function CartProvider({ children, autoFreeGiftConfig, gradientGiftsConfi
161
158
  */
162
159
  declare function useCartContext(): CartContextValue;
163
160
 
164
- export { type AttributeInput, type CartContextValue, CartProvider, type CartProviderProps, type LoadingState, ShopifyContext, type ShopifyContextValue, ShopifyProvider, type ShopifyProviderProps, useCartContext, useShopify };
161
+ export { type CartContextValue, CartProvider, type CartProviderProps, type LoadingState, ShopifyContext, type ShopifyContextValue, ShopifyProvider, type ShopifyProviderProps, useCartContext, useShopify };
@@ -1,11 +1,10 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
- import { ShopifyClient, ShopifyConfig, CartCookieAdapter as CartCookieAdapter$1, NormalizedCart, HasMetafieldsIdentifier } from '@anker-in/shopify-sdk';
4
- import { C as CookieAdapter, b as CartCookieAdapter, R as RouterAdapter, U as UserContextAdapter } from '../types-BLMoxbOk.js';
3
+ import { ShopifyClient, ShopifyConfig, CartCookieAdapter, NormalizedCart, AttributeInput, HasMetafieldsIdentifier } from '@anker-in/shopify-sdk';
4
+ import { C as CookieAdapter, R as RouterAdapter, U as UserContextAdapter } from '../types-Dt0DUG00.js';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
  import { SWRConfiguration } from 'swr';
7
- import { e as PlusMemberSettingsMetafields } from '../types-CICUnw0v.js';
8
- import 'swr/mutation';
7
+ import { e as PlusMemberSettingsMetafields } from '../types-BSsb8OPm.js';
9
8
 
10
9
  interface ShopifyContextValue {
11
10
  client: ShopifyClient;
@@ -24,7 +23,7 @@ interface ShopifyProviderProps {
24
23
  locale: string;
25
24
  locales?: string[];
26
25
  cookieAdapter?: CookieAdapter;
27
- cartCookieAdapter?: CartCookieAdapter$1;
26
+ cartCookieAdapter?: CartCookieAdapter;
28
27
  routerAdapter?: RouterAdapter;
29
28
  userAdapter?: UserContextAdapter;
30
29
  children: React__default.ReactNode;
@@ -41,10 +40,6 @@ declare function ShopifyProvider({ config, locale, locales, cookieAdapter, cartC
41
40
  */
42
41
  declare function useShopify(): ShopifyContextValue;
43
42
 
44
- type AttributeInput = {
45
- key: string;
46
- value: string;
47
- };
48
43
  type LoadingState = {
49
44
  editLineQuantityLoading: boolean;
50
45
  editLineCodeAmountLoading: boolean;
@@ -54,6 +49,8 @@ type LoadingState = {
54
49
  interface CartContextValue {
55
50
  /** Current cart data */
56
51
  cart: NormalizedCart | undefined;
52
+ /** Total quantity of items in cart */
53
+ totalQuantity: number;
57
54
  /** Whether cart is loading */
58
55
  isCartLoading: boolean;
59
56
  /** Manually trigger cart fetch */
@@ -161,4 +158,4 @@ declare function CartProvider({ children, autoFreeGiftConfig, gradientGiftsConfi
161
158
  */
162
159
  declare function useCartContext(): CartContextValue;
163
160
 
164
- export { type AttributeInput, type CartContextValue, CartProvider, type CartProviderProps, type LoadingState, ShopifyContext, type ShopifyContextValue, ShopifyProvider, type ShopifyProviderProps, useCartContext, useShopify };
161
+ export { type CartContextValue, CartProvider, type CartProviderProps, type LoadingState, ShopifyContext, type ShopifyContextValue, ShopifyProvider, type ShopifyProviderProps, useCartContext, useShopify };
@@ -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');
@@ -110,9 +111,10 @@ function normalizeAddToCartLines(lines) {
110
111
  const variant = line.variant;
111
112
  const product = variant.product;
112
113
  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;
114
+ const originalPrice = variant.price?.amount ? Number(variant.price.amount) : 0;
115
+ const finalPrice = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : originalPrice;
116
+ const subtotalAmount = originalPrice * quantity;
117
+ const totalAmount = finalPrice * quantity;
116
118
  return {
117
119
  id: `temp-line-${index}-${variant.id}`,
118
120
  // Temporary ID for pre-cart lines
@@ -126,7 +128,7 @@ function normalizeAddToCartLines(lines) {
126
128
  customAttributes: line.attributes || [],
127
129
  variant: {
128
130
  id: variant.id,
129
- price,
131
+ price: finalPrice,
130
132
  listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
131
133
  sku: variant.sku || "",
132
134
  name: variant.title || "",
@@ -157,15 +159,16 @@ function createMockCartFromLines(lines, existingCart) {
157
159
  const normalizedLines = normalizeAddToCartLines(lines);
158
160
  const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
159
161
  const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
162
+ const currency = lines[0]?.variant?.price?.currencyCode;
160
163
  return {
161
164
  id: existingCart?.id || "temp-cart-id",
162
165
  customerId: existingCart?.customerId,
163
166
  email: existingCart?.email,
164
167
  createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
165
- currency: existingCart?.currency || { code: "USD" },
168
+ currency: existingCart?.currency || { code: currency },
166
169
  taxesIncluded: existingCart?.taxesIncluded,
167
170
  lineItems: normalizedLines,
168
- totallineItemsDiscount: 0,
171
+ totalLineItemsDiscount: 0,
169
172
  orderDiscounts: 0,
170
173
  lineItemsSubtotalPrice: subtotalPrice,
171
174
  subtotalPrice,
@@ -196,22 +199,12 @@ var getQuery = () => {
196
199
  }
197
200
  return theRequest;
198
201
  };
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
202
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
210
203
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
211
204
  const matchedList = cartData?.lineItems?.filter((line) => {
212
205
  const { is_gift } = getDiscountEnvAttributeValue(line.customAttributes);
213
206
  return isAllStoreVariant ? !is_gift : variant_list?.find((item) => {
214
- return !is_gift && atobID(line.variantId) === item;
207
+ return !is_gift && shopifyCore.atobID(line.variantId) === item;
215
208
  });
216
209
  });
217
210
  return matchedList?.reduce((acc, line) => {
@@ -412,6 +405,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
412
405
  const effectiveCart = react.useMemo(() => {
413
406
  return cart;
414
407
  }, [lines, cart]);
408
+ console.log("effectiveCart useCalcAutoFreeGift", effectiveCart);
415
409
  const { activeCampaign, subtotal } = react.useMemo(() => {
416
410
  for (const campaign of autoFreeGiftConfig) {
417
411
  const { rule_conditions = [], rule_result } = campaign;
@@ -427,6 +421,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
427
421
  all_store_variant: spend_get_reward.main_product?.all_store_variant || false
428
422
  }
429
423
  );
424
+ console.log("matchedSubtotal useCalcAutoFreeGift", matchedSubtotal);
430
425
  if (matchedSubtotal > 0) {
431
426
  return { activeCampaign: campaign, subtotal: matchedSubtotal };
432
427
  }
@@ -439,11 +434,20 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
439
434
  return { qualifyingGift: null, nextTierGoal: null };
440
435
  }
441
436
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
442
- const qualifyingTier = [...giftTiers].reverse().find((tier) => subtotal >= Number(tier.spend_sum_money));
443
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
437
+ const currentCurrency = effectiveCart?.currency?.code || "";
438
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency);
439
+ const getThresholdAmount = (tier) => {
440
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency]?.value) {
441
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency].value);
442
+ }
443
+ return Number(tier.spend_sum_money || 0);
444
+ };
445
+ const qualifyingTier = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
446
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
444
447
  if (!qualifyingTier) {
445
448
  return { qualifyingGift: null, nextTierGoal: nextGoal || null };
446
449
  }
450
+ const actualThreshold = getThresholdAmount(qualifyingTier);
447
451
  const formattedGift = {
448
452
  tier: qualifyingTier,
449
453
  itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
@@ -451,7 +455,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
451
455
  if (!giftProduct) return null;
452
456
  return {
453
457
  variant: {
454
- id: btoaID(giftProduct.variant_id),
458
+ id: shopifyCore.btoaID(giftProduct.variant_id),
455
459
  handle: giftProduct.handle,
456
460
  sku: giftProduct.sku
457
461
  },
@@ -462,7 +466,10 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
462
466
  value: JSON.stringify({
463
467
  is_gift: true,
464
468
  rule_id: activeCampaign.rule_id,
465
- spend_sum_money: qualifyingTier.spend_sum_money
469
+ spend_sum_money: actualThreshold,
470
+ // 使用实际的门槛金额(多币种支持)
471
+ currency_code: currentCurrency
472
+ // 记录当前币种
466
473
  })
467
474
  }
468
475
  ]
@@ -470,7 +477,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
470
477
  }).filter((item) => item !== null)
471
478
  };
472
479
  return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
473
- }, [activeCampaign, subtotal]);
480
+ }, [activeCampaign, subtotal, effectiveCart]);
474
481
  const giftHandles = react.useMemo(() => {
475
482
  const giftVariant = autoFreeGiftConfig.map(
476
483
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -486,18 +493,24 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
486
493
  }
487
494
  return true;
488
495
  }, [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
- });
496
+ const { data: giftProductsResult } = useSWR__default.default(
497
+ shouldFetch ? giftHandles : null,
498
+ async () => {
499
+ const res = await shopifySdk.getProductsByHandles(client, {
500
+ handles: giftHandles,
501
+ locale
502
+ });
503
+ const result = Array.isArray(res) ? res : [];
504
+ giftProductsCache.current = {
505
+ data: result,
506
+ giftHandles: [...giftHandles]
507
+ };
508
+ return result;
509
+ },
510
+ {
511
+ revalidateOnFocus: false
512
+ }
513
+ );
501
514
  const finalGiftProductsResult = react.useMemo(() => {
502
515
  if (giftProductsCache.current && !shouldFetch) {
503
516
  return giftProductsCache.current.data || void 0;
@@ -550,12 +563,14 @@ var useScriptAutoFreeGift = ({
550
563
  upgrade_multiple2 = 1.2;
551
564
  upgrade_value2 = 40;
552
565
  }
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
- });
566
+ effectiveCart?.lineItems?.forEach(
567
+ ({ customAttributes }) => {
568
+ customAttributes?.forEach(({ key, value }) => {
569
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
570
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
571
+ });
572
+ }
573
+ );
559
574
  return [upgrade_multiple2, upgrade_value2];
560
575
  }, [effectiveCart?.lineItems, points_subscribe]);
561
576
  const breakpoints = react.useMemo(() => {
@@ -620,18 +635,24 @@ var useScriptAutoFreeGift = ({
620
635
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
621
636
  return [currentLevel, nextLevel];
622
637
  }, [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
- });
638
+ const { data: giftProductsResult } = useSWR__default.default(
639
+ shouldFetch ? giftHandles : null,
640
+ async () => {
641
+ const res = await shopifySdk.getProductsByHandles(client, {
642
+ handles: giftHandles,
643
+ locale
644
+ });
645
+ const result = Array.isArray(res) ? res : [];
646
+ giftProductsCache.current = {
647
+ data: result,
648
+ giftHandles: [...giftHandles]
649
+ };
650
+ return result;
651
+ },
652
+ {
653
+ revalidateOnFocus: false
654
+ }
655
+ );
635
656
  const finalGiftProductsResult = react.useMemo(() => {
636
657
  if (giftProductsCache.current && !shouldFetch) {
637
658
  return giftProductsCache.current.data || void 0;
@@ -713,12 +734,10 @@ function useHasPlusMemberInCart({
713
734
  };
714
735
  }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
715
736
  }
716
-
717
- // src/hooks/cart/feature/use-cart-attributes.ts
718
737
  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");
738
+ const inviteCode = shopifySdk.getLocalStorage("invite_code") || Cookies5__default.default.get("invite_code");
739
+ const playModeId = shopifySdk.getLocalStorage("playModeId") || Cookies5__default.default.get("playModeId");
740
+ const popup = shopifySdk.getLocalStorage("_popup") || Cookies5__default.default.get("_popup");
722
741
  if (inviteCode && playModeId) {
723
742
  return popup ? [
724
743
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -742,8 +761,6 @@ var useCartAttributes = ({
742
761
  memberSetting,
743
762
  cart
744
763
  });
745
- console.log("memberSetting", memberSetting);
746
- console.log("hasPlusMember", hasPlusMember);
747
764
  react.useEffect(() => {
748
765
  setCurrentUrl(window.location.href);
749
766
  }, []);
@@ -769,7 +786,7 @@ var useCartAttributes = ({
769
786
  return "new_user_login";
770
787
  }, [customer]);
771
788
  const memberAttributes = react.useMemo(() => {
772
- return [
789
+ const attributes = [
773
790
  {
774
791
  key: "_token",
775
792
  value: profile?.token
@@ -790,17 +807,28 @@ var useCartAttributes = ({
790
807
  value: profile?.token ? "true" : "false"
791
808
  }
792
809
  ];
810
+ if (profile?.token) {
811
+ attributes.push({
812
+ key: "_login_user",
813
+ value: "1"
814
+ });
815
+ }
816
+ return attributes;
793
817
  }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
794
818
  const functionAttributes = react.useMemo(() => {
795
- return [
796
- cart?.discountCodes && {
819
+ const hasFunctionEnvAttribute = cart?.lineItems.some(
820
+ (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
821
+ );
822
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
823
+ return hasFunctionEnvAttribute ? [
824
+ {
797
825
  key: "_discounts_function_env",
798
826
  value: JSON.stringify({
799
- discount_code: cart?.discountCodes.map((item) => item.code),
827
+ discount_code: discountCodes,
800
828
  user_tags: customer?.tags || []
801
829
  })
802
830
  }
803
- ];
831
+ ] : [];
804
832
  }, [cart]);
805
833
  const presellAttributes = react.useMemo(() => {
806
834
  return [
@@ -832,18 +860,50 @@ var useCartAttributes = ({
832
860
  }
833
861
  ];
834
862
  }, [currentUrl]);
863
+ const commonAttributes = react.useMemo(
864
+ () => [
865
+ ...memberAttributes,
866
+ ...functionAttributes,
867
+ ...presellAttributes,
868
+ ...weightAttributes,
869
+ ...trackingAttributes,
870
+ ...getReferralAttributes()
871
+ ].filter((item) => item?.value),
872
+ [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
873
+ );
874
+ const extraAttributesInCart = react.useMemo(() => {
875
+ const commonAttributeKeys = [
876
+ // member attributes
877
+ "_token",
878
+ "_member_type",
879
+ "_user_type",
880
+ "_is_login",
881
+ "_login_user",
882
+ // function attributes
883
+ "_discounts_function_env",
884
+ // presell attributes
885
+ "_presale",
886
+ // weight attributes
887
+ "_weight",
888
+ "_app_source_name",
889
+ // tracking attributes
890
+ "utm_params",
891
+ // referral attributes
892
+ "_invite_code",
893
+ "_play_mode_id",
894
+ "_popup"
895
+ ];
896
+ return cart?.customAttributes?.filter(
897
+ (item) => !commonAttributeKeys.includes(item.key)
898
+ ) || [];
899
+ }, [cart]);
835
900
  return react.useMemo(
836
901
  () => ({
837
- attributes: [
838
- ...memberAttributes,
839
- ...functionAttributes,
840
- ...presellAttributes,
841
- ...weightAttributes,
842
- ...trackingAttributes,
843
- ...getReferralAttributes()
844
- ].filter((item) => item?.value)
902
+ attributes: [...commonAttributes, ...extraAttributesInCart].filter(
903
+ (item) => item?.value
904
+ )
845
905
  }),
846
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
906
+ [commonAttributes, extraAttributesInCart]
847
907
  );
848
908
  };
849
909
  var useUpdateLineCodeAmountAttributes = ({
@@ -872,7 +932,7 @@ var useUpdateLineCodeAmountAttributes = ({
872
932
  );
873
933
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
874
934
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
875
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
935
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
876
936
  attrNeedUpdate.push({
877
937
  key: CUSTOMER_ATTRIBUTE_KEY,
878
938
  value: JSON.stringify({
@@ -911,29 +971,22 @@ var useUpdateLineCodeAmountAttributes = ({
911
971
  }).filter(
912
972
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
913
973
  ).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
974
+ let lineId = line.id;
975
+ let attributes = line.customAttributes || [];
976
+ if (attrNeedDelete.length) {
977
+ attributes = attributes.filter(
978
+ (attr) => !attrNeedDelete.includes(attr.key)
979
+ );
980
+ }
914
981
  if (attrNeedUpdate.length) {
915
- return {
916
- id: line.id,
917
- attributes: [
918
- ...line.customAttributes?.filter(
919
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
920
- ) || [],
921
- ...attrNeedUpdate
922
- ]
923
- };
924
- } else if (attrNeedDelete.length) {
925
- return {
926
- id: line.id,
927
- attributes: line.customAttributes?.filter(
928
- (attr) => !attrNeedDelete.includes(attr.key)
929
- ) || []
930
- };
931
- } else {
932
- return {
933
- id: line.id,
934
- attributes: line.customAttributes || []
935
- };
982
+ attributes = attributes.filter(
983
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
984
+ ).concat(attrNeedUpdate);
936
985
  }
986
+ return {
987
+ id: lineId,
988
+ attributes
989
+ };
937
990
  }),
938
991
  [cart?.lineItems, mainProductDiscountCodes]
939
992
  );
@@ -1059,8 +1112,13 @@ function CartProvider({
1059
1112
  const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
1060
1113
  ahooks.useRequest(
1061
1114
  () => {
1062
- const newAttributes = [...attributes, ...customAttributes];
1063
- const needUpdate = cart && !checkAttributesUpdateNeeded(
1115
+ const newAttributes = [...attributes];
1116
+ customAttributes.forEach((item) => {
1117
+ if (item.value && !newAttributes.some((attr) => attr.key === item.key)) {
1118
+ newAttributes.push(item);
1119
+ }
1120
+ });
1121
+ const needUpdate = cart && checkAttributesUpdateNeeded(
1064
1122
  cart.customAttributes,
1065
1123
  newAttributes,
1066
1124
  customAttributesNeedDelete
@@ -1164,8 +1222,14 @@ function CartProvider({
1164
1222
  );
1165
1223
  return result;
1166
1224
  }, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
1225
+ const totalQuantity = react.useMemo(() => {
1226
+ const cartLinesCount = cart?.lineItems.reduce((acc, item) => acc + item.quantity, 0) || 0;
1227
+ const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
1228
+ return cartLinesCount + giftLinesCount;
1229
+ }, [cart?.lineItems, giftNeedAddToCartLines]);
1167
1230
  const value = react.useMemo(
1168
1231
  () => ({
1232
+ totalQuantity,
1169
1233
  cart,
1170
1234
  isCartLoading,
1171
1235
  triggerFetch: fetchCart,
@@ -1193,6 +1257,7 @@ function CartProvider({
1193
1257
  }),
1194
1258
  [
1195
1259
  cart,
1260
+ totalQuantity,
1196
1261
  isCartLoading,
1197
1262
  fetchCart,
1198
1263
  mutateCart,