@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.
@@ -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) => {
@@ -425,43 +421,29 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
425
421
  }
426
422
  return { activeCampaign: null, subtotal: 0 };
427
423
  }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
428
- const { qualifyingGift, nextTierGoal } = useMemo(() => {
424
+ const { qualifyingTier, nextTierGoal, actualThreshold, currentCurrency } = useMemo(() => {
429
425
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
430
- return { qualifyingGift: null, nextTierGoal: null };
426
+ return { qualifyingTier: null, nextTierGoal: null, actualThreshold: 0, currentCurrency: "" };
431
427
  }
432
428
  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)
429
+ const currentCurrency2 = effectiveCart?.currency?.code || "";
430
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency2);
431
+ const getThresholdAmount = (tier) => {
432
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency2]?.value) {
433
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency2].value);
434
+ }
435
+ return Number(tier.spend_sum_money || 0);
462
436
  };
463
- return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
464
- }, [activeCampaign, subtotal]);
437
+ const qualifyingTier2 = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
438
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
439
+ const actualThreshold2 = qualifyingTier2 ? getThresholdAmount(qualifyingTier2) : 0;
440
+ return {
441
+ qualifyingTier: qualifyingTier2,
442
+ nextTierGoal: nextGoal || null,
443
+ actualThreshold: actualThreshold2,
444
+ currentCurrency: currentCurrency2
445
+ };
446
+ }, [activeCampaign, subtotal, effectiveCart]);
465
447
  const giftHandles = useMemo(() => {
466
448
  const giftVariant = autoFreeGiftConfig.map(
467
449
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -477,24 +459,82 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
477
459
  }
478
460
  return true;
479
461
  }, [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
- });
462
+ const { data: giftProductsResult } = useSWR(
463
+ shouldFetch ? giftHandles : null,
464
+ async () => {
465
+ const res = await getProductsByHandles(client, {
466
+ handles: giftHandles,
467
+ locale
468
+ });
469
+ const result = Array.isArray(res) ? res : [];
470
+ giftProductsCache.current = {
471
+ data: result,
472
+ giftHandles: [...giftHandles]
473
+ };
474
+ return result;
475
+ },
476
+ {
477
+ revalidateOnFocus: false
478
+ }
479
+ );
492
480
  const finalGiftProductsResult = useMemo(() => {
493
481
  if (giftProductsCache.current && !shouldFetch) {
494
482
  return giftProductsCache.current.data || void 0;
495
483
  }
496
484
  return giftProductsResult;
497
485
  }, [giftProductsResult, shouldFetch]);
486
+ const qualifyingGift = useMemo(() => {
487
+ if (!qualifyingTier || !activeCampaign) {
488
+ return null;
489
+ }
490
+ const itemsToAdd = qualifyingTier.reward_list?.map((reward) => {
491
+ if (!reward.variant_list || reward.variant_list.length === 0) {
492
+ return null;
493
+ }
494
+ let selectedGiftProduct = null;
495
+ for (const giftVariant of reward.variant_list) {
496
+ const productInfo = finalGiftProductsResult?.find(
497
+ (p) => p.handle === giftVariant.handle
498
+ );
499
+ if (productInfo) {
500
+ const variantInfo = productInfo.variants?.find((v) => v.sku === giftVariant.sku);
501
+ if (variantInfo?.availableForSale) {
502
+ selectedGiftProduct = giftVariant;
503
+ break;
504
+ }
505
+ }
506
+ }
507
+ if (!selectedGiftProduct) {
508
+ selectedGiftProduct = reward.variant_list[0];
509
+ }
510
+ return {
511
+ variant: {
512
+ id: btoaID(selectedGiftProduct.variant_id),
513
+ handle: selectedGiftProduct.handle,
514
+ sku: selectedGiftProduct.sku
515
+ },
516
+ quantity: reward?.get_unit || 1,
517
+ attributes: [
518
+ {
519
+ key: CUSTOMER_ATTRIBUTE_KEY,
520
+ value: JSON.stringify({
521
+ is_gift: true,
522
+ rule_id: activeCampaign.rule_id,
523
+ spend_sum_money: actualThreshold,
524
+ // 使用实际的门槛金额(多币种支持)
525
+ currency_code: currentCurrency
526
+ // 记录当前币种
527
+ })
528
+ }
529
+ ]
530
+ };
531
+ }).filter((item) => item !== null);
532
+ const formattedGift = {
533
+ tier: qualifyingTier,
534
+ itemsToAdd
535
+ };
536
+ return formattedGift;
537
+ }, [qualifyingTier, activeCampaign, finalGiftProductsResult, actualThreshold, currentCurrency]);
498
538
  return {
499
539
  qualifyingGift,
500
540
  nextTierGoal,
@@ -541,12 +581,14 @@ var useScriptAutoFreeGift = ({
541
581
  upgrade_multiple2 = 1.2;
542
582
  upgrade_value2 = 40;
543
583
  }
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
- });
584
+ effectiveCart?.lineItems?.forEach(
585
+ ({ customAttributes }) => {
586
+ customAttributes?.forEach(({ key, value }) => {
587
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
588
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
589
+ });
590
+ }
591
+ );
550
592
  return [upgrade_multiple2, upgrade_value2];
