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

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.
@@ -95,6 +95,81 @@ 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
+ return {
152
+ id: existingCart?.id || "temp-cart-id",
153
+ customerId: existingCart?.customerId,
154
+ email: existingCart?.email,
155
+ createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
156
+ currency: existingCart?.currency || { code: "USD" },
157
+ taxesIncluded: existingCart?.taxesIncluded,
158
+ lineItems: normalizedLines,
159
+ totallineItemsDiscount: 0,
160
+ orderDiscounts: 0,
161
+ lineItemsSubtotalPrice: subtotalPrice,
162
+ subtotalPrice,
163
+ totalPrice,
164
+ totalTaxAmount: 0,
165
+ discountCodes: existingCart?.discountCodes || [],
166
+ discountAllocations: [],
167
+ url: existingCart?.url || "",
168
+ ready: true,
169
+ customAttributes: existingCart?.customAttributes
170
+ };
171
+ }
172
+
98
173
  // src/hooks/cart/utils/index.ts
99
174
  var getQuery = () => {
100
175
  const url = typeof window !== "undefined" ? window.location.search : "";
@@ -134,25 +209,25 @@ var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
134
209
  return acc + (main_product?.spend_money_type === 1 /* ORIGIN_PRICE */ ? Number(line.subtotalAmount) || 0 : Number(line.totalAmount) || 0);
135
210
  }, 0) || 0;
136
211
  };
