@anker-in/shopify-react 0.1.1-beta.2 → 0.1.1-beta.21

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.
@@ -71,6 +71,83 @@ var CODE_AMOUNT_KEY = "_sku_code_money";
71
71
  var SCRIPT_CODE_AMOUNT_KEY = "_code_money";
72
72
  var MAIN_PRODUCT_CODE = ["WS24", "WSTD", "WS7D", "WSCP", "WSPE", "WSPD"];
73
73
 
74
+ // src/hooks/cart/utils/normalize-add-to-cart-lines.ts
75
+ function normalizeAddToCartLines(lines) {
76
+ return lines.filter((line) => line.variant?.id).map((line, index) => {
77
+ const variant = line.variant;
78
+ const product = variant.product;
79
+ const quantity = line.quantity || 1;
80
+ const price = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : variant.price?.amount ? Number(variant.price.amount) : 0;
81
+ const subtotalAmount = price * quantity;
82
+ const totalAmount = subtotalAmount;
83
+ return {
84
+ id: `temp-line-${index}-${variant.id}`,
85
+ // Temporary ID for pre-cart lines
86
+ name: product?.title || variant.title || "",
87
+ quantity,
88
+ variantId: variant.id,
89
+ productId: product?.id || variant.id.split("/").slice(0, -2).join("/"),
90
+ totalAmount,
91
+ subtotalAmount,
92
+ discountAllocations: [],
93
+ customAttributes: line.attributes || [],
94
+ variant: {
95
+ id: variant.id,
96
+ price,
97
+ listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
98
+ sku: variant.sku || "",
99
+ name: variant.title || "",
100
+ image: variant.image ? {
101
+ url: variant.image.url,
102
+ altText: variant.image.altText || void 0
103
+ } : void 0,
104
+ requiresShipping: false,
105
+ // Default value, not available in NormalizedProductVariant
106
+ availableForSale: variant.availableForSale ?? true,
107
+ quantityAvailable: variant.quantityAvailable ?? 0,
108
+ currentlyNotInStock: false,
109
+ // Default value, will be updated when added to cart
110
+ weight: variant.weight,
111
+ metafields: variant.metafields
112
+ },
113
+ product,
114
+ path: product?.handle ? `/products/${product.handle}` : "",
115
+ discounts: [],
116
+ options: variant.selectedOptions?.map((opt) => ({
117
+ name: opt.name,
118
+ value: opt.value
119
+ }))
120
+ };
121
+ });
122
+ }
123
+ function createMockCartFromLines(lines, existingCart) {
124
+ const normalizedLines = normalizeAddToCartLines(lines);
125
+ const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
126
+ const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
127
+ console.log("lines createMockCartFromLines", lines);
128
+ const currency = lines[0]?.variant?.price?.currencyCode;
129
+ return {
130
+ id: existingCart?.id || "temp-cart-id",
131
+ customerId: existingCart?.customerId,
132
+ email: existingCart?.email,
133
+ createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
134
+ currency: existingCart?.currency?.code || { code: currency },
135
+ taxesIncluded: existingCart?.taxesIncluded,
136
+ lineItems: normalizedLines,
137
+ totalLineItemsDiscount: 0,
138
+ orderDiscounts: 0,
139
+ lineItemsSubtotalPrice: subtotalPrice,
140
+ subtotalPrice,
141
+ totalPrice,
142
+ totalTaxAmount: 0,
143
+ discountCodes: existingCart?.discountCodes || [],
144
+ discountAllocations: [],
145
+ url: existingCart?.url || "",
146
+ ready: true,
147
+ customAttributes: existingCart?.customAttributes
148
+ };
149
+ }
150
+
74
151
  // src/hooks/cart/utils/index.ts
75
152
  var getQuery = () => {
76
153
  const url = typeof window !== "undefined" ? window.location.search : "";
@@ -88,22 +165,12 @@ var getQuery = () => {
88
165
  }
89
166
  return theRequest;
90
167
  };
91
- function atobID(id) {
92
- if (id && typeof id === "string" && id.includes("/")) {
93
- return id.split("/").pop()?.split("?")?.shift();
94
- } else {
95
- return id;
96
- }
97
- }
98
- function btoaID(id, type = "ProductVariant") {
99
- return `gid://shopify/${type}/${id}`;
100
- }
101
168
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
102
169
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
103
170
  const matchedList = cartData?.lineItems?.filter((line) => {
104
171
  const { is_gift } = getDiscountEnvAttributeValue(line.customAttributes);
105
172
  return isAllStoreVariant ? !is_gift : variant_list?.find((item) => {
106
- return !is_gift && atobID(line.variantId) === item;
173
+ return !is_gift && shopifySdk.atobID(line.variantId) === item;
107
174
  });
108
175
  });
