@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.
@@ -1,5 +1,5 @@
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, btoaID, getProductsByHandles, getLocalStorage, atobID } 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';
@@ -95,6 +95,83 @@ var CODE_AMOUNT_KEY = "_sku_code_money";
95
95
  var SCRIPT_CODE_AMOUNT_KEY = "_code_money";
96
96
  var MAIN_PRODUCT_CODE = ["WS24", "WSTD", "WS7D", "WSCP", "WSPE", "WSPD"];
97
97
 
98
+ // src/hooks/cart/utils/normalize-add-to-cart-lines.ts
99
+ function normalizeAddToCartLines(lines) {
100
+ return lines.filter((line) => line.variant?.id).map((line, index) => {
101
+ const variant = line.variant;
102
+ const product = variant.product;
103
+ 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;
107
+ return {
108
+ id: `temp-line-${index}-${variant.id}`,
109
+ // Temporary ID for pre-cart lines
110
+ name: product?.title || variant.title || "",
111
+ quantity,
112
+ variantId: variant.id,
113
+ productId: product?.id || variant.id.split("/").slice(0, -2).join("/"),
114
+ totalAmount,
115
+ subtotalAmount,
116
+ discountAllocations: [],
117
+ customAttributes: line.attributes || [],
118
+ variant: {
119
+ id: variant.id,
120
+ price,
121
+ listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
122
+ sku: variant.sku || "",
123
+ name: variant.title || "",
124
+ image: variant.image ? {
125
+ url: variant.image.url,
126
+ altText: variant.image.altText || void 0
127
+ } : void 0,
128
+ requiresShipping: false,
129
+ // Default value, not available in NormalizedProductVariant
130
+ availableForSale: variant.availableForSale ?? true,
131
+ quantityAvailable: variant.quantityAvailable ?? 0,
132
+ currentlyNotInStock: false,
133
+ // Default value, will be updated when added to cart
134
+ weight: variant.weight,
135
+ metafields: variant.metafields
136
+ },
137
+ product,
138
+ path: product?.handle ? `/products/${product.handle}` : "",
139
+ discounts: [],
140
+ options: variant.selectedOptions?.map((opt) => ({
141
+ name: opt.name,
142
+ value: opt.value
143
+ }))
144
+ };
145
+ });
146
+ }
147
+ function createMockCartFromLines(lines, existingCart) {
148
+ const normalizedLines = normalizeAddToCartLines(lines);
149
+ const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
150
+ const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
151
+ console.log("lines createMockCartFromLines", lines);
152
+ const currency = lines[0]?.variant?.price?.currencyCode;
153
+ return {
154
+ id: existingCart?.id || "temp-cart-id",
155
+ customerId: existingCart?.customerId,
156
+ email: existingCart?.email,
157
+ createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
158
+ currency: existingCart?.currency?.code || { code: currency },
159
+ taxesIncluded: existingCart?.taxesIncluded,
160
+ lineItems: normalizedLines,
161
+ totalLineItemsDiscount: 0,
162
+ orderDiscounts: 0,
163
+ lineItemsSubtotalPrice: subtotalPrice,
164
+ subtotalPrice,
165
+ totalPrice,
166
+ totalTaxAmount: 0,
167
+ discountCodes: existingCart?.discountCodes || [],
168
+ discountAllocations: [],
169
+ url: existingCart?.url || "",
170
+ ready: true,
171
+ customAttributes: existingCart?.customAttributes
172
+ };
173
+ }
174
+
98
175
  // src/hooks/cart/utils/index.ts
99
176
  var getQuery = () => {
100
177
  const url = typeof window !== "undefined" ? window.location.search : "";
@@ -112,16 +189,6 @@ var getQuery = () => {
112
189
  }
113
190
  return theRequest;
114
191
  };