137
- var getDiscountEnvAttributeValue = (attributes = []) => {
138
- const attr = attributes.find((attr2) => attr2.key === CUSTOMER_ATTRIBUTE_KEY);
139
- return safeParseJson(attr?.value ?? "") ?? {};
140
- };
141
- var isAttributesEqual = (attrs1 = [], attrs2 = []) => {
142
- if (attrs1.length !== attrs2.length) return false;
143
- const sorted1 = [...attrs1].sort((a, b) => a.key.localeCompare(b.key));
144
- const sorted2 = [...attrs2].sort((a, b) => a.key.localeCompare(b.key));
145
- return sorted1.every(
146
- (attr, i) => attr.key === sorted2[i]?.key && attr.value === sorted2[i]?.value
147
- );
148
- };
149
- var safeParseJson = (str) => {
212
+ var safeParse = (str) => {
150
213
  try {
151
214
  return JSON.parse(str);
152
215
  } catch (err) {
153
216
  return {};
154
217
  }
155
218
  };
219
+ var getDiscountEnvAttributeValue = (attributes = []) => {
220
+ const attr = attributes.find((attr2) => attr2.key === CUSTOMER_ATTRIBUTE_KEY);
221
+ return safeParse(attr?.value ?? "") ?? {};
222
+ };
223
+ var checkAttributesUpdateNeeded = (oldAttributes, newAttributes, customAttributesNeedRemove) => {
224
+ return oldAttributes.some((attr) => {
225
+ const newAttr = newAttributes.find((newAttr2) => newAttr2.key === attr.key);
226
+ return newAttr ? newAttr.value !== attr.value : true;
227
+ }) || newAttributes.some((attr) => !oldAttributes.some((oldAttr) => oldAttr.key === attr.key)) || customAttributesNeedRemove.some(
228
+ (removeAttr) => oldAttributes.some((oldAttr) => oldAttr.key === removeAttr.key)
229
+ );
230
+ };
156
231
  var containsAll = (source, requiredItems = []) => {
157
232
  if (!requiredItems?.length) return true;
158
233
  const sourceSet = new Set(source);
@@ -319,12 +394,15 @@ var formatFunctionAutoFreeGift = ({
319
394
  };
320
395
  return result;
321
396
  };
322
- var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
397
+ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
323
398
  const tags = useMemo(() => customer?.tags || [], [customer?.tags]);
324
399
  const isCustomerLoading = useMemo(() => !customer ? true : false, [customer]);
325
400
  const dealsType = "";
326
401
  const { client, locale } = useShopify();
327
402
  const giftProductsCache = useRef(null);
403
+ const effectiveCart = useMemo(() => {
404
+ return cart;
405
+ }, [lines, cart]);
328
406
  const { activeCampaign, subtotal } = useMemo(() => {
329
407
  for (const campaign of autoFreeGiftConfig) {
330
408
  const { rule_conditions = [], rule_result } = campaign;
@@ -332,7 +410,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
332
410
  const isPreCheckPassed = preCheck(rule_conditions, tags, []);
333
411
  if (isPreCheckPassed && spend_get_reward) {
334
412
  const matchedSubtotal = getMatchedMainProductSubTotal(
335
- cart,
413
+ effectiveCart,
336
414
  spend_get_reward.main_product?.variant_list?.map((v) => v.variant_id) || [],
337
415
  {
338
416
  spend_money_type: spend_get_reward.main_product?.spend_money_type || 1,
@@ -346,7 +424,7 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer) => {
346
424
  }
347
425
  }
348
426
  return { activeCampaign: null, subtotal: 0 };
349
- }, [autoFreeGiftConfig, cart, tags, dealsType]);
427
+ }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
350
428
  const { qualifyingGift, nextTierGoal } = useMemo(() => {
351
429
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
352
430
  return { qualifyingGift: null, nextTierGoal: null };
@@ -429,18 +507,33 @@ var useScriptAutoFreeGift = ({
429
507
  campaign,
430
508
  _giveaway,
431
509
  cart,
432
- locale: providedLocale
510
+ locale: providedLocale,
511
+ lines
433
512
  }) => {
434
513
  const { client, locale: contextLocale } = useShopify();
435
514
  const locale = providedLocale || contextLocale;
436
515
  const [points_subscribe, set_points_subscribe] = useState(false);
437
516
  const giftProductsCache = useRef(null);
517
+ const effectiveCart = useMemo(() => {
518
+ if (lines && lines.length > 0) {
519
+ return createMockCartFromLines(lines, cart);
520
+ }
521
+ return cart;
522
+ }, [lines, cart]);
438
523
  useEffect(() => {
439
524
  if (locale === "au") {
440
525
  const isPointsSubscribe = Cookies5.get("points_subscribe");
441
526
  set_points_subscribe(!!isPointsSubscribe);
442
527
  }
443
528
  }, [locale]);
529
+ const isActivityAvailable = useMemo(() => {
530
+ if (!campaign) return false;
531
+ const query = getQuery();
532
+ const utmCampaign = Cookies5.get("utm_campaign") || query?.utm_campaign;
533
+ if (campaign.activityAvailableQuery && !utmCampaign?.includes(campaign.activityAvailableQuery))
534
+ return false;
535
+ return true;
536
+ }, [campaign]);
444
537
  const [upgrade_multiple, upgrade_value] = useMemo(() => {
445
538
  let upgrade_multiple2 = 1;
446
539
  let upgrade_value2 = 0;
@@ -448,17 +541,17 @@ var useScriptAutoFreeGift = ({
448
541
  upgrade_multiple2 = 1.2;
449
542
  upgrade_value2 = 40;
450
543
  }
451
- cart?.lineItems?.forEach(({ customAttributes }) => {
544
+ effectiveCart?.lineItems?.forEach(({ customAttributes }) => {
452
545
  customAttributes?.forEach(({ key, value }) => {
453
546
  if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
454
547
  if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
455
548
  });
456
549
  });
457
550
  return [upgrade_multiple2, upgrade_value2];
458
- }, [cart?.lineItems, points_subscribe]);
551
+ }, [effectiveCart?.lineItems, points_subscribe]);
459
552
  const breakpoints = useMemo(() => {
460
- if (!campaign) return [];
461
- return (campaign.breakpoints || []).map((item) => ({
553
+ if (!isActivityAvailable) return [];
554
+ return (campaign?.breakpoints || []).map((item) => ({
462
555
  breakpoint: new Decimal2(item.breakpoint).minus(new Decimal2(upgrade_value)).dividedBy(new Decimal2(upgrade_multiple)).toFixed(2, Decimal2.ROUND_DOWN),
463
556
  giveawayProducts: item.giveawayProducts || []
464
557
  }));
@@ -482,25 +575,26 @@ var useScriptAutoFreeGift = ({
482
575
  return true;
483
576
  }, [giftHandles]);
484
577
  const involvedLines = useMemo(() => {
485
- if (!campaign) return [];
486
- return (cart?.lineItems || []).filter((line) => {
578
+ if (!isActivityAvailable) return [];
579
+ return (effectiveCart?.lineItems || []).filter((line) => {
487
580
  const isNotGift = line?.totalAmount && Number(line.totalAmount) > 0 && line.customAttributes?.every(
488
581
  (item) => item.key !== _giveaway
489
582
  );
490
583
  const hasCampaignTag = line.product?.tags?.some(
491
- (tag) => campaign.includeTags?.includes(tag.trim()) && line.variant?.availableForSale
584
+ (tag) => campaign?.includeTags?.includes(tag.trim()) && line.variant?.availableForSale
492
585
  );
493
586
  return isNotGift && hasCampaignTag;
494
587
  });
495
- }, [cart?.lineItems, campaign, _giveaway]);
588
+ }, [effectiveCart?.lineItems, isActivityAvailable, _giveaway]);
496
589
  const involvedSubTotal = useMemo(() => {
497
- if (!campaign) return new Decimal2(0);
590
+ if (!isActivityAvailable) return new Decimal2(0);
498
591
  return involvedLines.reduce((prev, item) => {
499
- const amount = campaign.useTotalAmount ? item.totalAmount : item.subtotalAmount;
592
+ const amount = campaign?.useTotalAmount ? item.totalAmount : item.subtotalAmount;
500
593
  return new Decimal2(prev).plus(new Decimal2(amount || 0));
501
594
  }, new Decimal2(0));
502
- }, [involvedLines, campaign]);
595
+ }, [involvedLines, isActivityAvailable]);
503
596
  const [freeGiftLevel, nextFreeGiftLevel] = useMemo(() => {
597
+ if (!isActivityAvailable) return [null, null];
504
598
  const sortedLevels = [...breakpoints].sort(
505
599
  (a, b) => Number(b.breakpoint) - Number(a.breakpoint)
506
600
  );
@@ -924,6 +1018,9 @@ function CartProvider({
924
1018
  }) {
925
1019
  const { client, cartCookieAdapter } = useShopify();
926
1020
  const [customAttributes, setCustomAttributes] = useState([]);
1021
+ const [customAttributesNeedDelete, setCustomAttributesNeedDelete] = useState(
1022
+ []
1023
+ );
927
1024
  const [isCodeChanging, setIsCodeChanging] = useState(false);
928
1025
  const [loadingState, setLoadingState] = useState({
929
1026
  editLineQuantityLoading: false,
@@ -954,7 +1051,11 @@ function CartProvider({
954
1051
  useRequest(
955
1052
  () => {
956
1053
  const newAttributes = [...attributes, ...customAttributes];
957
- const needUpdate = cart && !isAttributesEqual(cart.customAttributes, newAttributes);
1054
+ const needUpdate = cart && !checkAttributesUpdateNeeded(
1055
+ cart.customAttributes,
1056
+ newAttributes,
1057
+ customAttributesNeedDelete
1058
+ );
958
1059
  if (needUpdate) {
959
1060
  return updateAttributes({ attributes: newAttributes });
960
1061
  } else {
@@ -975,11 +1076,12 @@ function CartProvider({
975
1076
  isCartLoading: isCartLoading || isCodeChanging,
976
1077
  setLoadingState
977
1078
  });
978
- const removeCustomAttributes = useCallback((attributes2) => {
979
- setCustomAttributes(
980
- (prev) => prev.filter((attr) => !attributes2.some((a) => a.key === attr.key))
981
- );
982
- }, []);
1079
+ const removeCustomAttributes = useCallback(
1080
+ (attributes2) => {
1081
+ setCustomAttributesNeedDelete(attributes2);
1082
+ },
1083
+ [setCustomAttributesNeedDelete]
1084
+ );
983
1085
  const addCustomAttributes = useCallback(
984
1086
  (attributes2) => {
985
1087
  const sameAttributes = attributes2.filter(
@@ -1066,6 +1168,7 @@ function CartProvider({
1066
1168
  isCodeChanging,
1067
1169
  setIsCodeChanging,
1068
1170
  autoFreeGiftConfig,
1171
+ gradientGiftsConfig,
1069
1172
  setLoadingState,
1070
1173
  loadingState,
1071
1174
  // function满赠
@@ -1089,6 +1192,7 @@ function CartProvider({
1089
1192
  locale,
1090
1193
  isCodeChanging,
1091
1194
  autoFreeGiftConfig,
1195
+ gradientGiftsConfig,
1092
1196
  loadingState,
1093
1197
  // function满赠
1094
1198
  functionAutoFreeGift,