@anker-in/shopify-react 0.1.1-beta.4 → 0.1.1-beta.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,7 @@ var shopifySdk = require('@anker-in/shopify-sdk');
5
5
  var Cookies5 = require('js-cookie');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var Decimal2 = require('decimal.js');
8
+ var shopifyCore = require('@anker-in/shopify-core');
8
9
  var useSWR = require('swr');
9
10
  var useSWRMutation8 = require('swr/mutation');
10
11
  var ahooks = require('ahooks');
@@ -61,7 +62,8 @@ function ShopifyProvider({
61
62
  cartCookieAdapter = browserCartCookieAdapter,
62
63
  routerAdapter,
63
64
  userAdapter,
64
- children
65
+ children,
66
+ performanceAdapter
65
67
  }) {
66
68
  const client = react.useMemo(() => {
67
69
  return shopifySdk.createShopifyClient(config, locale);
@@ -75,7 +77,8 @@ function ShopifyProvider({
75
77
  cookieAdapter,
76
78
  cartCookieAdapter,
77
79
  routerAdapter,
78
- userAdapter
80
+ userAdapter,
81
+ performanceAdapter
79
82
  };
80
83
  }, [
81
84
  client,
@@ -85,6 +88,7 @@ function ShopifyProvider({
85
88
  cookieAdapter,
86
89
  cartCookieAdapter,
87
90
  routerAdapter,
91
+ performanceAdapter,
88
92
  userAdapter
89
93
  ]);
90
94
  return /* @__PURE__ */ jsxRuntime.jsx(ShopifyContext.Provider, { value, children });
@@ -110,9 +114,10 @@ function normalizeAddToCartLines(lines) {
110
114
  const variant = line.variant;
111
115
  const product = variant.product;
112
116
  const quantity = line.quantity || 1;
113
- const price = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : variant.price?.amount ? Number(variant.price.amount) : 0;
114
- const subtotalAmount = price * quantity;
115
- const totalAmount = subtotalAmount;
117
+ const originalPrice = variant.price?.amount ? Number(variant.price.amount) : 0;
118
+ const finalPrice = variant.finalPrice?.amount === void 0 ? originalPrice : Number(variant.finalPrice?.amount);
119
+ const subtotalAmount = originalPrice * quantity;
120
+ const totalAmount = finalPrice * quantity;
116
121
  return {
117
122
  id: `temp-line-${index}-${variant.id}`,
118
123
  // Temporary ID for pre-cart lines
@@ -126,7 +131,7 @@ function normalizeAddToCartLines(lines) {
126
131
  customAttributes: line.attributes || [],
127
132
  variant: {
128
133
  id: variant.id,
129
- price,
134
+ price: finalPrice,
130
135
  listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
131
136
  sku: variant.sku || "",
132
137
  name: variant.title || "",
@@ -157,15 +162,16 @@ function createMockCartFromLines(lines, existingCart) {
157
162
  const normalizedLines = normalizeAddToCartLines(lines);
158
163
  const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
159
164
  const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
165
+ const currency = lines[0]?.variant?.price?.currencyCode;
160
166
  return {
161
167
  id: existingCart?.id || "temp-cart-id",
162
168
  customerId: existingCart?.customerId,
163
169
  email: existingCart?.email,
164
170
  createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
165
- currency: existingCart?.currency || { code: "USD" },
171
+ currency: existingCart?.currency || { code: currency },
166
172
  taxesIncluded: existingCart?.taxesIncluded,
167
173
  lineItems: normalizedLines,
168
- totallineItemsDiscount: 0,
174
+ totalLineItemsDiscount: 0,
169
175
  orderDiscounts: 0,
170
176
  lineItemsSubtotalPrice: subtotalPrice,
171
177
  subtotalPrice,
@@ -196,22 +202,12 @@ var getQuery = () => {
196
202
  }
197
203
  return theRequest;
198
204
  };
199
- function atobID(id) {
200
- if (id && typeof id === "string" && id.includes("/")) {
201
- return id.split("/").pop()?.split("?")?.shift();
202
- } else {
203
- return id;
204
- }
205
- }
206
- function btoaID(id, type = "ProductVariant") {
207
- return `gid://shopify/${type}/${id}`;
208
- }
209
205
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
210
206
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
211
207
  const matchedList = cartData?.lineItems?.filter((line) => {
212
208
  const { is_gift } = getDiscountEnvAttributeValue(line.customAttributes);
213
209
  return isAllStoreVariant ? !is_gift : variant_list?.find((item) => {
214
- return !is_gift && atobID(line.variantId) === item;
210
+ return !is_gift && shopifyCore.atobID(line.variantId) === item;
215
211
  });
216
212
  });
217
213
  return matchedList?.reduce((acc, line) => {
@@ -434,43 +430,29 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
434
430
  }
435
431
  return { activeCampaign: null, subtotal: 0 };
436
432
  }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
437
- const { qualifyingGift, nextTierGoal } = react.useMemo(() => {
433
+ const { qualifyingTier, nextTierGoal, actualThreshold, currentCurrency } = react.useMemo(() => {
438
434
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
439
- return { qualifyingGift: null, nextTierGoal: null };
435
+ return { qualifyingTier: null, nextTierGoal: null, actualThreshold: 0, currentCurrency: "" };
440
436
  }
441
437
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
442
- const qualifyingTier = [...giftTiers].sort((a, b) => Number(b.spend_sum_money) - Number(a.spend_sum_money)).find((tier) => subtotal >= Number(tier.spend_sum_money));
443
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
444
- if (!qualifyingTier) {
445
- return { qualifyingGift: null, nextTierGoal: nextGoal || null };
446
- }
447
- const formattedGift = {
448
- tier: qualifyingTier,
449
- itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
450
- const giftProduct = reward?.variant_list?.[0];
451
- if (!giftProduct) return null;
452
- return {
453
- variant: {
454
- id: btoaID(giftProduct.variant_id),
455
- handle: giftProduct.handle,
456
- sku: giftProduct.sku
457
- },
458
- quantity: reward?.get_unit || 1,
459
- attributes: [
460
- {
461
- key: CUSTOMER_ATTRIBUTE_KEY,
462
- value: JSON.stringify({
463
- is_gift: true,
464
- rule_id: activeCampaign.rule_id,
465
- spend_sum_money: qualifyingTier.spend_sum_money
466
- })
467
- }
468
- ]
469
- };
470
- }).filter((item) => item !== null)
438
+ const currentCurrency2 = effectiveCart?.currency?.code || "";
439
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency2);
440
+ const getThresholdAmount = (tier) => {
441
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency2]?.value) {
442
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency2].value);
443
+ }
444
+ return Number(tier.spend_sum_money || 0);
471
445
  };
472
- return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
473
- }, [activeCampaign, subtotal]);
446
+ const qualifyingTier2 = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
447
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
448
+ const actualThreshold2 = qualifyingTier2 ? getThresholdAmount(qualifyingTier2) : 0;
449
+ return {
450
+ qualifyingTier: qualifyingTier2,
451
+ nextTierGoal: nextGoal || null,
452
+ actualThreshold: actualThreshold2,
453
+ currentCurrency: currentCurrency2
454
+ };
455
+ }, [activeCampaign, subtotal, effectiveCart]);
474
456
  const giftHandles = react.useMemo(() => {
475
457
  const giftVariant = autoFreeGiftConfig.map(
476
458
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -486,24 +468,82 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
486
468
  }
487
469
  return true;
488
470
  }, [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
- });
471
+ const { data: giftProductsResult } = useSWR__default.default(
472
+ shouldFetch ? giftHandles : null,
473
+ async () => {
474
+ const res = await shopifySdk.getProductsByHandles(client, {
475
+ handles: giftHandles,
476
+ locale
477
+ });
478
+ const result = Array.isArray(res) ? res : [];
479
+ giftProductsCache.current = {
480
+ data: result,
481
+ giftHandles: [...giftHandles]
482
+ };
483
+ return result;
484
+ },
485
+ {
486
+ revalidateOnFocus: false
487
+ }
488
+ );
501
489
  const finalGiftProductsResult = react.useMemo(() => {
502
490
  if (giftProductsCache.current && !shouldFetch) {
503
491
  return giftProductsCache.current.data || void 0;
504
492
  }
505
493
  return giftProductsResult;
506
494
  }, [giftProductsResult, shouldFetch]);
495
+ const qualifyingGift = react.useMemo(() => {
496
+ if (!qualifyingTier || !activeCampaign) {
497
+ return null;
498
+ }
499
+ const itemsToAdd = qualifyingTier.reward_list?.map((reward) => {
500
+ if (!reward.variant_list || reward.variant_list.length === 0) {
501
+ return null;
502
+ }
503
+ let selectedGiftProduct = null;
504
+ for (const giftVariant of reward.variant_list) {
505
+ const productInfo = finalGiftProductsResult?.find(
506
+ (p) => p.handle === giftVariant.handle
507
+ );
508
+ if (productInfo) {
509
+ const variantInfo = productInfo.variants?.find((v) => v.sku === giftVariant.sku);
510
+ if (variantInfo?.availableForSale) {
511
+ selectedGiftProduct = giftVariant;
512
+ break;
513
+ }
514
+ }
515
+ }
516
+ if (!selectedGiftProduct) {
517
+ selectedGiftProduct = reward.variant_list[0];
518
+ }
519
+ return {
520
+ variant: {
521
+ id: shopifyCore.btoaID(selectedGiftProduct.variant_id),
522
+ handle: selectedGiftProduct.handle,
523
+ sku: selectedGiftProduct.sku
524
+ },
525
+ quantity: reward?.get_unit || 1,
526
+ attributes: [
527
+ {
528
+ key: CUSTOMER_ATTRIBUTE_KEY,
529
+ value: JSON.stringify({
530
+ is_gift: true,
531
+ rule_id: activeCampaign.rule_id,
532
+ spend_sum_money: actualThreshold,
533
+ // 使用实际的门槛金额(多币种支持)
534
+ currency_code: currentCurrency
535
+ // 记录当前币种
536
+ })
537
+ }
538
+ ]
539
+ };
540
+ }).filter((item) => item !== null);
541
+ const formattedGift = {
542
+ tier: qualifyingTier,
543
+ itemsToAdd
544
+ };
545
+ return formattedGift;
546
+ }, [qualifyingTier, activeCampaign, finalGiftProductsResult, actualThreshold, currentCurrency]);
507
547
  return {
508
548
  qualifyingGift,
509
549
  nextTierGoal,
@@ -550,12 +590,14 @@ var useScriptAutoFreeGift = ({
550
590
  upgrade_multiple2 = 1.2;
551
591
  upgrade_value2 = 40;
552
592
  }
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
- });
593
+ effectiveCart?.lineItems?.forEach(
594
+ ({ customAttributes }) => {
595
+ customAttributes?.forEach(({ key, value }) => {
596
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
597
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
598
+ });
599
+ }
600
+ );
559
601
  return [upgrade_multiple2, upgrade_value2];
560
602
  }, [effectiveCart?.lineItems, points_subscribe]);
