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

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.
package/dist/index.js CHANGED
@@ -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 useSWRMutation = require('swr/mutation');
10
11
  var ahooks = require('ahooks');
@@ -148,9 +149,10 @@ function normalizeAddToCartLines(lines) {
148
149
  const variant = line.variant;
149
150
  const product = variant.product;
150
151
  const quantity = line.quantity || 1;
151
- const price = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : variant.price?.amount ? Number(variant.price.amount) : 0;
152
- const subtotalAmount = price * quantity;
153
- const totalAmount = subtotalAmount;
152
+ const originalPrice = variant.price?.amount ? Number(variant.price.amount) : 0;
153
+ const finalPrice = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : originalPrice;
154
+ const subtotalAmount = originalPrice * quantity;
155
+ const totalAmount = finalPrice * quantity;
154
156
  return {
155
157
  id: `temp-line-${index}-${variant.id}`,
156
158
  // Temporary ID for pre-cart lines
@@ -164,7 +166,7 @@ function normalizeAddToCartLines(lines) {
164
166
  customAttributes: line.attributes || [],
165
167
  variant: {
166
168
  id: variant.id,
167
- price,
169
+ price: finalPrice,
168
170
  listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
169
171
  sku: variant.sku || "",
170
172
  name: variant.title || "",
@@ -195,15 +197,16 @@ function createMockCartFromLines(lines, existingCart) {
195
197
  const normalizedLines = normalizeAddToCartLines(lines);
196
198
  const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
197
199
  const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
200
+ const currency = lines[0]?.variant?.price?.currencyCode;
198
201
  return {
199
202
  id: existingCart?.id || "temp-cart-id",
200
203
  customerId: existingCart?.customerId,
201
204
  email: existingCart?.email,
202
205
  createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
203
- currency: existingCart?.currency || { code: "USD" },
206
+ currency: existingCart?.currency || { code: currency },
204
207
  taxesIncluded: existingCart?.taxesIncluded,
205
208
  lineItems: normalizedLines,
206
- totallineItemsDiscount: 0,
209
+ totalLineItemsDiscount: 0,
207
210
  orderDiscounts: 0,
208
211
  lineItemsSubtotalPrice: subtotalPrice,
209
212
  subtotalPrice,
@@ -234,22 +237,12 @@ var getQuery = () => {
234
237
  }
235
238
  return theRequest;
236
239
  };
237
- function atobID(id) {
238
- if (id && typeof id === "string" && id.includes("/")) {
239
- return id.split("/").pop()?.split("?")?.shift();
240
- } else {
241
- return id;
242
- }
243
- }
244
- function btoaID(id, type = "ProductVariant") {
245
- return `gid://shopify/${type}/${id}`;
246
- }
247
240
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
248
241
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
249
242
  const matchedList = cartData?.lineItems?.filter((line) => {
250
243
  const { is_gift } = getDiscountEnvAttributeValue(line.customAttributes);
251
244
  return isAllStoreVariant ? !is_gift : variant_list?.find((item) => {
252
- return !is_gift && atobID(line.variantId) === item;
245
+ return !is_gift && shopifyCore.atobID(line.variantId) === item;
253
246
  });
254
247
  });
255
248
  return matchedList?.reduce((acc, line) => {
@@ -453,6 +446,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
453
446
  }
454
447
  return cart;
455
448
  }, [lines, cart]);
449
+ console.log("effectiveCart useCalcAutoFreeGift", effectiveCart);
456
450
  const { activeCampaign, subtotal } = react.useMemo(() => {
457
451
  for (const campaign of autoFreeGiftConfig) {
458
452
  const { rule_conditions = [], rule_result } = campaign;
@@ -468,6 +462,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
468
462
  all_store_variant: spend_get_reward.main_product?.all_store_variant || false
469
463
  }
470
464
  );
465
+ console.log("matchedSubtotal useCalcAutoFreeGift", matchedSubtotal);
471
466
  if (matchedSubtotal > 0) {
472
467
  return { activeCampaign: campaign, subtotal: matchedSubtotal };
473
468
  }
@@ -480,11 +475,20 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
480
475
  return { qualifyingGift: null, nextTierGoal: null };
481
476
  }
482
477
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
483
- const qualifyingTier = [...giftTiers].reverse().find((tier) => subtotal >= Number(tier.spend_sum_money));
484
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
478
+ const currentCurrency = effectiveCart?.currency?.code || "";
479
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency);
480
+ const getThresholdAmount = (tier) => {
481
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency]?.value) {
482
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency].value);
483
+ }
484
+ return Number(tier.spend_sum_money || 0);
485
+ };
486
+ const qualifyingTier = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
487
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
485
488
  if (!qualifyingTier) {
486
489
  return { qualifyingGift: null, nextTierGoal: nextGoal || null };
487
490
  }
491
+ const actualThreshold = getThresholdAmount(qualifyingTier);
488
492
  const formattedGift = {
489
493
  tier: qualifyingTier,
490
494
  itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
@@ -492,7 +496,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
492
496
  if (!giftProduct) return null;
493
497
  return {
494
498
  variant: {
495
- id: btoaID(giftProduct.variant_id),
499
+ id: shopifyCore.btoaID(giftProduct.variant_id),
496
500
  handle: giftProduct.handle,
497
501
  sku: giftProduct.sku
498
502
  },
@@ -503,7 +507,10 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
503
507
  value: JSON.stringify({
504
508
  is_gift: true,
505
509
  rule_id: activeCampaign.rule_id,
506
- spend_sum_money: qualifyingTier.spend_sum_money
510
+ spend_sum_money: actualThreshold,
511
+ // 使用实际的门槛金额(多币种支持)
512
+ currency_code: currentCurrency
513
+ // 记录当前币种
507
514
  })
508
515
  }
509
516
  ]