109
176
  return matchedList?.reduce((acc, line) => {
@@ -295,12 +362,18 @@ var formatFunctionAutoFreeGift = ({
295
362
  };
296
363
  return result;
297
364
  };
298
- var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
365
+ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
299
366
  const tags = react.useMemo(() => customer?.tags || [], [customer?.tags]);
300
367
  const isCustomerLoading = react.useMemo(() => !customer ? true : false, [customer]);
301
368
  const dealsType = "";
302
369
  const { client, locale } = useShopify();
303
370
  const giftProductsCache = react.useRef(null);
371
+ const effectiveCart = react.useMemo(() => {
372
+ if (lines && lines.length > 0) {
373
+ return createMockCartFromLines(lines, cart);
374
+ }
375
+ return cart;
376
+ }, [lines, cart]);
304
377
  const { activeCampaign, subtotal } = react.useMemo(() => {
305
378
  for (const campaign of autoFreeGiftConfig) {
306
379
  const { rule_conditions = [], rule_result } = campaign;
@@ -308,7 +381,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
308
381
  const isPreCheckPassed = preCheck(rule_conditions, tags, []);
309
382
  if (isPreCheckPassed && spend_get_reward) {
310
383
  const matchedSubtotal = getMatchedMainProductSubTotal(
311
- cart,
384
+ effectiveCart,
312
385
  spend_get_reward.main_product?.variant_list?.map((v) => v.variant_id) || [],
313
386
  {
314
387
  spend_money_type: spend_get_reward.main_product?.spend_money_type || 1,
@@ -322,17 +395,26 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
322
395
  }
323
396
  }
324
397
  return { activeCampaign: null, subtotal: 0 };
325
- }, [autoFreeGiftConfig, cart, tags, dealsType]);
398
+ }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
326
399
  const { qualifyingGift, nextTierGoal } = react.useMemo(() => {
327
400
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
328
401
  return { qualifyingGift: null, nextTierGoal: null };
329
402
  }
330
403
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
331
- const qualifyingTier = [...giftTiers].reverse().find((tier) => subtotal >= Number(tier.spend_sum_money));
332
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
404
+ const currentCurrency = effectiveCart?.currency?.code || "";
405
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency);
406
+ const getThresholdAmount = (tier) => {
407
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency]?.value) {
408
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency].value);
409
+ }
410
+ return Number(tier.spend_sum_money || 0);
411
+ };
412
+ const qualifyingTier = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
413
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
333
414
  if (!qualifyingTier) {
334
415
  return { qualifyingGift: null, nextTierGoal: nextGoal || null };
335
416
  }
417
+ const actualThreshold = getThresholdAmount(qualifyingTier);
336
418
  const formattedGift = {
337
419
  tier: qualifyingTier,
338
420
  itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
@@ -340,7 +422,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
340
422
  if (!giftProduct) return null;
341
423
  return {
342
424
  variant: {
343
- id: btoaID(giftProduct.variant_id),
425
+ id: shopifySdk.btoaID(giftProduct.variant_id),
344
426
  handle: giftProduct.handle,
345
427
  sku: giftProduct.sku
346
428
  },
@@ -351,7 +433,10 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
351
433
  value: JSON.stringify({
352
434
  is_gift: true,
353
435
  rule_id: activeCampaign.rule_id,
354
- spend_sum_money: qualifyingTier.spend_sum_money
436
+ spend_sum_money: actualThreshold,
437
+ // 使用实际的门槛金额(多币种支持)
438
+ currency_code: currentCurrency
439
+ // 记录当前币种
355
440
  })
356
441
  }
357
442
  ]
@@ -359,7 +444,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
359
444
  }).filter((item) => item !== null)
360
445
  };
361
446
  return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
362
- }, [activeCampaign, subtotal]);
447
+ }, [activeCampaign, subtotal, effectiveCart]);
363
448
  const giftHandles = react.useMemo(() => {
364
449
  const giftVariant = autoFreeGiftConfig.map(
365
450
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -375,18 +460,24 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
375
460
  }
376
461
  return true;
377
462
  }, [giftHandles]);