551
593
  }, [effectiveCart?.lineItems, points_subscribe]);
552
594
  const breakpoints = useMemo(() => {
@@ -611,18 +653,24 @@ var useScriptAutoFreeGift = ({
611
653
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
612
654
  return [currentLevel, nextLevel];
613
655
  }, [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
- });
656
+ const { data: giftProductsResult } = useSWR(
657
+ shouldFetch ? giftHandles : null,
658
+ async () => {
659
+ const res = await getProductsByHandles(client, {
660
+ handles: giftHandles,
661
+ locale
662
+ });
663
+ const result = Array.isArray(res) ? res : [];
664
+ giftProductsCache.current = {
665
+ data: result,
666
+ giftHandles: [...giftHandles]
667
+ };
668
+ return result;
669
+ },
670
+ {
671
+ revalidateOnFocus: false
672
+ }
673
+ );
626
674
  const finalGiftProductsResult = useMemo(() => {
627
675
  if (giftProductsCache.current && !shouldFetch) {
628
676
  return giftProductsCache.current.data || void 0;
@@ -669,7 +717,7 @@ function useUpdateCartAttributes(mutate, metafieldIdentifiers, options) {
669
717
  }
670
718
  return updatedCart;
671
719
  },
672
- [client, locale, cartCookieAdapter, mutate]
720
+ [client, locale, cartCookieAdapter, mutate, metafieldIdentifiers]
673
721
  );
674
722
  return useSWRMutation8("update-cart-attributes", updateAttributes, options);
675
723
  }
@@ -704,12 +752,10 @@ function useHasPlusMemberInCart({
704
752
  };
705
753
  }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
706
754
  }
707
-
708
- // src/hooks/cart/feature/use-cart-attributes.ts
709
755
  var getReferralAttributes = () => {
710
- const inviteCode = Cookies5.get("invite_code");
711
- const playModeId = Cookies5.get("playModeId");
712
- const popup = Cookies5.get("_popup");
756
+ const inviteCode = getLocalStorage("inviteCode") || Cookies5.get("inviteCode");
757
+ const playModeId = getLocalStorage("playModeId") || Cookies5.get("playModeId");
758
+ const popup = getLocalStorage("_popup") || Cookies5.get("_popup");
713
759
  if (inviteCode && playModeId) {
714
760
  return popup ? [
715
761
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -733,8 +779,6 @@ var useCartAttributes = ({
733
779
  memberSetting,
734
780
  cart
735
781
  });
736
- console.log("memberSetting", memberSetting);
737
- console.log("hasPlusMember", hasPlusMember);
738
782
  useEffect(() => {
739
783
  setCurrentUrl(window.location.href);
740
784
  }, []);
@@ -760,7 +804,7 @@ var useCartAttributes = ({
760
804
  return "new_user_login";
761
805
  }, [customer]);
762
806
  const memberAttributes = useMemo(() => {
763
- return [
807
+ const attributes = [
764
808
  {
765
809
  key: "_token",
766
810
  value: profile?.token
@@ -781,17 +825,28 @@ var useCartAttributes = ({
781
825
  value: profile?.token ? "true" : "false"
782
826
  }
783
827
  ];
828
+ if (profile?.token) {
829
+ attributes.push({
830
+ key: "_login_user",
831
+ value: "1"
832
+ });
833
+ }
834
+ return attributes;
784
835
  }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
785
836
  const functionAttributes = useMemo(() => {
786
- return [
787
- cart?.discountCodes && {
837
+ const hasFunctionEnvAttribute = cart?.lineItems.some(
838
+ (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
839
+ );
840
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
841
+ return hasFunctionEnvAttribute ? [
842
+ {
788
843
  key: "_discounts_function_env",
789
844
  value: JSON.stringify({
790
- discount_code: cart?.discountCodes.map((item) => item.code),
845
+ discount_code: discountCodes,
791
846
  user_tags: customer?.tags || []
792
847
  })
793
848
  }
794
- ];
849
+ ] : [];
795
850
  }, [cart]);
796
851
  const presellAttributes = useMemo(() => {
797
852
  return [
@@ -823,18 +878,50 @@ var useCartAttributes = ({
823
878
  }
824
879
  ];
825
880
  }, [currentUrl]);
881
+ const commonAttributes = useMemo(
882
+ () => [
883
+ ...memberAttributes,
884
+ ...functionAttributes,
885
+ ...presellAttributes,
886
+ ...weightAttributes,
887
+ ...trackingAttributes,
888
+ ...getReferralAttributes()
889
+ ].filter((item) => item?.value),
890
+ [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
891
+ );
892
+ const extraAttributesInCart = useMemo(() => {
893
+ const commonAttributeKeys = [
894
+ // member attributes
895
+ "_token",
896
+ "_member_type",
897
+ "_user_type",
898
+ "_is_login",
899
+ "_login_user",
900
+ // function attributes
901
+ "_discounts_function_env",
902
+ // presell attributes
903
+ "_presale",
904
+ // weight attributes
905
+ "_weight",
906
+ "_app_source_name",
907
+ // tracking attributes
908
+ "utm_params",
909
+ // referral attributes
910
+ "_invite_code",
911
+ "_play_mode_id",
912
+ "_popup"
913
+ ];
914
+ return cart?.customAttributes?.filter(
915
+ (item) => !commonAttributeKeys.includes(item.key)
916
+ ) || [];
917
+ }, [cart]);
826
918
  return useMemo(
827
919
  () => ({
828
- attributes: [
829
- ...memberAttributes,
830
- ...functionAttributes,
831
- ...presellAttributes,
832
- ...weightAttributes,
833
- ...trackingAttributes,
834
- ...getReferralAttributes()
835
- ].filter((item) => item?.value)
920
+ attributes: [...commonAttributes, ...extraAttributesInCart].filter(
921
+ (item) => item?.value
922
+ )
836
923
  }),
837
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
924
+ [commonAttributes, extraAttributesInCart]
838
925
  );
839
926
  };
840
927
  var useUpdateLineCodeAmountAttributes = ({
@@ -863,7 +950,7 @@ var useUpdateLineCodeAmountAttributes = ({
863
950
  );
864
951
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
865
952
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
866
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
953
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
867
954
  attrNeedUpdate.push({
868
955
  key: CUSTOMER_ATTRIBUTE_KEY,
869
956
  value: JSON.stringify({
@@ -902,29 +989,22 @@ var useUpdateLineCodeAmountAttributes = ({
902
989
  }).filter(
903
990
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
904
991
  ).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
992
+ let lineId = line.id;
993
+ let attributes = line.customAttributes || [];
994
+ if (attrNeedDelete.length) {
995
+ attributes = attributes.filter(
996
+ (attr) => !attrNeedDelete.includes(attr.key)
997
+ );
998
+ }
905
999
  if (attrNeedUpdate.length) {
906
- return {
907
- id: line.id,
908
- attributes: [
909
- ...line.customAttributes?.filter(
910
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
911
- ) || [],
912
- ...attrNeedUpdate
913
- ]
914
- };
915
- } else if (attrNeedDelete.length) {
916
- return {
917
- id: line.id,
918
- attributes: line.customAttributes?.filter(
919
- (attr) => !attrNeedDelete.includes(attr.key)
920
- ) || []
921
- };
922
- } else {
923
- return {
924
- id: line.id,
925
- attributes: line.customAttributes || []
926
- };
1000
+ attributes = attributes.filter(
1001
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
1002
+ ).concat(attrNeedUpdate);
927
1003
  }
1004
+ return {
1005
+ id: lineId,
1006
+ attributes
1007
+ };
928
1008
  }),
929
1009
  [cart?.lineItems, mainProductDiscountCodes]
930
1010
  );
@@ -990,7 +1070,10 @@ var createInitialValue = () => ({
990
1070
  freeShippingMethods: [],
991
1071
  paymentShippingMethods: [],
992
1072
  nddOverweight: false,
993
- tddOverweight: false
1073
+ tddOverweight: false,
1074
+ nddCoupon: void 0,
1075
+ tddCoupon: void 0,
1076
+ isLoadingCoupon: false
994
1077
  },
995
1078
  selectedPlusMemberProduct: null,
996
1079
  plusMemberProducts: [],
@@ -1050,8 +1133,13 @@ function CartProvider({
1050
1133
  const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
1051
1134
  useRequest(
1052
1135
  () => {
1053
- const newAttributes = [...attributes, ...customAttributes];
1054
- const needUpdate = cart && !checkAttributesUpdateNeeded(
1136
+ const newAttributes = [...attributes];
1137
+ customAttributes.forEach((item) => {
1138
+ if (item.value && !newAttributes.some((attr) => attr.key === item.key)) {
1139
+ newAttributes.push(item);
1140
+ }
1141
+ });
1142
+ const needUpdate = cart && checkAttributesUpdateNeeded(
1055
1143
  cart.customAttributes,
1056
1144
  newAttributes,
1057
1145
  customAttributesNeedDelete
@@ -1074,7 +1162,8 @@ function CartProvider({
1074
1162
  cart,
1075
1163
  mutateCart,
1076
1164
  isCartLoading: isCartLoading || isCodeChanging,
1077
- setLoadingState
1165
+ setLoadingState,
1166
+ metafieldIdentifiers
1078
1167
  });
1079
1168
  const removeCustomAttributes = useCallback(
1080
1169
  (attributes2) => {
@@ -1155,8 +1244,14 @@ function CartProvider({
1155
1244
  );
1156
1245
  return result;
1157
1246
  }, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
1247
+ const totalQuantity = useMemo(() => {
1248
+ const cartLinesCount = cart?.lineItems.reduce((acc, item) => acc + item.quantity, 0) || 0;
1249
+ const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
1250
+ return cartLinesCount + giftLinesCount;
1251
+ }, [cart?.lineItems, giftNeedAddToCartLines]);
1158
1252
  const value = useMemo(
1159
1253
  () => ({
1254
+ totalQuantity,
1160
1255
  cart,
1161
1256
  isCartLoading,
1162
1257
  triggerFetch: fetchCart,
@@ -1184,6 +1279,7 @@ function CartProvider({
1184
1279
  }),
1185
1280
  [
1186
1281
  cart,
1282
+ totalQuantity,
1187
1283
  isCartLoading,
1188
1284
  fetchCart,
1189
1285
  mutateCart,
@@ -1208,9 +1304,9 @@ function CartProvider({
1208
1304
  );
1209
1305
  return /* @__PURE__ */ jsx(CartContext.Provider, { value, children });
1210
1306
  }
1211
- function useCartContext() {
1307
+ function useCartContext(options) {
1212
1308
  const context = useContext(CartContext);
1213
- if (!context) {
1309
+ if (!context && !options?.optional) {
1214
1310
  throw new Error("useCartContext must be used within a CartProvider");
1215
1311
  }
1216
1312
  return context;