115
- function atobID(id) {
116
- if (id && typeof id === "string" && id.includes("/")) {
117
- return id.split("/").pop()?.split("?")?.shift();
118
- } else {
119
- return id;
120
- }
121
- }
122
- function btoaID(id, type = "ProductVariant") {
123
- return `gid://shopify/${type}/${id}`;
124
- }
125
192
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
126
193
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
127
194
  const matchedList = cartData?.lineItems?.filter((line) => {
@@ -319,12 +386,15 @@ var formatFunctionAutoFreeGift = ({
319
386
  };
320
387
  return result;
321
388
  };
322
- var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
389
+ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
323
390
  const tags = useMemo(() => customer?.tags || [], [customer?.tags]);
324
391
  const isCustomerLoading = useMemo(() => !customer ? true : false, [customer]);
325
392
  const dealsType = "";
326
393
  const { client, locale } = useShopify();
327
394
  const giftProductsCache = useRef(null);
395
+ const effectiveCart = useMemo(() => {
396
+ return cart;
397
+ }, [lines, cart]);
328
398
  const { activeCampaign, subtotal } = useMemo(() => {
329
399
  for (const campaign of autoFreeGiftConfig) {
330
400
  const { rule_conditions = [], rule_result } = campaign;
@@ -332,7 +402,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
332
402
  const isPreCheckPassed = preCheck(rule_conditions, tags, []);
333
403
  if (isPreCheckPassed && spend_get_reward) {
334
404
  const matchedSubtotal = getMatchedMainProductSubTotal(
335
- cart,
405
+ effectiveCart,
336
406
  spend_get_reward.main_product?.variant_list?.map((v) => v.variant_id) || [],
337
407
  {
338
408
  spend_money_type: spend_get_reward.main_product?.spend_money_type || 1,
@@ -346,17 +416,26 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
346
416
  }
347
417
  }
348
418
  return { activeCampaign: null, subtotal: 0 };
349
- }, [autoFreeGiftConfig, cart, tags, dealsType]);
419
+ }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
350
420
  const { qualifyingGift, nextTierGoal } = useMemo(() => {
351
421
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
352
422
  return { qualifyingGift: null, nextTierGoal: null };
353
423
  }
354
424
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
355
- const qualifyingTier = [...giftTiers].reverse().find((tier) => subtotal >= Number(tier.spend_sum_money));
356
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
425
+ const currentCurrency = effectiveCart?.currency?.code || "";
426
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency);
427
+ const getThresholdAmount = (tier) => {
428
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency]?.value) {
429
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency].value);
430
+ }
431
+ return Number(tier.spend_sum_money || 0);
432
+ };
433
+ const qualifyingTier = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
434
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
357
435
  if (!qualifyingTier) {
358
436
  return { qualifyingGift: null, nextTierGoal: nextGoal || null };
359
437
  }
438
+ const actualThreshold = getThresholdAmount(qualifyingTier);
360
439
  const formattedGift = {
361
440
  tier: qualifyingTier,
362
441
  itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
@@ -375,7 +454,10 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
375
454
  value: JSON.stringify({
376
455
  is_gift: true,
377
456
  rule_id: activeCampaign.rule_id,
378
- spend_sum_money: qualifyingTier.spend_sum_money
457
+ spend_sum_money: actualThreshold,
458
+ // 使用实际的门槛金额(多币种支持)
459
+ currency_code: currentCurrency
460
+ // 记录当前币种
379
461
  })
380
462
  }
381
463
  ]
@@ -383,7 +465,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
383
465
  }).filter((item) => item !== null)
384
466
  };
385
467
  return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
386
- }, [activeCampaign, subtotal]);
468
+ }, [activeCampaign, subtotal, effectiveCart]);
387
469
  const giftHandles = useMemo(() => {
388
470
  const giftVariant = autoFreeGiftConfig.map(
389
471
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -399,18 +481,24 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
399
481
  }
400
482
  return true;
401
483
  }, [giftHandles]);