561
603
  const breakpoints = react.useMemo(() => {
@@ -620,18 +662,24 @@ var useScriptAutoFreeGift = ({
620
662
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
621
663
  return [currentLevel, nextLevel];
622
664
  }, [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
- });
665
+ const { data: giftProductsResult } = useSWR__default.default(
666
+ shouldFetch ? giftHandles : null,
667
+ async () => {
668
+ const res = await shopifySdk.getProductsByHandles(client, {
669
+ handles: giftHandles,
670
+ locale
671
+ });
672
+ const result = Array.isArray(res) ? res : [];
673
+ giftProductsCache.current = {
674
+ data: result,
675
+ giftHandles: [...giftHandles]
676
+ };
677
+ return result;
678
+ },
679
+ {
680
+ revalidateOnFocus: false
681
+ }
682
+ );
635
683
  const finalGiftProductsResult = react.useMemo(() => {
636
684
  if (giftProductsCache.current && !shouldFetch) {
637
685
  return giftProductsCache.current.data || void 0;
@@ -678,7 +726,7 @@ function useUpdateCartAttributes(mutate, metafieldIdentifiers, options) {
678
726
  }
679
727
  return updatedCart;
680
728
  },
681
- [client, locale, cartCookieAdapter, mutate]
729
+ [client, locale, cartCookieAdapter, mutate, metafieldIdentifiers]
682
730
  );
683
731
  return useSWRMutation8__default.default("update-cart-attributes", updateAttributes, options);
684
732
  }
@@ -713,12 +761,10 @@ function useHasPlusMemberInCart({
713
761
  };
714
762
  }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
715
763
  }
716
-
717
- // src/hooks/cart/feature/use-cart-attributes.ts
718
764
  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");
765
+ const inviteCode = shopifySdk.getLocalStorage("inviteCode") || Cookies5__default.default.get("inviteCode");
766
+ const playModeId = shopifySdk.getLocalStorage("playModeId") || Cookies5__default.default.get("playModeId");
767
+ const popup = shopifySdk.getLocalStorage("_popup") || Cookies5__default.default.get("_popup");
722
768
  if (inviteCode && playModeId) {
723
769
  return popup ? [
724
770
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -742,8 +788,6 @@ var useCartAttributes = ({
742
788
  memberSetting,
743
789
  cart
744
790
  });
745
- console.log("memberSetting", memberSetting);
746
- console.log("hasPlusMember", hasPlusMember);
747
791
  react.useEffect(() => {
748
792
  setCurrentUrl(window.location.href);
749
793
  }, []);
@@ -769,7 +813,7 @@ var useCartAttributes = ({
769
813
  return "new_user_login";
770
814
  }, [customer]);
771
815
  const memberAttributes = react.useMemo(() => {
772
- return [
816
+ const attributes = [
773
817
  {
774
818
  key: "_token",
775
819
  value: profile?.token
@@ -790,17 +834,28 @@ var useCartAttributes = ({
790
834
  value: profile?.token ? "true" : "false"
791
835
  }
792
836
  ];
837
+ if (profile?.token) {
838
+ attributes.push({
839
+ key: "_login_user",
840
+ value: "1"
841
+ });
842
+ }
843
+ return attributes;
793
844
  }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
794
845
  const functionAttributes = react.useMemo(() => {
795
- return [
796
- cart?.discountCodes && {
846
+ const hasFunctionEnvAttribute = cart?.lineItems.some(
847
+ (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
848
+ );
849
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
850
+ return hasFunctionEnvAttribute ? [
851
+ {
797
852
  key: "_discounts_function_env",
798
853
  value: JSON.stringify({
799
- discount_code: cart?.discountCodes.map((item) => item.code),
854
+ discount_code: discountCodes,
800
855
  user_tags: customer?.tags || []
801
856
  })
802
857
  }
803
- ];
858
+ ] : [];
804
859
  }, [cart]);
805
860
  const presellAttributes = react.useMemo(() => {
806
861
  return [
@@ -832,18 +887,50 @@ var useCartAttributes = ({
832
887
  }
833
888
  ];
834
889
  }, [currentUrl]);
890
+ const commonAttributes = react.useMemo(
891
+ () => [
892
+ ...memberAttributes,
893
+ ...functionAttributes,
894
+ ...presellAttributes,
895
+ ...weightAttributes,
896
+ ...trackingAttributes,
897
+ ...getReferralAttributes()
898
+ ].filter((item) => item?.value),
899
+ [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
900
+ );
901
+ const extraAttributesInCart = react.useMemo(() => {
902
+ const commonAttributeKeys = [
903
+ // member attributes
904
+ "_token",
905
+ "_member_type",
906
+ "_user_type",
907
+ "_is_login",
908
+ "_login_user",
909
+ // function attributes
910
+ "_discounts_function_env",
911
+ // presell attributes
912
+ "_presale",
913
+ // weight attributes
914
+ "_weight",
915
+ "_app_source_name",
916
+ // tracking attributes
917
+ "utm_params",
918
+ // referral attributes
919
+ "_invite_code",
920
+ "_play_mode_id",
921
+ "_popup"
922
+ ];
923
+ return cart?.customAttributes?.filter(
924
+ (item) => !commonAttributeKeys.includes(item.key)
925
+ ) || [];
926
+ }, [cart]);
835
927
  return react.useMemo(
836
928
  () => ({
837
- attributes: [
838
- ...memberAttributes,
839
- ...functionAttributes,
840
- ...presellAttributes,
841
- ...weightAttributes,
842
- ...trackingAttributes,
843
- ...getReferralAttributes()
844
- ].filter((item) => item?.value)
929
+ attributes: [...commonAttributes, ...extraAttributesInCart].filter(
930
+ (item) => item?.value
931
+ )
845
932
  }),
846
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
933
+ [commonAttributes, extraAttributesInCart]
847
934
  );
848
935
  };
849
936
  var useUpdateLineCodeAmountAttributes = ({
@@ -872,7 +959,7 @@ var useUpdateLineCodeAmountAttributes = ({
872
959
  );
873
960
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
874
961
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
875
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
962
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
876
963
  attrNeedUpdate.push({
877
964
  key: CUSTOMER_ATTRIBUTE_KEY,
878
965
  value: JSON.stringify({
@@ -911,29 +998,22 @@ var useUpdateLineCodeAmountAttributes = ({
911
998
  }).filter(
912
999
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
913
1000
  ).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
1001
+ let lineId = line.id;
1002
+ let attributes = line.customAttributes || [];
1003
+ if (attrNeedDelete.length) {
1004
+ attributes = attributes.filter(
1005
+ (attr) => !attrNeedDelete.includes(attr.key)
1006
+ );
1007
+ }
914
1008
  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
- };
1009
+ attributes = attributes.filter(
1010
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
1011
+ ).concat(attrNeedUpdate);
936
1012
  }
1013
+ return {
1014
+ id: lineId,
1015
+ attributes
1016
+ };
937
1017
  }),
938
1018
  [cart?.lineItems, mainProductDiscountCodes]
939
1019
  );
@@ -999,7 +1079,10 @@ var createInitialValue = () => ({
999
1079
  freeShippingMethods: [],
1000
1080
  paymentShippingMethods: [],
1001
1081
  nddOverweight: false,
1002
- tddOverweight: false
1082
+ tddOverweight: false,
1083
+ nddCoupon: void 0,
1084
+ tddCoupon: void 0,
1085
+ isLoadingCoupon: false
1003
1086
  },
1004
1087
  selectedPlusMemberProduct: null,
1005
1088
  plusMemberProducts: [],
@@ -1059,8 +1142,13 @@ function CartProvider({
1059
1142
  const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
1060
1143
  ahooks.useRequest(
1061
1144
  () => {
1062
- const newAttributes = [...attributes, ...customAttributes];
1063
- const needUpdate = cart && !checkAttributesUpdateNeeded(
1145
+ const newAttributes = [...attributes];
1146
+ customAttributes.forEach((item) => {
1147
+ if (item.value && !newAttributes.some((attr) => attr.key === item.key)) {
1148
+ newAttributes.push(item);
1149
+ }
1150
+ });
1151
+ const needUpdate = cart && checkAttributesUpdateNeeded(
1064
1152
  cart.customAttributes,
1065
1153
  newAttributes,
1066
1154
  customAttributesNeedDelete
@@ -1083,7 +1171,8 @@ function CartProvider({
1083
1171
  cart,
1084
1172
  mutateCart,
1085
1173
  isCartLoading: isCartLoading || isCodeChanging,
1086
- setLoadingState
1174
+ setLoadingState,
1175
+ metafieldIdentifiers
1087
1176
  });
1088
1177
  const removeCustomAttributes = react.useCallback(
1089
1178
  (attributes2) => {
@@ -1164,8 +1253,14 @@ function CartProvider({
1164
1253
  );
1165
1254
  return result;
1166
1255
  }, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
1256
+ const totalQuantity = react.useMemo(() => {
1257
+ const cartLinesCount = cart?.lineItems.reduce((acc, item) => acc + item.quantity, 0) || 0;
1258
+ const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
1259
+ return cartLinesCount + giftLinesCount;
1260
+ }, [cart?.lineItems, giftNeedAddToCartLines]);
1167
1261
  const value = react.useMemo(
1168
1262
  () => ({
1263
+ totalQuantity,
1169
1264
  cart,
1170
1265
  isCartLoading,
1171
1266
  triggerFetch: fetchCart,
@@ -1193,6 +1288,7 @@ function CartProvider({
1193
1288
  }),
1194
1289
  [
1195
1290
  cart,
1291
+ totalQuantity,
1196
1292
  isCartLoading,
1197
1293
  fetchCart,
1198
1294
  mutateCart,
@@ -1217,9 +1313,9 @@ function CartProvider({
1217
1313
  );
1218
1314
  return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
1219
1315
  }
1220
- function useCartContext() {
1316
+ function useCartContext(options) {
1221
1317
  const context = react.useContext(CartContext);
1222
- if (!context) {
1318
+ if (!context && !options?.optional) {
1223
1319
  throw new Error("useCartContext must be used within a CartProvider");
1224
1320
  }
1225
1321
  return context;