378
- const { data: giftProductsResult } = useSWR__default.default(shouldFetch ? giftHandles : null, async () => {
379
- const res = await shopifySdk.getProductsByHandles(client, {
380
- handles: giftHandles,
381
- locale
382
- });
383
- const result = Array.isArray(res) ? res : [];
384
- giftProductsCache.current = {
385
- data: result,
386
- giftHandles: [...giftHandles]
387
- };
388
- return result;
389
- });
463
+ const { data: giftProductsResult } = useSWR__default.default(
464
+ shouldFetch ? giftHandles : null,
465
+ async () => {
466
+ const res = await shopifySdk.getProductsByHandles(client, {
467
+ handles: giftHandles,
468
+ locale
469
+ });
470
+ const result = Array.isArray(res) ? res : [];
471
+ giftProductsCache.current = {
472
+ data: result,
473
+ giftHandles: [...giftHandles]
474
+ };
475
+ return result;
476
+ },
477
+ {
478
+ revalidateOnFocus: false
479
+ }
480
+ );
390
481
  const finalGiftProductsResult = react.useMemo(() => {
391
482
  if (giftProductsCache.current && !shouldFetch) {
392
483
  return giftProductsCache.current.data || void 0;
@@ -405,12 +496,19 @@ var useScriptAutoFreeGift = ({
405
496
  campaign,
406
497
  _giveaway,
407
498
  cart,
408
- locale: providedLocale
499
+ locale: providedLocale,
500
+ lines
409
501
  }) => {
410
502
  const { client, locale: contextLocale } = useShopify();
411
503
  const locale = providedLocale || contextLocale;
412
504
  const [points_subscribe, set_points_subscribe] = react.useState(false);
413
505
  const giftProductsCache = react.useRef(null);
506
+ const effectiveCart = react.useMemo(() => {
507
+ if (lines && lines.length > 0) {
508
+ return createMockCartFromLines(lines, cart);
509
+ }
510
+ return cart;
511
+ }, [lines, cart]);
414
512
  react.useEffect(() => {
415
513
  if (locale === "au") {
416
514
  const isPointsSubscribe = Cookies5__default.default.get("points_subscribe");
@@ -432,14 +530,16 @@ var useScriptAutoFreeGift = ({
432
530
  upgrade_multiple2 = 1.2;
433
531
  upgrade_value2 = 40;
434
532
  }
435
- cart?.lineItems?.forEach(({ customAttributes }) => {
436
- customAttributes?.forEach(({ key, value }) => {
437
- if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
438
- if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
439
- });
440
- });
533
+ effectiveCart?.lineItems?.forEach(
534
+ ({ customAttributes }) => {
535
+ customAttributes?.forEach(({ key, value }) => {
536
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
537
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
538
+ });
539
+ }
540
+ );
441
541
  return [upgrade_multiple2, upgrade_value2];
442
- }, [cart?.lineItems, points_subscribe]);
542
+ }, [effectiveCart?.lineItems, points_subscribe]);
443
543
  const breakpoints = react.useMemo(() => {
444
544
  if (!isActivityAvailable) return [];
445
545
  return (campaign?.breakpoints || []).map((item) => ({
@@ -467,7 +567,7 @@ var useScriptAutoFreeGift = ({
467
567
  }, [giftHandles]);
468
568
  const involvedLines = react.useMemo(() => {
469
569
  if (!isActivityAvailable) return [];
470
- return (cart?.lineItems || []).filter((line) => {
570
+ return (effectiveCart?.lineItems || []).filter((line) => {
471
571
  const isNotGift = line?.totalAmount && Number(line.totalAmount) > 0 && line.customAttributes?.every(
472
572
  (item) => item.key !== _giveaway
473
573
  );
@@ -476,7 +576,7 @@ var useScriptAutoFreeGift = ({
476
576
  );
477
577
  return isNotGift && hasCampaignTag;
478
578
  });
479
- }, [cart?.lineItems, isActivityAvailable, _giveaway]);
579
+ }, [effectiveCart?.lineItems, isActivityAvailable, _giveaway]);
480
580
  const involvedSubTotal = react.useMemo(() => {
481
581
  if (!isActivityAvailable) return new Decimal2__default.default(0);
482
582
  return involvedLines.reduce((prev, item) => {
@@ -502,18 +602,24 @@ var useScriptAutoFreeGift = ({
502
602
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
503
603
  return [currentLevel, nextLevel];
504
604
  }, [breakpoints, involvedSubTotal, involvedLines.length]);
505
- const { data: giftProductsResult } = useSWR__default.default(shouldFetch ? giftHandles : null, async () => {
506
- const res = await shopifySdk.getProductsByHandles(client, {
507
- handles: giftHandles,
508
- locale
509
- });
510
- const result = Array.isArray(res) ? res : [];
511
- giftProductsCache.current = {
512
- data: result,
513
- giftHandles: [...giftHandles]
514
- };
515
- return result;
516
- });
605
+ const { data: giftProductsResult } = useSWR__default.default(
606
+ shouldFetch ? giftHandles : null,
607
+ async () => {
608
+ const res = await shopifySdk.getProductsByHandles(client, {
609
+ handles: giftHandles,
610
+ locale
611
+ });
612
+ const result = Array.isArray(res) ? res : [];
613
+ giftProductsCache.current = {
614
+ data: result,
615
+ giftHandles: [...giftHandles]
616
+ };
617
+ return result;
618
+ },
619
+ {
620
+ revalidateOnFocus: false
621
+ }
622
+ );
517
623
  const finalGiftProductsResult = react.useMemo(() => {
518
624
  if (giftProductsCache.current && !shouldFetch) {
519
625
  return giftProductsCache.current.data || void 0;
@@ -751,7 +857,7 @@ function useApplyCartCodes(options) {
751
857
  if (!discountCodes?.length) {
752
858
  throw new Error("Invalid input used for this operation: Miss discountCode");
753
859
  }
754
- const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
860
+ const cartId = providedCartId || cart?.id;
755
861
  if (!cartId) {
756
862
  return void 0;
757
863
  }
@@ -764,6 +870,12 @@ function useApplyCartCodes(options) {
764
870
  cookieAdapter: cartCookieAdapter,
765
871
  metafieldIdentifiers
766
872
  });
873
+ const unApplicableCodes = discountCodes.filter(
874
+ (code) => updatedCart?.discountCodes?.find((item) => item.code === code && !item.applicable)
875
+ );
876
+ if (unApplicableCodes.length) {
877
+ throw new Error(`${unApplicableCodes.join(", ")} is not applicable to the cart`);
878
+ }
767
879
  if (updatedCart) {
768
880
  mutateCart(updatedCart);
769
881
  }
@@ -779,7 +891,7 @@ function useRemoveCartCodes(options) {
779
891
  const removeCodes = react.useCallback(
780
892
  async (_key, { arg }) => {
781
893
  const { cartId: providedCartId, discountCodes } = arg;
782
- const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
894
+ const cartId = providedCartId || cart?.id;
783
895
  const codes = cart?.discountCodes?.filter((code) => !!code.applicable) || [];
784
896
  const leftCodes = codes.filter((code) => discountCodes?.length ? !discountCodes.includes(code.code) : code.code).map((code) => code.code);
785
897
  const updatedCart = await shopifySdk.updateCartCodes(client, {
@@ -801,7 +913,7 @@ function useRemoveCartCodes(options) {
801
913
  // src/hooks/cart/use-add-to-cart.ts
802
914
  function useAddToCart({ withTrack = true } = {}, swrOptions) {
803
915
  const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
804
- const { cart } = useCartContext();
916
+ const { cart, addCustomAttributes } = useCartContext();
805
917
  const { trigger: applyCartCodes } = useApplyCartCodes();
806
918
  const { trigger: removeInvalidCodes } = useRemoveCartCodes();
807
919
  const { trigger: addCartLines2 } = useAddCartLines();
@@ -815,7 +927,8 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
815
927
  buyerIdentity,
816
928
  needCreateCart = false,
817
929
  onCodesInvalid,
818
- replaceExistingCodes
930
+ replaceExistingCodes,
931
+ customAttributes
819
932
  } = arg;
820
933
  if (!lineItems || lineItems.length === 0) {
821
934
  return;
@@ -838,6 +951,7 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
838
951
  if (!resultCart) {
839
952
  return void 0;
840
953
  }
954
+ console.log("npm addCartLines resultCart", resultCart);
841
955
  if (resultCart.discountCodes && resultCart.discountCodes.length > 0) {
842
956
  const unapplicableCodes = resultCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
843
957
  if (unapplicableCodes.length > 0) {
@@ -859,6 +973,9 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
859
973
  discountCodes
860
974
  });
861
975
  }
976
+ if (customAttributes && customAttributes.length > 0) {
977
+ addCustomAttributes(customAttributes);
978
+ }
862
979
  if (withTrack) {
863
980
  trackAddToCartGA({
864
981
  lineItems,
@@ -1011,6 +1128,60 @@ function useBuyNow({ withTrack = true } = {}, swrOptions) {
1011
1128
  );
1012
1129
  return useSWRMutation__default.default("buy-now", buyNow, swrOptions);
1013
1130
  }
1131
+ function useCalcGiftsFromLines({
1132
+ lines,
1133
+ customer,
1134
+ scriptGiveawayKey = CUSTOMER_SCRIPT_GIFT_KEY
1135
+ }) {
1136
+ const { locale } = useShopify();
1137
+ const { cart, autoFreeGiftConfig, gradientGiftsConfig } = useCartContext();
1138
+ const functionGift = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer, lines);
1139
+ const scriptGift = useScriptAutoFreeGift({
1140
+ campaign: gradientGiftsConfig || null,
1141
+ _giveaway: scriptGiveawayKey,
1142
+ cart,
1143
+ locale,
1144
+ lines
1145
+ });
1146
+ const allGiftLines = react.useMemo(() => {
1147
+ const functionGiftLines = functionGift.qualifyingGift?.itemsToAdd || [];
1148
+ const scriptGiftLines = scriptGift.freeGiftLevel ? scriptGift.freeGiftLevel.giveawayProducts.map((product) => {
1149
+ const giftProduct = scriptGift.giftProductsResult?.find(
1150
+ (p) => p.handle === product.handle
1151
+ );
1152
+ const variant = giftProduct?.variants?.[0];
1153
+ return {
1154
+ variant: {
1155
+ id: variant?.id || "",
1156
+ handle: product.handle,
1157
+ sku: product.sku
1158
+ },
1159
+ quantity: 1,
1160
+ attributes: [
1161
+ {
1162
+ key: scriptGiveawayKey,
1163
+ value: "true"
1164
+ }
1165
+ ]
1166
+ };
1167
+ }).filter((item) => item.variant.id) : [];
1168
+ return [...functionGiftLines, ...scriptGiftLines];
1169
+ }, [
1170
+ functionGift.qualifyingGift,
1171
+ scriptGift.freeGiftLevel,
1172
+ scriptGift.giftProductsResult,
1173
+ scriptGiveawayKey
1174
+ ]);
1175
+ const hasGifts = react.useMemo(() => {
1176
+ return allGiftLines.length > 0;
1177
+ }, [allGiftLines]);
1178
+ return {
1179
+ functionGift,
1180
+ scriptGift,
1181
+ allGiftLines,
1182
+ hasGifts
1183
+ };
1184
+ }
1014
1185
 
1015
1186
  // src/hooks/cart/types/order-discount.ts
1016
1187
  var OrderDiscountType = /* @__PURE__ */ ((OrderDiscountType2) => {
@@ -1061,9 +1232,12 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1061
1232
  discountAmount: 0
1062
1233
  };
1063
1234
  }
1064
- const tieredDiscounts = activeCampaign.result_detail.order_discount_conf.tiered_discounts;
1065
- const qualifyingTier = [...tieredDiscounts].reverse().find((tier) => subtotal >= Number(tier.amount));
1066
- const nextGoal = tieredDiscounts.find((tier) => subtotal < Number(tier.amount));
1235
+ const currentCurrency = cart?.currency?.code || "";
1236
+ console.log("currentCurrency", cart, currentCurrency);
1237
+ const orderDiscountConf = activeCampaign.result_detail.order_discount_conf;
1238
+ const tieredDiscounts = orderDiscountConf.tiered_discounts_markets?.[currentCurrency] || orderDiscountConf.tiered_discounts;
1239
+ const qualifyingTier = [...tieredDiscounts].sort((a, b) => Number(b.amount) - Number(a.amount)).find((tier) => subtotal >= Number(tier.amount));
1240
+ const nextGoal = [...tieredDiscounts].sort((a, b) => Number(a.amount) - Number(b.amount)).find((tier) => subtotal < Number(tier.amount));
1067
1241
  if (!qualifyingTier) {
1068
1242
  return {
1069
1243
  qualifyingDiscount: null,
@@ -1131,12 +1305,10 @@ function useHasPlusMemberInCart({
1131
1305
  };
1132
1306
  }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
1133
1307
  }
1134
-
1135
- // src/hooks/cart/feature/use-cart-attributes.ts
1136
1308
  var getReferralAttributes = () => {
1137
- const inviteCode = Cookies5__default.default.get("invite_code");
1138
- const playModeId = Cookies5__default.default.get("playModeId");
1139
- const popup = Cookies5__default.default.get("_popup");
1309
+ const inviteCode = shopifySdk.getLocalStorage("invite_code") || Cookies5__default.default.get("invite_code");
1310
+ const playModeId = shopifySdk.getLocalStorage("playModeId") || Cookies5__default.default.get("playModeId");
1311
+ const popup = shopifySdk.getLocalStorage("_popup") || Cookies5__default.default.get("_popup");
1140
1312
  if (inviteCode && playModeId) {
1141
1313
  return popup ? [
1142
1314
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -1160,8 +1332,6 @@ var useCartAttributes = ({
1160
1332
  memberSetting,
1161
1333
  cart
1162
1334
  });
1163
- console.log("memberSetting", memberSetting);
1164
- console.log("hasPlusMember", hasPlusMember);
1165
1335
  react.useEffect(() => {
1166
1336
  setCurrentUrl(window.location.href);
1167
1337
  }, []);
@@ -1187,7 +1357,7 @@ var useCartAttributes = ({
1187
1357
  return "new_user_login";
1188
1358
  }, [customer]);
1189
1359
  const memberAttributes = react.useMemo(() => {
1190
- return [
1360
+ const attributes = [
1191
1361
  {
1192
1362
  key: "_token",
1193
1363
  value: profile?.token
@@ -1208,17 +1378,28 @@ var useCartAttributes = ({
1208
1378
  value: profile?.token ? "true" : "false"
1209
1379
  }
1210
1380
  ];
1381
+ if (profile?.token) {
1382
+ attributes.push({
1383
+ key: "_login_user",
1384
+ value: "1"
1385
+ });
1386
+ }
1387
+ return attributes;
1211
1388
  }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
1212
1389
  const functionAttributes = react.useMemo(() => {
1213
- return [
1214
- cart?.discountCodes && {
1390
+ const hasFunctionEnvAttribute = cart?.lineItems.some(
1391
+ (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
1392
+ );
1393
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
1394
+ return hasFunctionEnvAttribute ? [
1395
+ {
1215
1396
  key: "_discounts_function_env",
1216
1397
  value: JSON.stringify({
1217
- discount_code: cart?.discountCodes.map((item) => item.code),
1398
+ discount_code: discountCodes,
1218
1399
  user_tags: customer?.tags || []
1219
1400
  })
1220
1401
  }
1221
- ];
1402
+ ] : [];
1222
1403
  }, [cart]);
1223
1404
  const presellAttributes = react.useMemo(() => {
1224
1405
  return [
@@ -1250,18 +1431,50 @@ var useCartAttributes = ({
1250
1431
  }
1251
1432
  ];
1252
1433
  }, [currentUrl]);
1434
+ const commonAttributes = react.useMemo(
1435
+ () => [
1436
+ ...memberAttributes,
1437
+ ...functionAttributes,
1438
+ ...presellAttributes,
1439
+ ...weightAttributes,
1440
+ ...trackingAttributes,
1441
+ ...getReferralAttributes()
1442
+ ].filter((item) => item?.value),
1443
+ [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
1444
+ );
1445
+ const extraAttributesInCart = react.useMemo(() => {
1446
+ const commonAttributeKeys = [
1447
+ // member attributes
1448
+ "_token",
1449
+ "_member_type",
1450
+ "_user_type",
1451
+ "_is_login",
1452
+ "_login_user",
1453
+ // function attributes
1454
+ "_discounts_function_env",
1455
+ // presell attributes
1456
+ "_presale",
1457
+ // weight attributes
1458
+ "_weight",
1459
+ "_app_source_name",
1460
+ // tracking attributes
1461
+ "utm_params",
1462
+ // referral attributes
1463
+ "_invite_code",
1464
+ "_play_mode_id",
1465
+ "_popup"
1466
+ ];
1467
+ return cart?.customAttributes?.filter(
1468
+ (item) => !commonAttributeKeys.includes(item.key)
1469
+ ) || [];
1470
+ }, [cart]);
1253
1471
  return react.useMemo(
1254
1472
  () => ({
1255
- attributes: [
1256
- ...memberAttributes,
1257
- ...functionAttributes,
1258
- ...presellAttributes,
1259
- ...weightAttributes,
1260
- ...trackingAttributes,
1261
- ...getReferralAttributes()
1262
- ].filter((item) => item?.value)
1473
+ attributes: [...commonAttributes, ...extraAttributesInCart].filter(
1474
+ (item) => item?.value
1475
+ )
1263
1476
  }),
1264
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
1477
+ [commonAttributes, extraAttributesInCart]
1265
1478
  );
1266
1479
  };
1267
1480
  var DEFAULT_MIN = 1;
@@ -1478,8 +1691,9 @@ function useProductsByHandles(options = {}) {
1478
1691
  metafieldIdentifiers
1479
1692
  });
1480
1693
  },
1481
- swrOptions || {
1482
- revalidateOnFocus: false
1694
+ {
1695
+ revalidateOnFocus: false,
1696
+ ...swrOptions
1483
1697
  }
1484
1698
  );
1485
1699
  }
@@ -2395,6 +2609,73 @@ var usePlusMemberDeliveryCodes = ({
2395
2609
  [deliveryData]
2396
2610
  );
2397
2611
  };
2612
+ function useUpdateCartDeliveryOptions(mutate, metafieldIdentifiers, options) {
2613
+ const { client, locale, cartCookieAdapter } = useShopify();
2614
+ const updateDeliveryOptions = react.useCallback(
2615
+ async (_key, { arg }) => {
2616
+ const updatedCart = await shopifySdk.updateCartDeliveryOptions(client, {
2617
+ ...arg,
2618
+ metafieldIdentifiers,
2619
+ cookieAdapter: cartCookieAdapter
2620
+ });
2621
+ console.log("useUpdateCartDeliveryOptions updatedCart", updatedCart);
2622
+ if (updatedCart) {
2623
+ mutate(updatedCart);
2624
+ }
2625
+ return updatedCart;
2626
+ },
2627
+ [client, locale, cartCookieAdapter, mutate]
2628
+ );
2629
+ return useSWRMutation__default.default("update-cart-delivery-options", updateDeliveryOptions, options);
2630
+ }
2631
+
2632
+ // src/hooks/member/plus/use-update-plus-member-delivery-options.ts
2633
+ var useUpdatePlusMemberDeliveryOptions = ({
2634
+ options
2635
+ } = {}) => {
2636
+ const { cart: cartContextData, mutateCart, metafieldIdentifiers } = useCartContext();
2637
+ const { trigger: updateCartDeliveryOptions2 } = useUpdateCartDeliveryOptions(
2638
+ mutateCart,
2639
+ metafieldIdentifiers
2640
+ );
2641
+ const handler = react.useCallback(
2642
+ async (_, { arg }) => {
2643
+ const currentCart = arg?.cart || cartContextData;
2644
+ const { deliveryData } = arg;
2645
+ const firstDeliveryGroup = currentCart?.deliveryGroups?.[0];
2646
+ const deliveryGroupId = firstDeliveryGroup?.id;
2647
+ const selectedOptionCode = deliveryData?.deliveryCustomData?.selected_delivery_option?.code;
2648
+ if (!deliveryGroupId || !selectedOptionCode || selectedOptionCode === firstDeliveryGroup?.selectedDeliveryOption?.code) {
2649
+ return null;
2650
+ }
2651
+ const deliveryGroup = currentCart?.deliveryGroups?.find(
2652
+ (group) => group?.id === deliveryGroupId
2653
+ );
2654
+ const matchedOption = deliveryGroup?.deliveryOptions?.find(
2655
+ (option) => option?.code === selectedOptionCode
2656
+ );
2657
+ if (!matchedOption?.handle) {
2658
+ return null;
2659
+ }
2660
+ const deliveryOptions = [
2661
+ {
2662
+ deliveryGroupId,
2663
+ deliveryOptionHandle: matchedOption.handle
2664
+ }
2665
+ ];
2666
+ const updatedCart = await updateCartDeliveryOptions2({
2667
+ selectedDeliveryOptions: deliveryOptions,
2668
+ cartId: currentCart?.id
2669
+ });
2670
+ if (updatedCart && mutateCart) {
2671
+ mutateCart(updatedCart);
2672
+ }
2673
+ return updatedCart;
2674
+ },
2675
+ [cartContextData, updateCartDeliveryOptions2, mutateCart]
2676
+ );
2677
+ return useSWRMutation__default.default("update-cart-delivery-options", handler, options);
2678
+ };
2398
2679
  var usePlusMemberItemCustomAttributes = ({
2399
2680
  deliveryData
2400
2681
  }) => {
@@ -2414,48 +2695,18 @@ var usePlusMemberCheckoutCustomAttributes = ({
2414
2695
  deliveryData,
2415
2696
  product,
2416
2697
  variant,
2417
- customer,
2418
2698
  isShowShippingBenefits
2419
2699
  }) => {
2420
2700
  const { deliveryCustomData } = deliveryData || {};
2421
2701
  const { profile } = usePlusMemberContext();
2422
- const userType = react.useMemo(() => {
2423
- const customerInfo = customer;
2424
- if (!customerInfo) {
2425
- return "new_user_unlogin";
2426
- }
2427
- if (customer) {
2428
- const { orders = {} } = customer;
2429
- const edgesLength = orders?.edges?.length;
2430
- if (edgesLength === 1) {
2431
- return "old_user_orders_once";
2432
- } else if (edgesLength && edgesLength > 1) {
2433
- return "old_user_orders_twice";
2434
- }
2435
- }
2436
- return "new_user_login";
2437
- }, [customer]);
2438
2702
  return react.useMemo(() => {
2439
2703
  const checkoutCustomAttributes = [
2440
- {
2441
- key: "_token",
2442
- value: profile?.token || ""
2443
- },
2704
+ // _last_url: 付费会员结算完成之后 checkout 有一个继续购买的按钮, 用于跳转到继续购买的页面
2444
2705
  {
2445
2706
  key: "_last_url",
2446
2707
  value: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
2447
- },
2448
- {
2449
- key: "_user_type",
2450
- value: userType
2451
2708
  }
2452
2709
  ];
2453
- if (profile) {
2454
- checkoutCustomAttributes.push({
2455
- key: "_login_user",
2456
- value: "1"
2457
- });
2458
- }
2459
2710
  if (deliveryCustomData) {
2460
2711
  checkoutCustomAttributes.push({
2461
2712
  key: "_checkout_delivery_custom",
@@ -2465,12 +2716,6 @@ var usePlusMemberCheckoutCustomAttributes = ({
2465
2716
  })
2466
2717
  });
2467
2718
  }
2468
- if (variant?.metafields?.presell) {
2469
- checkoutCustomAttributes.push({
2470
- key: "_presale",
2471
- value: "true"
2472
- });
2473
- }
2474
2719
  if (isShowShippingBenefits && !isShowShippingBenefits({ variant, product, setting: {} })) {
2475
2720
  checkoutCustomAttributes.push({
2476
2721
  key: "_hide_shipping",
@@ -2478,18 +2723,17 @@ var usePlusMemberCheckoutCustomAttributes = ({
2478
2723
  });
2479
2724
  }
2480
2725
  return checkoutCustomAttributes;
2481
- }, [deliveryCustomData, product, profile, userType, variant, isShowShippingBenefits]);
2726
+ }, [deliveryCustomData, product, profile, variant, isShowShippingBenefits]);
2482
2727
  };
2483
2728
  function useAutoRemovePlusMemberInCart({
2484
- metafields,
2485
- isMonthlyPlus,
2486
- isAnnualPlus
2729
+ cart,
2730
+ profile,
2731
+ memberSetting
2487
2732
  }) {
2488
- const { plus_monthly_product, plus_annual_product } = metafields || {};
2489
- const { cart } = useCartContext();
2733
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
2490
2734
  const { trigger: removeCartLines2 } = useRemoveCartLines();
2491
2735
  react.useEffect(() => {
2492
- if (!cart) return;
2736
+ if (!cart || !plus_monthly_product || !plus_annual_product) return;
2493
2737
  const removePlusProduct = async (productType) => {
2494
2738
  if (!productType) return;
2495
2739
  const product = cart.lineItems?.find(
@@ -2501,33 +2745,25 @@ function useAutoRemovePlusMemberInCart({
2501
2745
  });
2502
2746
  }
2503
2747
  };
2504
- if (isMonthlyPlus) {
2748
+ if (profile?.isMonthlyPlus) {
2505
2749
  removePlusProduct(plus_monthly_product);
2506
2750
  }
2507
- if (isAnnualPlus) {
2751
+ if (profile?.isAnnualPlus) {
2508
2752
  removePlusProduct(plus_annual_product);
2509
2753
  }
2510
- }, [
2511
- cart,
2512
- plus_annual_product,
2513
- plus_monthly_product,
2514
- isAnnualPlus,
2515
- isMonthlyPlus,
2516
- removeCartLines2
2517
- ]);
2754
+ }, [cart, plus_annual_product, plus_monthly_product, profile, removeCartLines2]);
2518
2755
  }
2519
2756
  function useAddPlusMemberProductsToCart({
2520
2757
  cart,
2521
- memberSetting,
2522
- selectedPlusMemberMode,
2523
- selectedPlusMemberProduct
2758
+ profile
2524
2759
  }) {
2760
+ const { selectedPlusMemberMode, selectedPlusMemberProduct, plusMemberMetafields } = usePlusMemberContext();
2525
2761
  const { hasMonthlyPlus, hasAnnualPlus } = useHasPlusMemberInCart({
2526
- cart,
2527
- memberSetting
2762
+ memberSetting: plusMemberMetafields,
2763
+ cart
2528
2764
  });
2529
2765
  const plusMemberProduct = react.useMemo(() => {
2530
- if (selectedPlusMemberMode === "free" /* FREE */) {
2766
+ if (!selectedPlusMemberProduct || selectedPlusMemberMode === "free" /* FREE */) {
2531
2767
  return void 0;
2532
2768
  }
2533
2769
  if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && hasMonthlyPlus) {
@@ -2536,7 +2772,10 @@ function useAddPlusMemberProductsToCart({
2536
2772
  if (selectedPlusMemberMode === "annual" /* ANNUAL */ && hasAnnualPlus) {
2537
2773
  return void 0;
2538
2774
  }
2539
- if (!selectedPlusMemberProduct) {
2775
+ if (profile?.isMonthlyPlus && selectedPlusMemberMode === "monthly" /* MONTHLY */) {
2776
+ return void 0;
2777
+ }
2778
+ if (profile?.isAnnualPlus && selectedPlusMemberMode === "annual" /* ANNUAL */) {
2540
2779
  return void 0;
2541
2780
  }
2542
2781
  return selectedPlusMemberProduct;
@@ -2828,10 +3067,9 @@ exports.RuleType = RuleType;
2828
3067
  exports.SCRIPT_CODE_AMOUNT_KEY = SCRIPT_CODE_AMOUNT_KEY;
2829
3068
  exports.ShippingMethodMode = ShippingMethodMode;
2830
3069
  exports.SpendMoneyType = SpendMoneyType;
2831
- exports.atobID = atobID;
2832
- exports.btoaID = btoaID;
2833
3070
  exports.checkAttributesUpdateNeeded = checkAttributesUpdateNeeded;
2834
3071
  exports.clearGeoLocationCache = clearGeoLocationCache;
3072
+ exports.createMockCartFromLines = createMockCartFromLines;
2835
3073
  exports.currencyCodeMapping = currencyCodeMapping;
2836
3074
  exports.defaultSWRMutationConfiguration = defaultSWRMutationConfiguration;
2837
3075
  exports.formatFunctionAutoFreeGift = formatFunctionAutoFreeGift;
@@ -2841,6 +3079,7 @@ exports.getDiscountEnvAttributeValue = getDiscountEnvAttributeValue;
2841
3079
  exports.getMatchedMainProductSubTotal = getMatchedMainProductSubTotal;
2842
3080
  exports.getQuery = getQuery;
2843
3081
  exports.getReferralAttributes = getReferralAttributes;
3082
+ exports.normalizeAddToCartLines = normalizeAddToCartLines;
2844
3083
  exports.preCheck = preCheck;
2845
3084
  exports.safeParse = safeParse;
2846
3085
  exports.useAddCartLines = useAddCartLines;
@@ -2857,6 +3096,7 @@ exports.useAutoRemovePlusMemberInCart = useAutoRemovePlusMemberInCart;
2857
3096
  exports.useBlog = useBlog;
2858
3097
  exports.useBuyNow = useBuyNow;
2859
3098
  exports.useCalcAutoFreeGift = useCalcAutoFreeGift;
3099
+ exports.useCalcGiftsFromLines = useCalcGiftsFromLines;
2860
3100
  exports.useCalcOrderDiscount = useCalcOrderDiscount;
2861
3101
  exports.useCartAttributes = useCartAttributes;
2862
3102
  exports.useCartItemQuantityLimit = useCartItemQuantityLimit;
@@ -2889,6 +3129,7 @@ exports.useSite = useSite;
2889
3129
  exports.useUpdateCartAttributes = useUpdateCartAttributes;
2890
3130
  exports.useUpdateCartLines = useUpdateCartLines;
2891
3131
  exports.useUpdateLineCodeAmountAttributes = useUpdateLineCodeAmountAttributes;
3132
+ exports.useUpdatePlusMemberDeliveryOptions = useUpdatePlusMemberDeliveryOptions;
2892
3133
  exports.useUpdateVariantQuery = useUpdateVariantQuery;
2893
3134
  exports.useVariant = useVariant;
2894
3135
  exports.useVariantMedia = useVariantMedia;