402
- const { data: giftProductsResult } = useSWR(shouldFetch ? giftHandles : null, async () => {
403
- const res = await getProductsByHandles(client, {
404
- handles: giftHandles,
405
- locale
406
- });
407
- const result = Array.isArray(res) ? res : [];
408
- giftProductsCache.current = {
409
- data: result,
410
- giftHandles: [...giftHandles]
411
- };
412
- return result;
413
- });
484
+ const { data: giftProductsResult } = useSWR(
485
+ shouldFetch ? giftHandles : null,
486
+ async () => {
487
+ const res = await getProductsByHandles(client, {
488
+ handles: giftHandles,
489
+ locale
490
+ });
491
+ const result = Array.isArray(res) ? res : [];
492
+ giftProductsCache.current = {
493
+ data: result,
494
+ giftHandles: [...giftHandles]
495
+ };
496
+ return result;
497
+ },
498
+ {
499
+ revalidateOnFocus: false
500
+ }
501
+ );
414
502
  const finalGiftProductsResult = useMemo(() => {
415
503
  if (giftProductsCache.current && !shouldFetch) {
416
504
  return giftProductsCache.current.data || void 0;
@@ -429,12 +517,19 @@ var useScriptAutoFreeGift = ({
429
517
  campaign,
430
518
  _giveaway,
431
519
  cart,
432
- locale: providedLocale
520
+ locale: providedLocale,
521
+ lines
433
522
  }) => {
434
523
  const { client, locale: contextLocale } = useShopify();
435
524
  const locale = providedLocale || contextLocale;
436
525
  const [points_subscribe, set_points_subscribe] = useState(false);
437
526
  const giftProductsCache = useRef(null);
527
+ const effectiveCart = useMemo(() => {
528
+ if (lines && lines.length > 0) {
529
+ return createMockCartFromLines(lines, cart);
530
+ }
531
+ return cart;
532
+ }, [lines, cart]);
438
533
  useEffect(() => {
439
534
  if (locale === "au") {
440
535
  const isPointsSubscribe = Cookies5.get("points_subscribe");
@@ -456,14 +551,16 @@ var useScriptAutoFreeGift = ({
456
551
  upgrade_multiple2 = 1.2;
457
552
  upgrade_value2 = 40;
458
553
  }
459
- cart?.lineItems?.forEach(({ customAttributes }) => {
460
- customAttributes?.forEach(({ key, value }) => {
461
- if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
462
- if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
463
- });
464
- });
554
+ effectiveCart?.lineItems?.forEach(
555
+ ({ customAttributes }) => {
556
+ customAttributes?.forEach(({ key, value }) => {
557
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
558
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
559
+ });
560
+ }
561
+ );
465
562
  return [upgrade_multiple2, upgrade_value2];
466
- }, [cart?.lineItems, points_subscribe]);
563
+ }, [effectiveCart?.lineItems, points_subscribe]);
467
564
  const breakpoints = useMemo(() => {
468
565
  if (!isActivityAvailable) return [];
469
566
  return (campaign?.breakpoints || []).map((item) => ({
@@ -491,7 +588,7 @@ var useScriptAutoFreeGift = ({
491
588
  }, [giftHandles]);
492
589
  const involvedLines = useMemo(() => {
493
590
  if (!isActivityAvailable) return [];
494
- return (cart?.lineItems || []).filter((line) => {
591
+ return (effectiveCart?.lineItems || []).filter((line) => {
495
592
  const isNotGift = line?.totalAmount && Number(line.totalAmount) > 0 && line.customAttributes?.every(
496
593
  (item) => item.key !== _giveaway
497
594
  );
@@ -500,7 +597,7 @@ var useScriptAutoFreeGift = ({
500
597
  );
501
598
  return isNotGift && hasCampaignTag;
502
599
  });
503
- }, [cart?.lineItems, isActivityAvailable, _giveaway]);
600
+ }, [effectiveCart?.lineItems, isActivityAvailable, _giveaway]);
504
601
  const involvedSubTotal = useMemo(() => {
505
602
  if (!isActivityAvailable) return new Decimal2(0);
506
603
  return involvedLines.reduce((prev, item) => {
@@ -526,18 +623,24 @@ var useScriptAutoFreeGift = ({
526
623
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
527
624
  return [currentLevel, nextLevel];
528
625
  }, [breakpoints, involvedSubTotal, involvedLines.length]);
529
- const { data: giftProductsResult } = useSWR(shouldFetch ? giftHandles : null, async () => {
530
- const res = await getProductsByHandles(client, {
531
- handles: giftHandles,
532
- locale
533
- });
534
- const result = Array.isArray(res) ? res : [];
535
- giftProductsCache.current = {
536
- data: result,
537
- giftHandles: [...giftHandles]
538
- };
539
- return result;
540
- });
626
+ const { data: giftProductsResult } = useSWR(
627
+ shouldFetch ? giftHandles : null,
628
+ async () => {
629
+ const res = await getProductsByHandles(client, {
630
+ handles: giftHandles,
631
+ locale
632
+ });
633
+ const result = Array.isArray(res) ? res : [];
634
+ giftProductsCache.current = {
635
+ data: result,
636
+ giftHandles: [...giftHandles]
637
+ };
638
+ return result;
639
+ },
640
+ {
641
+ revalidateOnFocus: false
642
+ }
643
+ );
541
644
  const finalGiftProductsResult = useMemo(() => {
542
645
  if (giftProductsCache.current && !shouldFetch) {
543
646
  return giftProductsCache.current.data || void 0;
@@ -619,12 +722,10 @@ function useHasPlusMemberInCart({
619
722
  };
620
723
  }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
621
724
  }
622
-
623
- // src/hooks/cart/feature/use-cart-attributes.ts
624
725
  var getReferralAttributes = () => {
625
- const inviteCode = Cookies5.get("invite_code");
626
- const playModeId = Cookies5.get("playModeId");
627
- const popup = Cookies5.get("_popup");
726
+ const inviteCode = getLocalStorage("invite_code") || Cookies5.get("invite_code");
727
+ const playModeId = getLocalStorage("playModeId") || Cookies5.get("playModeId");
728
+ const popup = getLocalStorage("_popup") || Cookies5.get("_popup");
628
729
  if (inviteCode && playModeId) {
629
730
  return popup ? [
630
731
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -648,8 +749,6 @@ var useCartAttributes = ({
648
749
  memberSetting,
649
750
  cart
650
751
  });
651
- console.log("memberSetting", memberSetting);
652
- console.log("hasPlusMember", hasPlusMember);
653
752
  useEffect(() => {
654
753
  setCurrentUrl(window.location.href);
655
754
  }, []);
@@ -675,7 +774,7 @@ var useCartAttributes = ({
675
774
  return "new_user_login";
676
775
  }, [customer]);
677
776
  const memberAttributes = useMemo(() => {
678
- return [
777
+ const attributes = [
679
778
  {
680
779
  key: "_token",
681
780
  value: profile?.token
@@ -696,17 +795,28 @@ var useCartAttributes = ({
696
795
  value: profile?.token ? "true" : "false"
697
796
  }
698
797
  ];
798
+ if (profile?.token) {
799
+ attributes.push({
800
+ key: "_login_user",
801
+ value: "1"
802
+ });
803
+ }
804
+ return attributes;
699
805
  }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
700
806
  const functionAttributes = useMemo(() => {
701
- return [
702
- cart?.discountCodes && {
807
+ const hasFunctionEnvAttribute = cart?.lineItems.some(
808
+ (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
809
+ );
810
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
811
+ return hasFunctionEnvAttribute ? [
812
+ {
703
813
  key: "_discounts_function_env",
704
814
  value: JSON.stringify({
705
- discount_code: cart?.discountCodes.map((item) => item.code),
815
+ discount_code: discountCodes,
706
816
  user_tags: customer?.tags || []
707
817
  })
708
818
  }
709
- ];
819
+ ] : [];
710
820
  }, [cart]);
711
821
  const presellAttributes = useMemo(() => {
712
822
  return [
@@ -738,18 +848,50 @@ var useCartAttributes = ({
738
848
  }
739
849
  ];
740
850
  }, [currentUrl]);
851
+ const commonAttributes = useMemo(
852
+ () => [
853
+ ...memberAttributes,
854
+ ...functionAttributes,
855
+ ...presellAttributes,
856
+ ...weightAttributes,
857
+ ...trackingAttributes,
858
+ ...getReferralAttributes()
859
+ ].filter((item) => item?.value),
860
+ [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
861
+ );
862
+ const extraAttributesInCart = useMemo(() => {
863
+ const commonAttributeKeys = [
864
+ // member attributes
865
+ "_token",
866
+ "_member_type",
867
+ "_user_type",
868
+ "_is_login",
869
+ "_login_user",
870
+ // function attributes
871
+ "_discounts_function_env",
872
+ // presell attributes
873
+ "_presale",
874
+ // weight attributes
875
+ "_weight",
876
+ "_app_source_name",
877
+ // tracking attributes
878
+ "utm_params",
879
+ // referral attributes
880
+ "_invite_code",
881
+ "_play_mode_id",
882
+ "_popup"
883
+ ];
884
+ return cart?.customAttributes?.filter(
885
+ (item) => !commonAttributeKeys.includes(item.key)
886
+ ) || [];
887
+ }, [cart]);
741
888
  return useMemo(
742
889
  () => ({
743
- attributes: [
744
- ...memberAttributes,
745
- ...functionAttributes,
746
- ...presellAttributes,
747
- ...weightAttributes,
748
- ...trackingAttributes,
749
- ...getReferralAttributes()
750
- ].filter((item) => item?.value)
890
+ attributes: [...commonAttributes, ...extraAttributesInCart].filter(
891
+ (item) => item?.value
892
+ )
751
893
  }),
752
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
894
+ [commonAttributes, extraAttributesInCart]
753
895
  );
754
896
  };
755
897
  var useUpdateLineCodeAmountAttributes = ({
@@ -965,8 +1107,13 @@ function CartProvider({
965
1107
  const { attributes } = useCartAttributes({ profile, customer, cart, memberSetting });
966
1108
  useRequest(
967
1109
  () => {
968
- const newAttributes = [...attributes, ...customAttributes];
969
- const needUpdate = cart && !checkAttributesUpdateNeeded(
1110
+ const newAttributes = [...attributes];
1111
+ customAttributes.forEach((item) => {
1112
+ if (item.value && !newAttributes.some((attr) => attr.key === item.key)) {
1113
+ newAttributes.push(item);
1114
+ }
1115
+ });
1116
+ const needUpdate = cart && checkAttributesUpdateNeeded(
970
1117
  cart.customAttributes,
971
1118
  newAttributes,
972
1119
  customAttributesNeedDelete
@@ -1070,8 +1217,14 @@ function CartProvider({
1070
1217
  );
1071
1218
  return result;
1072
1219
  }, [cart?.lineItems, scriptAutoFreeGift, functionAutoFreeGift]);
1220
+ const totalQuantity = useMemo(() => {
1221
+ const cartLinesCount = cart?.lineItems.reduce((acc, item) => acc + item.quantity, 0) || 0;
1222
+ const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
1223
+ return cartLinesCount + giftLinesCount;
1224
+ }, [cart?.lineItems, giftNeedAddToCartLines]);
1073
1225
  const value = useMemo(
1074
1226
  () => ({
1227
+ totalQuantity,
1075
1228
  cart,
1076
1229
  isCartLoading,
1077
1230
  triggerFetch: fetchCart,
@@ -1083,6 +1236,7 @@ function CartProvider({
1083
1236
  isCodeChanging,
1084
1237
  setIsCodeChanging,
1085
1238
  autoFreeGiftConfig,
1239
+ gradientGiftsConfig,
1086
1240
  setLoadingState,
1087
1241
  loadingState,
1088
1242
  // function满赠
@@ -1098,6 +1252,7 @@ function CartProvider({
1098
1252
  }),
1099
1253
  [
1100
1254
  cart,
1255
+ totalQuantity,
1101
1256
  isCartLoading,
1102
1257
  fetchCart,
1103
1258
  mutateCart,
@@ -1106,6 +1261,7 @@ function CartProvider({
1106
1261
  locale,
1107
1262
  isCodeChanging,
1108
1263
  autoFreeGiftConfig,
1264
+ gradientGiftsConfig,
1109
1265
  loadingState,
1110
1266
  // function满赠
1111
1267
  functionAutoFreeGift,