@@ -511,7 +518,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
511
518
  }).filter((item) => item !== null)
512
519
  };
513
520
  return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
514
- }, [activeCampaign, subtotal]);
521
+ }, [activeCampaign, subtotal, effectiveCart]);
515
522
  const giftHandles = react.useMemo(() => {
516
523
  const giftVariant = autoFreeGiftConfig.map(
517
524
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -527,18 +534,24 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
527
534
  }
528
535
  return true;
529
536
  }, [giftHandles]);
530
- const { data: giftProductsResult } = useSWR__default.default(shouldFetch ? giftHandles : null, async () => {
531
- const res = await shopifySdk.getProductsByHandles(client, {
532
- handles: giftHandles,
533
- locale
534
- });
535
- const result = Array.isArray(res) ? res : [];
536
- giftProductsCache.current = {
537
- data: result,
538
- giftHandles: [...giftHandles]
539
- };
540
- return result;
541
- });
537
+ const { data: giftProductsResult } = useSWR__default.default(
538
+ shouldFetch ? giftHandles : null,
539
+ async () => {
540
+ const res = await shopifySdk.getProductsByHandles(client, {
541
+ handles: giftHandles,
542
+ locale
543
+ });
544
+ const result = Array.isArray(res) ? res : [];
545
+ giftProductsCache.current = {
546
+ data: result,
547
+ giftHandles: [...giftHandles]
548
+ };
549
+ return result;
550
+ },
551
+ {
552
+ revalidateOnFocus: false
553
+ }
554
+ );
542
555
  const finalGiftProductsResult = react.useMemo(() => {
543
556
  if (giftProductsCache.current && !shouldFetch) {
544
557
  return giftProductsCache.current.data || void 0;
@@ -591,12 +604,14 @@ var useScriptAutoFreeGift = ({
591
604
  upgrade_multiple2 = 1.2;
592
605
  upgrade_value2 = 40;
593
606
  }
594
- effectiveCart?.lineItems?.forEach(({ 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
- });
607
+ effectiveCart?.lineItems?.forEach(
608
+ ({ customAttributes }) => {
609
+ customAttributes?.forEach(({ key, value }) => {
610
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
611
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
612
+ });
613
+ }
614
+ );
600
615
  return [upgrade_multiple2, upgrade_value2];
601
616
  }, [effectiveCart?.lineItems, points_subscribe]);
602
617
  const breakpoints = react.useMemo(() => {
@@ -661,18 +676,24 @@ var useScriptAutoFreeGift = ({
661
676
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
662
677
  return [currentLevel, nextLevel];
663
678
  }, [breakpoints, involvedSubTotal, involvedLines.length]);
664
- const { data: giftProductsResult } = useSWR__default.default(shouldFetch ? giftHandles : null, async () => {
665
- const res = await shopifySdk.getProductsByHandles(client, {
666
- handles: giftHandles,
667
- locale
668
- });
669
- const result = Array.isArray(res) ? res : [];
670
- giftProductsCache.current = {
671
- data: result,
672
- giftHandles: [...giftHandles]
673
- };
674
- return result;
675
- });
679
+ const { data: giftProductsResult } = useSWR__default.default(
680
+ shouldFetch ? giftHandles : null,
681
+ async () => {
682
+ const res = await shopifySdk.getProductsByHandles(client, {
683
+ handles: giftHandles,
684
+ locale
685
+ });
686
+ const result = Array.isArray(res) ? res : [];
687
+ giftProductsCache.current = {
688
+ data: result,
689
+ giftHandles: [...giftHandles]
690
+ };
691
+ return result;
692
+ },
693
+ {
694
+ revalidateOnFocus: false
695
+ }
696
+ );
676
697
  const finalGiftProductsResult = react.useMemo(() => {
677
698
  if (giftProductsCache.current && !shouldFetch) {
678
699
  return giftProductsCache.current.data || void 0;
@@ -858,10 +879,10 @@ var trackBuyNowGA = ({
858
879
  return;
859
880
  }
860
881
  const { variant } = lineItems[0];
861
- const currencyCode = variant.price?.currencyCode;
882
+ const currencyCode = variant.product?.price?.currencyCode || variant.price?.currencyCode;
862
883
  const totalPrice = lineItems?.reduce(
863
884
  (prev, { variant: variant2 }) => prev.plus(
864
- variant2?.finalPrice?.amount ?? variant2?.compareAtPrice?.amount ?? (variant2?.price?.amount || 0)
885
+ variant2?.finalPrice?.amount ?? variant2?.compareAtPrice?.amount ?? variant2?.price?.amount ?? 0
865
886
  ),
866
887
  new Decimal2__default.default(0)
867
888
  ).toNumber();
@@ -935,7 +956,7 @@ function useApplyCartCodes(options) {
935
956
  if (!discountCodes?.length) {
936
957
  throw new Error("Invalid input used for this operation: Miss discountCode");
937
958
  }
938
- const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
959
+ const cartId = providedCartId || cart?.id;
939
960
  if (!cartId) {
940
961
  return void 0;
941
962
  }
@@ -948,12 +969,18 @@ function useApplyCartCodes(options) {
948
969
  cookieAdapter: cartCookieAdapter,
949
970
  metafieldIdentifiers
950
971
  });
972
+ const unApplicableCodes = discountCodes.filter(
973
+ (code) => updatedCart?.discountCodes?.find((item) => item.code === code && !item.applicable)
974
+ );
975
+ if (unApplicableCodes.length) {
976
+ throw new Error(`${unApplicableCodes.join(", ")} is not applicable to the cart`);
977
+ }
951
978
  if (updatedCart) {
952
979
  mutateCart(updatedCart);
953
980
  }
954
981
  return updatedCart;
955
982
  },
956
- [client, locale, cartCookieAdapter, mutateCart, cart]
983
+ [client, locale, cartCookieAdapter, mutateCart, cart, metafieldIdentifiers]
957
984
  );
958
985
  return useSWRMutation__default.default("apply-codes", applyCodes, options);
959
986
  }
@@ -963,7 +990,7 @@ function useRemoveCartCodes(options) {
963
990
  const removeCodes = react.useCallback(
964
991
  async (_key, { arg }) => {
965
992
  const { cartId: providedCartId, discountCodes } = arg;
966
- const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
993
+ const cartId = providedCartId || cart?.id;
967
994
  const codes = cart?.discountCodes?.filter((code) => !!code.applicable) || [];
968
995
  const leftCodes = codes.filter((code) => discountCodes?.length ? !discountCodes.includes(code.code) : code.code).map((code) => code.code);
969
996
  const updatedCart = await shopifySdk.updateCartCodes(client, {
@@ -977,15 +1004,70 @@ function useRemoveCartCodes(options) {
977
1004
  }
978
1005
  return updatedCart;
979
1006
  },
980
- [client, locale, cartCookieAdapter, mutateCart, cart]
1007
+ [client, locale, cartCookieAdapter, mutateCart, cart, metafieldIdentifiers]
981
1008
  );
982
1009
  return useSWRMutation__default.default("remove-codes", removeCodes, options);
983
1010
  }
984
1011
 
1012
+ // src/hooks/cart/utils/add-to-cart.ts
1013
+ var getLinesWithAttributes = ({
1014
+ cart,
1015
+ lineItems
1016
+ }) => {
1017
+ return lineItems.map((line) => {
1018
+ const sameLineInCart = cart?.lineItems.find(
1019
+ (lineInCart) => lineInCart.variant.sku === line.variant?.sku && lineInCart.product?.handle === line.variant?.product?.handle
1020
+ );
1021
+ const codeAmountAttribute = sameLineInCart?.customAttributes?.find(
1022
+ (attr) => attr.key === CODE_AMOUNT_KEY
1023
+ );
1024
+ const scriptCodeAmountAttribute = sameLineInCart?.customAttributes?.find(
1025
+ (attr) => attr.key === SCRIPT_CODE_AMOUNT_KEY
1026
+ );
1027
+ let functionAttribute = null;
1028
+ try {
1029
+ functionAttribute = sameLineInCart?.customAttributes?.find(
1030
+ (attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY && JSON.parse(attr.value)?.discounted_amount
1031
+ );
1032
+ } catch (error) {
1033
+ }
1034
+ if (codeAmountAttribute || functionAttribute || scriptCodeAmountAttribute) {
1035
+ return {
1036
+ ...line,
1037
+ attributes: [
1038
+ ...line.attributes || [],
1039
+ codeAmountAttribute,
1040
+ functionAttribute,
1041
+ scriptCodeAmountAttribute
1042
+ ].filter(Boolean)
1043
+ };
1044
+ }
1045
+ return line;
1046
+ });
1047
+ };
1048
+ var getLinesWithFunctionAttributes = (lineItems) => {
1049
+ return lineItems.map((line) => {
1050
+ let itemAttributes = line.attributes || [];
1051
+ const functionEnvAttribute = itemAttributes.find((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY);
1052
+ if (!functionEnvAttribute) {
1053
+ itemAttributes = itemAttributes.concat([
1054
+ {
1055
+ key: CUSTOMER_ATTRIBUTE_KEY,
1056
+ value: JSON.stringify({
1057
+ is_gift: false,
1058
+ discounted_amount: Number(line.variant?.finalPrice?.amount || line.variant?.price?.amount) * (line.quantity || 1)
1059
+ })
1060
+ }
1061
+ ]);
1062
+ }
1063
+ return { ...line, attributes: itemAttributes };
1064
+ });
1065
+ };
1066
+
985
1067
  // src/hooks/cart/use-add-to-cart.ts
986
1068
  function useAddToCart({ withTrack = true } = {}, swrOptions) {
987
1069
  const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
988
- const { cart } = useCartContext();
1070
+ const { cart, addCustomAttributes } = useCartContext();
989
1071
  const { trigger: applyCartCodes } = useApplyCartCodes();
990
1072
  const { trigger: removeInvalidCodes } = useRemoveCartCodes();
991
1073
  const { trigger: addCartLines2 } = useAddCartLines();
@@ -999,12 +1081,18 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
999
1081
  buyerIdentity,
1000
1082
  needCreateCart = false,
1001
1083
  onCodesInvalid,
1002
- replaceExistingCodes
1084
+ replaceExistingCodes,
1085
+ customAttributes
1003
1086
  } = arg;
1004
1087
  if (!lineItems || lineItems.length === 0) {
1005
1088
  return;
1006
1089
  }
1007
- const lines = lineItems.map((item) => ({
1090
+ const linesWithAttributes = getLinesWithAttributes({
1091
+ cart,
1092
+ lineItems
1093
+ });
1094
+ const linesWithFunctionAttributes = getLinesWithFunctionAttributes(linesWithAttributes);
1095
+ const lines = linesWithFunctionAttributes.map((item) => ({
1008
1096
  merchandiseId: item.variant?.id || "",
1009
1097
  quantity: item.quantity || 1,
1010
1098
  attributes: item.attributes,
@@ -1044,6 +1132,9 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
1044
1132
  discountCodes
1045
1133
  });
1046
1134
  }
1135
+ if (customAttributes && customAttributes.length > 0) {
1136
+ addCustomAttributes(customAttributes);
1137
+ }
1047
1138
  if (withTrack) {
1048
1139
  trackAddToCartGA({
1049
1140
  lineItems,
@@ -1070,9 +1161,10 @@ function useUpdateCartLines(options) {
1070
1161
  if (updatedCart) {
1071
1162
  mutateCart(updatedCart);
1072
1163
  }
1164
+ console.log("use-update-cart-lines updatedCart", metafieldIdentifiers, updatedCart);
1073
1165
  return updatedCart;
1074
1166
  },
1075
- [client, locale, cartCookieAdapter, mutateCart]
1167
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
1076
1168
  );
1077
1169
  return useSWRMutation__default.default("update-cart-lines", updateLines, options);
1078
1170
  }
@@ -1111,7 +1203,7 @@ function useRemoveCartLines(options) {
1111
1203
  }
1112
1204
  return updatedCart;
1113
1205
  },
1114
- [client, locale, cartCookieAdapter, mutateCart]
1206
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
1115
1207
  );
1116
1208
  return useSWRMutation__default.default("remove-cart-lines", removeLines, options);
1117
1209
  }
@@ -1130,7 +1222,7 @@ function useUpdateCartAttributes(mutate, metafieldIdentifiers, options) {
1130
1222
  }
1131
1223
  return updatedCart;
1132
1224
  },
1133
- [client, locale, cartCookieAdapter, mutate]
1225
+ [client, locale, cartCookieAdapter, mutate, metafieldIdentifiers]
1134
1226
  );
1135
1227
  return useSWRMutation__default.default("update-cart-attributes", updateAttributes, options);
1136
1228
  }
@@ -1152,7 +1244,8 @@ function useBuyNow({ withTrack = true } = {}, swrOptions) {
1152
1244
  if (!lineItems || lineItems.length === 0) {
1153
1245
  return;
1154
1246
  }
1155
- const lines = lineItems.map((item) => ({
1247
+ const linesWithFunctionAttributes = getLinesWithFunctionAttributes(lineItems);
1248
+ const lines = linesWithFunctionAttributes.map((item) => ({
1156
1249
  merchandiseId: item.variant?.id || "",
1157
1250
  quantity: item.quantity || 1,
1158
1251
  attributes: item.attributes,
@@ -1270,7 +1363,7 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1270
1363
  const isCustomerLoading = react.useMemo(() => !customer ? true : false, [customer]);
1271
1364
  const dealsType = "";
1272
1365
  const { activeCampaign, subtotal } = react.useMemo(() => {
1273
- for (const campaign of orderDiscountConfig) {
1366
+ for (const campaign of orderDiscountConfig || []) {
1274
1367
  const { rule_conditions = [], result_detail } = campaign;
1275
1368
  const { main_product, order_discount_conf } = result_detail || {};
1276
1369
  const isPreCheckPassed = preCheck(rule_conditions, tags, []);
@@ -1300,9 +1393,12 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1300
1393
  discountAmount: 0
1301
1394
  };
1302
1395
  }
1303
- const tieredDiscounts = activeCampaign.result_detail.order_discount_conf.tiered_discounts;
1304
- const qualifyingTier = [...tieredDiscounts].reverse().find((tier) => subtotal >= Number(tier.amount));
1305
- const nextGoal = tieredDiscounts.find((tier) => subtotal < Number(tier.amount));
1396
+ const currentCurrency = cart?.currency?.code || "";
1397
+ console.log("currentCurrency", cart, currentCurrency);
1398
+ const orderDiscountConf = activeCampaign.result_detail.order_discount_conf;
1399
+ const tieredDiscounts = orderDiscountConf.tiered_discounts_markets?.[currentCurrency] || orderDiscountConf.tiered_discounts;
1400
+ const qualifyingTier = [...tieredDiscounts].sort((a, b) => Number(b.amount) - Number(a.amount)).find((tier) => subtotal >= Number(tier.amount));
1401
+ const nextGoal = [...tieredDiscounts].sort((a, b) => Number(a.amount) - Number(b.amount)).find((tier) => subtotal < Number(tier.amount));
1306
1402
  if (!qualifyingTier) {
1307
1403
  return {
1308
1404
  qualifyingDiscount: null,
@@ -1370,12 +1466,10 @@ function useHasPlusMemberInCart({
1370
1466
  };
1371
1467
  }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
1372
1468
  }
1373
-
1374
- // src/hooks/cart/feature/use-cart-attributes.ts
1375
1469
  var getReferralAttributes = () => {
1376
- const inviteCode = Cookies5__default.default.get("invite_code");
1377
- const playModeId = Cookies5__default.default.get("playModeId");
1378
- const popup = Cookies5__default.default.get("_popup");
1470
+ const inviteCode = shopifySdk.getLocalStorage("inviteCode") || Cookies5__default.default.get("inviteCode");
1471
+ const playModeId = shopifySdk.getLocalStorage("playModeId") || Cookies5__default.default.get("playModeId");
1472
+ const popup = shopifySdk.getLocalStorage("_popup") || Cookies5__default.default.get("_popup");
1379
1473
  if (inviteCode && playModeId) {
1380
1474
  return popup ? [
1381
1475
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -1399,8 +1493,6 @@ var useCartAttributes = ({
1399
1493
  memberSetting,
1400
1494
  cart
1401
1495
  });
1402
- console.log("memberSetting", memberSetting);
1403
- console.log("hasPlusMember", hasPlusMember);
1404
1496
  react.useEffect(() => {
1405
1497
  setCurrentUrl(window.location.href);
1406
1498
  }, []);
@@ -1426,7 +1518,7 @@ var useCartAttributes = ({
1426
1518
  return "new_user_login";
1427
1519
  }, [customer]);
1428
1520
  const memberAttributes = react.useMemo(() => {
1429
- return [
1521
+ const attributes = [
1430
1522
  {
1431
1523
  key: "_token",
1432
1524
  value: profile?.token
@@ -1447,17 +1539,28 @@ var useCartAttributes = ({
1447
1539
  value: profile?.token ? "true" : "false"
1448
1540
  }
1449
1541
  ];
1542
+ if (profile?.token) {
1543
+ attributes.push({
1544
+ key: "_login_user",
1545
+ value: "1"
1546
+ });
1547
+ }
1548
+ return attributes;
1450
1549
  }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
1451
1550
  const functionAttributes = react.useMemo(() => {
1452
- return [
1453
- cart?.discountCodes && {
1551
+ const hasFunctionEnvAttribute = cart?.lineItems.some(
1552
+ (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
1553
+ );
1554
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
1555
+ return hasFunctionEnvAttribute ? [
1556
+ {
1454
1557
  key: "_discounts_function_env",
1455
1558
  value: JSON.stringify({
1456
- discount_code: cart?.discountCodes.map((item) => item.code),
1559
+ discount_code: discountCodes,
1457
1560
  user_tags: customer?.tags || []
1458
1561
  })
1459
1562
  }
1460
- ];
1563
+ ] : [];
1461
1564
  }, [cart]);
1462
1565
  const presellAttributes = react.useMemo(() => {
1463
1566
  return [
@@ -1489,18 +1592,50 @@ var useCartAttributes = ({
1489
1592
  }
1490
1593
  ];
1491
1594
  }, [currentUrl]);
1595
+ const commonAttributes = react.useMemo(
1596
+ () => [
1597
+ ...memberAttributes,
1598
+ ...functionAttributes,
1599
+ ...presellAttributes,
1600
+ ...weightAttributes,
1601
+ ...trackingAttributes,
1602
+ ...getReferralAttributes()
1603
+ ].filter((item) => item?.value),
1604
+ [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
1605
+ );
1606
+ const extraAttributesInCart = react.useMemo(() => {
1607
+ const commonAttributeKeys = [
1608
+ // member attributes
1609
+ "_token",
1610
+ "_member_type",
1611
+ "_user_type",
1612
+ "_is_login",
1613
+ "_login_user",
1614
+ // function attributes
1615
+ "_discounts_function_env",
1616
+ // presell attributes
1617
+ "_presale",
1618
+ // weight attributes
1619
+ "_weight",
1620
+ "_app_source_name",
1621
+ // tracking attributes
1622
+ "utm_params",
1623
+ // referral attributes
1624
+ "_invite_code",
1625
+ "_play_mode_id",
1626
+ "_popup"
1627
+ ];
1628
+ return cart?.customAttributes?.filter(
1629
+ (item) => !commonAttributeKeys.includes(item.key)
1630
+ ) || [];
1631
+ }, [cart]);
1492
1632
  return react.useMemo(
1493
1633
  () => ({
1494
- attributes: [
1495
- ...memberAttributes,
1496
- ...functionAttributes,
1497
- ...presellAttributes,
1498
- ...weightAttributes,
1499
- ...trackingAttributes,
1500
- ...getReferralAttributes()
1501
- ].filter((item) => item?.value)
1634
+ attributes: [...commonAttributes, ...extraAttributesInCart].filter(
1635
+ (item) => item?.value
1636
+ )
1502
1637
  }),
1503
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
1638
+ [commonAttributes, extraAttributesInCart]
1504
1639
  );
1505
1640
  };
1506
1641
  var DEFAULT_MIN = 1;
@@ -1563,7 +1698,7 @@ var useUpdateLineCodeAmountAttributes = ({
1563
1698
  );
1564
1699
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
1565
1700
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
1566
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
1701
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
1567
1702
  attrNeedUpdate.push({
1568
1703
  key: CUSTOMER_ATTRIBUTE_KEY,
1569
1704
  value: JSON.stringify({
@@ -1602,29 +1737,22 @@ var useUpdateLineCodeAmountAttributes = ({
1602
1737
  }).filter(
1603
1738
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
1604
1739
  ).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
1740
+ let lineId = line.id;
1741
+ let attributes = line.customAttributes || [];
1742
+ if (attrNeedDelete.length) {
1743
+ attributes = attributes.filter(
1744
+ (attr) => !attrNeedDelete.includes(attr.key)
1745
+ );
1746
+ }
1605
1747
  if (attrNeedUpdate.length) {
1606
- return {
1607
- id: line.id,
1608
- attributes: [
1609
- ...line.customAttributes?.filter(
1610
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
1611
- ) || [],
1612
- ...attrNeedUpdate
1613
- ]
1614
- };
1615
- } else if (attrNeedDelete.length) {
1616
- return {
1617
- id: line.id,
1618
- attributes: line.customAttributes?.filter(
1619
- (attr) => !attrNeedDelete.includes(attr.key)
1620
- ) || []
1621
- };
1622
- } else {
1623
- return {
1624
- id: line.id,
1625
- attributes: line.customAttributes || []
1626
- };
1748
+ attributes = attributes.filter(
1749
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
1750
+ ).concat(attrNeedUpdate);
1627
1751
  }
1752
+ return {
1753
+ id: lineId,
1754
+ attributes
1755
+ };
1628
1756
  }),
1629
1757
  [cart?.lineItems, mainProductDiscountCodes]
1630
1758
  );
@@ -1717,8 +1845,9 @@ function useProductsByHandles(options = {}) {
1717
1845
  metafieldIdentifiers
1718
1846
  });
1719
1847
  },
1720
- swrOptions || {
1721
- revalidateOnFocus: false
1848
+ {
1849
+ revalidateOnFocus: false,
1850
+ ...swrOptions
1722
1851
  }
1723
1852
  );
1724
1853
  }
@@ -2634,6 +2763,73 @@ var usePlusMemberDeliveryCodes = ({
2634
2763
  [deliveryData]
2635
2764
  );
2636
2765
  };
2766
+ function useUpdateCartDeliveryOptions(mutate, metafieldIdentifiers, options) {
2767
+ const { client, locale, cartCookieAdapter } = useShopify();
2768
+ const updateDeliveryOptions = react.useCallback(
2769
+ async (_key, { arg }) => {
2770
+ const updatedCart = await shopifySdk.updateCartDeliveryOptions(client, {
2771
+ ...arg,
2772
+ metafieldIdentifiers,
2773
+ cookieAdapter: cartCookieAdapter
2774
+ });
2775
+ console.log("useUpdateCartDeliveryOptions updatedCart", updatedCart);
2776
+ if (updatedCart) {
2777
+ mutate(updatedCart);
2778
+ }
2779
+ return updatedCart;
2780
+ },
2781
+ [client, locale, cartCookieAdapter, mutate, metafieldIdentifiers]
2782
+ );
2783
+ return useSWRMutation__default.default("update-cart-delivery-options", updateDeliveryOptions, options);
2784
+ }
2785
+
2786
+ // src/hooks/member/plus/use-update-plus-member-delivery-options.ts
2787
+ var useUpdatePlusMemberDeliveryOptions = ({
2788
+ options
2789
+ } = {}) => {
2790
+ const { cart: cartContextData, mutateCart, metafieldIdentifiers } = useCartContext();
2791
+ const { trigger: updateCartDeliveryOptions2 } = useUpdateCartDeliveryOptions(
2792
+ mutateCart,
2793
+ metafieldIdentifiers
2794
+ );
2795
+ const handler = react.useCallback(
2796
+ async (_, { arg }) => {
2797
+ const currentCart = arg?.cart || cartContextData;
2798
+ const { deliveryData } = arg;
2799
+ const firstDeliveryGroup = currentCart?.deliveryGroups?.[0];
2800
+ const deliveryGroupId = firstDeliveryGroup?.id;
2801
+ const selectedOptionCode = deliveryData?.deliveryCustomData?.selected_delivery_option?.code;
2802
+ if (!deliveryGroupId || !selectedOptionCode || selectedOptionCode === firstDeliveryGroup?.selectedDeliveryOption?.code) {
2803
+ return null;
2804
+ }
2805
+ const deliveryGroup = currentCart?.deliveryGroups?.find(
2806
+ (group) => group?.id === deliveryGroupId
2807
+ );
2808
+ const matchedOption = deliveryGroup?.deliveryOptions?.find(
2809
+ (option) => option?.code === selectedOptionCode
2810
+ );
2811
+ if (!matchedOption?.handle) {
2812
+ return null;
2813
+ }
2814
+ const deliveryOptions = [
2815
+ {
2816
+ deliveryGroupId,
2817
+ deliveryOptionHandle: matchedOption.handle
2818
+ }
2819
+ ];
2820
+ const updatedCart = await updateCartDeliveryOptions2({
2821
+ selectedDeliveryOptions: deliveryOptions,
2822
+ cartId: currentCart?.id
2823
+ });
2824
+ if (updatedCart && mutateCart) {
2825
+ mutateCart(updatedCart);
2826
+ }
2827
+ return updatedCart;
2828
+ },
2829
+ [cartContextData, updateCartDeliveryOptions2, mutateCart]
2830
+ );
2831
+ return useSWRMutation__default.default("update-cart-delivery-options", handler, options);
2832
+ };
2637
2833
  var usePlusMemberItemCustomAttributes = ({
2638
2834
  deliveryData
2639
2835
  }) => {
@@ -2653,48 +2849,18 @@ var usePlusMemberCheckoutCustomAttributes = ({
2653
2849
  deliveryData,
2654
2850
  product,
2655
2851
  variant,
2656
- customer,
2657
2852
  isShowShippingBenefits
2658
2853
  }) => {
2659
2854
  const { deliveryCustomData } = deliveryData || {};
2660
2855
  const { profile } = usePlusMemberContext();
2661
- const userType = react.useMemo(() => {
2662
- const customerInfo = customer;
2663
- if (!customerInfo) {
2664
- return "new_user_unlogin";
2665
- }
2666
- if (customer) {
2667
- const { orders = {} } = customer;
2668
- const edgesLength = orders?.edges?.length;
2669
- if (edgesLength === 1) {
2670
- return "old_user_orders_once";
2671
- } else if (edgesLength && edgesLength > 1) {
2672
- return "old_user_orders_twice";
2673
- }
2674
- }
2675
- return "new_user_login";
2676
- }, [customer]);
2677
2856
  return react.useMemo(() => {
2678
2857
  const checkoutCustomAttributes = [
2679
- {
2680
- key: "_token",
2681
- value: profile?.token || ""
2682
- },
2858
+ // _last_url: 付费会员结算完成之后 checkout 有一个继续购买的按钮, 用于跳转到继续购买的页面
2683
2859
  {
2684
2860
  key: "_last_url",
2685
2861
  value: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
2686
- },
2687
- {
2688
- key: "_user_type",
2689
- value: userType
2690
2862
  }
2691
2863
  ];
2692
- if (profile) {
2693
- checkoutCustomAttributes.push({
2694
- key: "_login_user",
2695
- value: "1"
2696
- });
2697
- }
2698
2864
  if (deliveryCustomData) {
2699
2865
  checkoutCustomAttributes.push({
2700
2866
  key: "_checkout_delivery_custom",
@@ -2704,12 +2870,6 @@ var usePlusMemberCheckoutCustomAttributes = ({
2704
2870
  })
2705
2871
  });
2706
2872
  }
2707
- if (variant?.metafields?.presell) {
2708
- checkoutCustomAttributes.push({
2709
- key: "_presale",
2710
- value: "true"
2711
- });
2712
- }
2713
2873
  if (isShowShippingBenefits && !isShowShippingBenefits({ variant, product, setting: {} })) {
2714
2874
  checkoutCustomAttributes.push({
2715
2875
  key: "_hide_shipping",
@@ -2717,18 +2877,17 @@ var usePlusMemberCheckoutCustomAttributes = ({
2717
2877
  });
2718
2878
  }
2719
2879
  return checkoutCustomAttributes;
2720
- }, [deliveryCustomData, product, profile, userType, variant, isShowShippingBenefits]);
2880
+ }, [deliveryCustomData, product, profile, variant, isShowShippingBenefits]);
2721
2881
  };
2722
2882
  function useAutoRemovePlusMemberInCart({
2723
- metafields,
2724
- isMonthlyPlus,
2725
- isAnnualPlus
2883
+ cart,
2884
+ profile,
2885
+ memberSetting
2726
2886
  }) {
2727
- const { plus_monthly_product, plus_annual_product } = metafields || {};
2728
- const { cart } = useCartContext();
2887
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
2729
2888
  const { trigger: removeCartLines2 } = useRemoveCartLines();
2730
2889
  react.useEffect(() => {
2731
- if (!cart) return;
2890
+ if (!cart || !plus_monthly_product || !plus_annual_product) return;
2732
2891
  const removePlusProduct = async (productType) => {
2733
2892
  if (!productType) return;
2734
2893
  const product = cart.lineItems?.find(
@@ -2740,33 +2899,25 @@ function useAutoRemovePlusMemberInCart({
2740
2899
  });
2741
2900
  }
2742
2901
  };
2743
- if (isMonthlyPlus) {
2902
+ if (profile?.isMonthlyPlus) {
2744
2903
  removePlusProduct(plus_monthly_product);
2745
2904
  }
2746
- if (isAnnualPlus) {
2905
+ if (profile?.isAnnualPlus) {
2747
2906
  removePlusProduct(plus_annual_product);
2748
2907
  }
2749
- }, [
2750
- cart,
2751
- plus_annual_product,
2752
- plus_monthly_product,
2753
- isAnnualPlus,
2754
- isMonthlyPlus,
2755
- removeCartLines2
2756
- ]);
2908
+ }, [cart, plus_annual_product, plus_monthly_product, profile, removeCartLines2]);
2757
2909
  }
2758
2910
  function useAddPlusMemberProductsToCart({
2759
2911
  cart,
2760
- memberSetting,
2761
- selectedPlusMemberMode,
2762
- selectedPlusMemberProduct
2912
+ profile
2763
2913
  }) {
2914
+ const { selectedPlusMemberMode, selectedPlusMemberProduct, plusMemberMetafields } = usePlusMemberContext();
2764
2915
  const { hasMonthlyPlus, hasAnnualPlus } = useHasPlusMemberInCart({
2765
- cart,
2766
- memberSetting
2916
+ memberSetting: plusMemberMetafields,
2917
+ cart
2767
2918
  });
2768
2919
  const plusMemberProduct = react.useMemo(() => {
2769
- if (selectedPlusMemberMode === "free" /* FREE */) {
2920
+ if (!selectedPlusMemberProduct || selectedPlusMemberMode === "free" /* FREE */) {
2770
2921
  return void 0;
2771
2922
  }
2772
2923
  if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && hasMonthlyPlus) {
@@ -2775,7 +2926,10 @@ function useAddPlusMemberProductsToCart({
2775
2926
  if (selectedPlusMemberMode === "annual" /* ANNUAL */ && hasAnnualPlus) {
2776
2927
  return void 0;
2777
2928
  }
2778
- if (!selectedPlusMemberProduct) {
2929
+ if (profile?.isMonthlyPlus && selectedPlusMemberMode === "monthly" /* MONTHLY */) {
2930
+ return void 0;
2931
+ }
2932
+ if (profile?.isAnnualPlus && selectedPlusMemberMode === "annual" /* ANNUAL */) {
2779
2933
  return void 0;
2780
2934
  }
2781
2935
  return selectedPlusMemberProduct;
@@ -3094,8 +3248,13 @@ function CartProvider({
3094
3248
  const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
3095
3249
  ahooks.useRequest(
3096
3250
  () => {
3097
- const newAttributes = [...attributes, ...customAttributes];
3098
- const needUpdate = cart && !checkAttributesUpdateNeeded(
3251
+ const newAttributes = [...attributes];
3252
+ customAttributes.forEach((item) => {
3253
+ if (item.value && !newAttributes.some((attr) => attr.key === item.key)) {
3254
+ newAttributes.push(item);
3255
+ }
3256
+ });
3257
+ const needUpdate = cart && checkAttributesUpdateNeeded(
3099
3258
  cart.customAttributes,
3100
3259
  newAttributes,
3101
3260
  customAttributesNeedDelete
@@ -3199,8 +3358,14 @@ function CartProvider({
3199
3358
  );
3200
3359
  return result;
3201
3360
  }, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
3361
+ const totalQuantity = react.useMemo(() => {
3362
+ const cartLinesCount = cart?.lineItems.reduce((acc, item) => acc + item.quantity, 0) || 0;
3363
+ const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
3364
+ return cartLinesCount + giftLinesCount;
3365
+ }, [cart?.lineItems, giftNeedAddToCartLines]);
3202
3366
  const value = react.useMemo(
3203
3367
  () => ({
3368
+ totalQuantity,
3204
3369
  cart,
3205
3370
  isCartLoading,
3206
3371
  triggerFetch: fetchCart,
@@ -3228,6 +3393,7 @@ function CartProvider({
3228
3393
  }),
3229
3394
  [
3230
3395
  cart,
3396
+ totalQuantity,
3231
3397
  isCartLoading,
3232
3398
  fetchCart,
3233
3399
  mutateCart,
@@ -3252,38 +3418,14 @@ function CartProvider({
3252
3418
  );
3253
3419
  return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
3254
3420
  }
3255
- function useCartContext() {
3421
+ function useCartContext(options) {
3256
3422
  const context = react.useContext(CartContext);
3257
- if (!context) {
3423
+ if (!context && !options?.optional) {
3258
3424
  throw new Error("useCartContext must be used within a CartProvider");
3259
3425
  }
3260
3426
  return context;
3261
3427
  }
3262
3428
 
3263
- Object.defineProperty(exports, "ShopifyConfig", {
3264
- enumerable: true,
3265
- get: function () { return shopifySdk.ShopifyConfig; }
3266
- });
3267
- Object.defineProperty(exports, "clearLocalStorage", {
3268
- enumerable: true,
3269
- get: function () { return shopifySdk.clearLocalStorage; }
3270
- });
3271
- Object.defineProperty(exports, "createShopifyClient", {
3272
- enumerable: true,
3273
- get: function () { return shopifySdk.createShopifyClient; }
3274
- });
3275
- Object.defineProperty(exports, "getLocalStorage", {
3276
- enumerable: true,
3277
- get: function () { return shopifySdk.getLocalStorage; }
3278
- });
3279
- Object.defineProperty(exports, "removeLocalStorage", {
3280
- enumerable: true,
3281
- get: function () { return shopifySdk.removeLocalStorage; }
3282
- });
3283
- Object.defineProperty(exports, "setLocalStorage", {
3284
- enumerable: true,
3285
- get: function () { return shopifySdk.setLocalStorage; }
3286
- });
3287
3429
  exports.BuyRuleType = BuyRuleType;
3288
3430
  exports.CODE_AMOUNT_KEY = CODE_AMOUNT_KEY;
3289
3431
  exports.CUSTOMER_ATTRIBUTE_KEY = CUSTOMER_ATTRIBUTE_KEY;
@@ -3305,10 +3447,8 @@ exports.ShippingMethodMode = ShippingMethodMode;
3305
3447
  exports.ShopifyContext = ShopifyContext;
3306
3448
  exports.ShopifyProvider = ShopifyProvider;
3307
3449
  exports.SpendMoneyType = SpendMoneyType;
3308
- exports.atobID = atobID;
3309
3450
  exports.browserCartCookieAdapter = browserCartCookieAdapter;
3310
3451
  exports.browserCookieAdapter = browserCookieAdapter;
3311
- exports.btoaID = btoaID;
3312
3452
  exports.checkAttributesUpdateNeeded = checkAttributesUpdateNeeded;
3313
3453
  exports.clearGeoLocationCache = clearGeoLocationCache;
3314
3454
  exports.createMockCartFromLines = createMockCartFromLines;
@@ -3379,8 +3519,15 @@ exports.useSite = useSite;
3379
3519
  exports.useUpdateCartAttributes = useUpdateCartAttributes;
3380
3520
  exports.useUpdateCartLines = useUpdateCartLines;
3381
3521
  exports.useUpdateLineCodeAmountAttributes = useUpdateLineCodeAmountAttributes;
3522
+ exports.useUpdatePlusMemberDeliveryOptions = useUpdatePlusMemberDeliveryOptions;
3382
3523
  exports.useUpdateVariantQuery = useUpdateVariantQuery;
3383
3524
  exports.useVariant = useVariant;
3384
3525
  exports.useVariantMedia = useVariantMedia;
3526
+ Object.keys(shopifySdk).forEach(function (k) {
3527
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
3528
+ enumerable: true,
3529
+ get: function () { return shopifySdk[k]; }
3530
+ });
3531
+ });
3385
3532
  //# sourceMappingURL=index.js.map
3386
3533
  //# sourceMappingURL=index.js.map