@anker-in/shopify-react 0.1.1-beta.9 → 0.1.1

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,9 +1,10 @@
1
1
  import { createContext, useMemo, useRef, useState, useEffect, useCallback, useContext } from 'react';
2
2
  import useSWRMutation from 'swr/mutation';
3
- import { getProductsByHandles, createCart, updateCartCodes, addCartLines, updateCartLines, removeCartLines, updateCartAttributes, getProduct, getAllProducts, getCollection, getAllCollections, getCollections, getBlog, getAllBlogs, getArticle, getArticles, getArticlesInBlog, getLocalStorage, setLocalStorage, updateCartDeliveryOptions } from '@anker-in/shopify-sdk';
3
+ import { getProductsByHandles, createCart, updateCartCodes, addCartLines, getLocalStorage, updateCartLines, removeCartLines, updateCartAttributes, getProduct, getAllProducts, getCollection, getAllCollections, getCollections, getBlog, getAllBlogs, getArticle, getArticles, getArticlesInBlog, setLocalStorage } from '@anker-in/shopify-sdk';
4
4
  import Cookies5 from 'js-cookie';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
  import Decimal2 from 'decimal.js';
7
+ import { atobID, btoaID } from '@anker-in/shopify-core';
7
8
  import useSWR from 'swr';
8
9
  import { useRequest } from 'ahooks';
9
10
 
@@ -60,6 +61,7 @@ var CUSTOMER_ATTRIBUTE_KEY = "_discounts_function_env";
60
61
  var CUSTOMER_SCRIPT_GIFT_KEY = "_giveaway_gradient_gifts";
61
62
  var CODE_AMOUNT_KEY = "_sku_code_money";
62
63
  var SCRIPT_CODE_AMOUNT_KEY = "_code_money";
64
+ var MEMBER_PRICE_ATTRIBUTE_KEY = "_member_price";
63
65
  var MAIN_PRODUCT_CODE = ["WS24", "WSTD", "WS7D", "WSCP", "WSPE", "WSPD"];
64
66
 
65
67
  // src/hooks/cart/utils/normalize-add-to-cart-lines.ts
@@ -68,9 +70,10 @@ function normalizeAddToCartLines(lines) {
68
70
  const variant = line.variant;
69
71
  const product = variant.product;
70
72
  const quantity = line.quantity || 1;
71
- const price = variant.finalPrice?.amount ? Number(variant.finalPrice.amount) : variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : variant.price?.amount ? Number(variant.price.amount) : 0;
72
- const subtotalAmount = price * quantity;
73
- const totalAmount = subtotalAmount;
73
+ const originalPrice = variant.price?.amount ? Number(variant.price.amount) : 0;
74
+ const finalPrice = variant.finalPrice?.amount === void 0 ? originalPrice : Number(variant.finalPrice?.amount);
75
+ const subtotalAmount = originalPrice * quantity;
76
+ const totalAmount = finalPrice * quantity;
74
77
  return {
75
78
  id: `temp-line-${index}-${variant.id}`,
76
79
  // Temporary ID for pre-cart lines
@@ -84,7 +87,7 @@ function normalizeAddToCartLines(lines) {
84
87
  customAttributes: line.attributes || [],
85
88
  variant: {
86
89
  id: variant.id,
87
- price,
90
+ price: finalPrice,
88
91
  listPrice: variant.compareAtPrice?.amount ? Number(variant.compareAtPrice.amount) : 0,
89
92
  sku: variant.sku || "",
90
93
  name: variant.title || "",
@@ -115,12 +118,13 @@ function createMockCartFromLines(lines, existingCart) {
115
118
  const normalizedLines = normalizeAddToCartLines(lines);
116
119
  const subtotalPrice = normalizedLines.reduce((sum, line) => sum + line.subtotalAmount, 0);
117
120
  const totalPrice = normalizedLines.reduce((sum, line) => sum + line.totalAmount, 0);
121
+ const currency = lines[0]?.variant?.price?.currencyCode;
118
122
  return {
119
123
  id: existingCart?.id || "temp-cart-id",
120
124
  customerId: existingCart?.customerId,
121
125
  email: existingCart?.email,
122
126
  createdAt: existingCart?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
123
- currency: existingCart?.currency || { code: "USD" },
127
+ currency: existingCart?.currency || { code: currency },
124
128
  taxesIncluded: existingCart?.taxesIncluded,
125
129
  lineItems: normalizedLines,
126
130
  totalLineItemsDiscount: 0,
@@ -154,16 +158,6 @@ var getQuery = () => {
154
158
  }
155
159
  return theRequest;
156
160
  };
157
- function atobID(id) {
158
- if (id && typeof id === "string" && id.includes("/")) {
159
- return id.split("/").pop()?.split("?")?.shift();
160
- } else {
161
- return id;
162
- }
163
- }
164
- function btoaID(id, type = "ProductVariant") {
165
- return `gid://shopify/${type}/${id}`;
166
- }
167
161
  var getMatchedMainProductSubTotal = (cartData, variant_list, main_product) => {
168
162
  const isAllStoreVariant = main_product?.all_store_variant ?? false;
169
163
  const matchedList = cartData?.lineItems?.filter((line) => {
@@ -187,14 +181,6 @@ var getDiscountEnvAttributeValue = (attributes = []) => {
187
181
  const attr = attributes.find((attr2) => attr2.key === CUSTOMER_ATTRIBUTE_KEY);
188
182
  return safeParse(attr?.value ?? "") ?? {};
189
183
  };
190
- var checkAttributesUpdateNeeded = (oldAttributes, newAttributes, customAttributesNeedRemove) => {
191
- return oldAttributes.some((attr) => {
192
- const newAttr = newAttributes.find((newAttr2) => newAttr2.key === attr.key);
193
- return newAttr ? newAttr.value !== attr.value : true;
194
- }) || newAttributes.some((attr) => !oldAttributes.some((oldAttr) => oldAttr.key === attr.key)) || customAttributesNeedRemove.some(
195
- (removeAttr) => oldAttributes.some((oldAttr) => oldAttr.key === removeAttr.key)
196
- );
197
- };
198
184
  var containsAll = (source, requiredItems = []) => {
199
185
  if (!requiredItems?.length) return true;
200
186
  const sourceSet = new Set(source);
@@ -395,43 +381,29 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
395
381
  }
396
382
  return { activeCampaign: null, subtotal: 0 };
397
383
  }, [autoFreeGiftConfig, effectiveCart, tags, dealsType]);
398
- const { qualifyingGift, nextTierGoal } = useMemo(() => {
384
+ const { qualifyingTier, nextTierGoal, actualThreshold, currentCurrency } = useMemo(() => {
399
385
  if (!activeCampaign || !activeCampaign.rule_result?.spend_get_reward?.gift_product) {
400
- return { qualifyingGift: null, nextTierGoal: null };
386
+ return { qualifyingTier: null, nextTierGoal: null, actualThreshold: 0, currentCurrency: "" };
401
387
  }
402
388
  const giftTiers = activeCampaign.rule_result.spend_get_reward.gift_product;
403
- const qualifyingTier = [...giftTiers].sort((a, b) => Number(b.spend_sum_money) - Number(a.spend_sum_money)).find((tier) => subtotal >= Number(tier.spend_sum_money));
404
- const nextGoal = giftTiers.find((tier) => subtotal < Number(tier.spend_sum_money));
405
- if (!qualifyingTier) {
406
- return { qualifyingGift: null, nextTierGoal: nextGoal || null };
407
- }
408
- const formattedGift = {
409
- tier: qualifyingTier,
410
- itemsToAdd: qualifyingTier.reward_list?.map((reward) => {
411
- const giftProduct = reward?.variant_list?.[0];
412
- if (!giftProduct) return null;
413
- return {
414
- variant: {
415
- id: btoaID(giftProduct.variant_id),
416
- handle: giftProduct.handle,
417
- sku: giftProduct.sku
418
- },
419
- quantity: reward?.get_unit || 1,
420
- attributes: [
421
- {
422
- key: CUSTOMER_ATTRIBUTE_KEY,
423
- value: JSON.stringify({
424
- is_gift: true,
425
- rule_id: activeCampaign.rule_id,
426
- spend_sum_money: qualifyingTier.spend_sum_money
427
- })
428
- }
429
- ]
430
- };
431
- }).filter((item) => item !== null)
389
+ const currentCurrency2 = effectiveCart?.currency?.code || "";
390
+ console.log("currentCurrency useCalcAutoFreeGift", effectiveCart, currentCurrency2);
391
+ const getThresholdAmount = (tier) => {
392
+ if (tier.spend_sum_money_multi_markets?.[currentCurrency2]?.value) {
393
+ return Number(tier.spend_sum_money_multi_markets[currentCurrency2].value);
394
+ }
395
+ return Number(tier.spend_sum_money || 0);
432
396
  };
433
- return { qualifyingGift: formattedGift, nextTierGoal: nextGoal || null };
434
- }, [activeCampaign, subtotal]);
397
+ const qualifyingTier2 = [...giftTiers].sort((a, b) => getThresholdAmount(b) - getThresholdAmount(a)).find((tier) => subtotal >= getThresholdAmount(tier));
398
+ const nextGoal = giftTiers.find((tier) => subtotal < getThresholdAmount(tier));
399
+ const actualThreshold2 = qualifyingTier2 ? getThresholdAmount(qualifyingTier2) : 0;
400
+ return {
401
+ qualifyingTier: qualifyingTier2,
402
+ nextTierGoal: nextGoal || null,
403
+ actualThreshold: actualThreshold2,
404
+ currentCurrency: currentCurrency2
405
+ };
406
+ }, [activeCampaign, subtotal, effectiveCart]);
435
407
  const giftHandles = useMemo(() => {
436
408
  const giftVariant = autoFreeGiftConfig.map(
437
409
  (item) => item.rule_result?.spend_get_reward?.gift_product?.map(
@@ -447,24 +419,82 @@ var useCalcAutoFreeGift = (cart, autoFreeGiftConfig, customer, lines) => {
447
419
  }
448
420
  return true;
449
421
  }, [giftHandles]);
450
- const { data: giftProductsResult } = useSWR(shouldFetch ? giftHandles : null, async () => {
451
- const res = await getProductsByHandles(client, {
452
- handles: giftHandles,
453
- locale
454
- });
455
- const result = Array.isArray(res) ? res : [];
456
- giftProductsCache.current = {
457
- data: result,
458
- giftHandles: [...giftHandles]
459
- };
460
- return result;
461
- });
422
+ const { data: giftProductsResult } = useSWR(
423
+ shouldFetch ? giftHandles : null,
424
+ async () => {
425
+ const res = await getProductsByHandles(client, {
426
+ handles: giftHandles,
427
+ locale
428
+ });
429
+ const result = Array.isArray(res) ? res : [];
430
+ giftProductsCache.current = {
431
+ data: result,
432
+ giftHandles: [...giftHandles]
433
+ };
434
+ return result;
435
+ },
436
+ {
437
+ revalidateOnFocus: false
438
+ }
439
+ );
462
440
  const finalGiftProductsResult = useMemo(() => {
463
441
  if (giftProductsCache.current && !shouldFetch) {
464
442
  return giftProductsCache.current.data || void 0;
465
443
  }
466
444
  return giftProductsResult;
467
445
  }, [giftProductsResult, shouldFetch]);
446
+ const qualifyingGift = useMemo(() => {
447
+ if (!qualifyingTier || !activeCampaign) {
448
+ return null;
449
+ }
450
+ const itemsToAdd = qualifyingTier.reward_list?.map((reward) => {
451
+ if (!reward.variant_list || reward.variant_list.length === 0) {
452
+ return null;
453
+ }
454
+ let selectedGiftProduct = null;
455
+ for (const giftVariant of reward.variant_list) {
456
+ const productInfo = finalGiftProductsResult?.find(
457
+ (p) => p.handle === giftVariant.handle
458
+ );
459
+ if (productInfo) {
460
+ const variantInfo = productInfo.variants?.find((v) => v.sku === giftVariant.sku);
461
+ if (variantInfo?.availableForSale) {
462
+ selectedGiftProduct = giftVariant;
463
+ break;
464
+ }
465
+ }
466
+ }
467
+ if (!selectedGiftProduct) {
468
+ selectedGiftProduct = reward.variant_list[0];
469
+ }
470
+ return {
471
+ variant: {
472
+ id: btoaID(selectedGiftProduct.variant_id),
473
+ handle: selectedGiftProduct.handle,
474
+ sku: selectedGiftProduct.sku
475
+ },
476
+ quantity: reward?.get_unit || 1,
477
+ attributes: [
478
+ {
479
+ key: CUSTOMER_ATTRIBUTE_KEY,
480
+ value: JSON.stringify({
481
+ is_gift: true,
482
+ rule_id: activeCampaign.rule_id,
483
+ spend_sum_money: actualThreshold,
484
+ // 使用实际的门槛金额(多币种支持)
485
+ currency_code: currentCurrency
486
+ // 记录当前币种
487
+ })
488
+ }
489
+ ]
490
+ };
491
+ }).filter((item) => item !== null);
492
+ const formattedGift = {
493
+ tier: qualifyingTier,
494
+ itemsToAdd
495
+ };
496
+ return formattedGift;
497
+ }, [qualifyingTier, activeCampaign, finalGiftProductsResult, actualThreshold, currentCurrency]);
468
498
  return {
469
499
  qualifyingGift,
470
500
  nextTierGoal,
@@ -478,7 +508,8 @@ var useScriptAutoFreeGift = ({
478
508
  _giveaway,
479
509
  cart,
480
510
  locale: providedLocale,
481
- lines
511
+ lines,
512
+ profile
482
513
  }) => {
483
514
  const { client, locale: contextLocale } = useShopify();
484
515
  const locale = providedLocale || contextLocale;
@@ -502,8 +533,9 @@ var useScriptAutoFreeGift = ({
502
533
  const utmCampaign = Cookies5.get("utm_campaign") || query?.utm_campaign;
503
534
  if (campaign.activityAvailableQuery && !utmCampaign?.includes(campaign.activityAvailableQuery))
504
535
  return false;
536
+ if (campaign.requireLogin && !profile?.email) return false;
505
537
  return true;
506
- }, [campaign]);
538
+ }, [campaign, profile]);
507
539
  const [upgrade_multiple, upgrade_value] = useMemo(() => {
508
540
  let upgrade_multiple2 = 1;
509
541
  let upgrade_value2 = 0;
@@ -511,12 +543,14 @@ var useScriptAutoFreeGift = ({
511
543
  upgrade_multiple2 = 1.2;
512
544
  upgrade_value2 = 40;
513
545
  }
514
- effectiveCart?.lineItems?.forEach(({ customAttributes }) => {
515
- customAttributes?.forEach(({ key, value }) => {
516
- if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
517
- if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
518
- });
519
- });
546
+ effectiveCart?.lineItems?.forEach(
547
+ ({ customAttributes }) => {
548
+ customAttributes?.forEach(({ key, value }) => {
549
+ if (key === "_amount_upgrade_multiple") upgrade_multiple2 = Number(value) || 1;
550
+ if (key === "_amount_upgrade_value") upgrade_value2 = Number(value) || 0;
551
+ });
552
+ }
553
+ );
520
554
  return [upgrade_multiple2, upgrade_value2];
521
555
  }, [effectiveCart?.lineItems, points_subscribe]);
522
556
  const breakpoints = useMemo(() => {
@@ -581,18 +615,24 @@ var useScriptAutoFreeGift = ({
581
615
  const nextLevel = levelIndex > 0 ? sortedLevels[levelIndex - 1] ?? null : null;
582
616
  return [currentLevel, nextLevel];
583
617
  }, [breakpoints, involvedSubTotal, involvedLines.length]);
584
- const { data: giftProductsResult } = useSWR(shouldFetch ? giftHandles : null, async () => {
585
- const res = await getProductsByHandles(client, {
586
- handles: giftHandles,
587
- locale
588
- });
589
- const result = Array.isArray(res) ? res : [];
590
- giftProductsCache.current = {
591
- data: result,
592
- giftHandles: [...giftHandles]
593
- };
594
- return result;
595
- });
618
+ const { data: giftProductsResult } = useSWR(
619
+ shouldFetch ? giftHandles : null,
620
+ async () => {
621
+ const res = await getProductsByHandles(client, {
622
+ handles: giftHandles,
623
+ locale
624
+ });
625
+ const result = Array.isArray(res) ? res : [];
626
+ giftProductsCache.current = {
627
+ data: result,
628
+ giftHandles: [...giftHandles]
629
+ };
630
+ return result;
631
+ },
632
+ {
633
+ revalidateOnFocus: false
634
+ }
635
+ );
596
636
  const finalGiftProductsResult = useMemo(() => {
597
637
  if (giftProductsCache.current && !shouldFetch) {
598
638
  return giftProductsCache.current.data || void 0;
@@ -625,16 +665,19 @@ var useScriptAutoFreeGift = ({
625
665
  };
626
666
  };
627
667
  var CartContext = createContext(null);
628
- function useCartContext() {
668
+ function useCartContext(options) {
629
669
  const context = useContext(CartContext);
630
- if (!context) {
670
+ if (!context && true) {
631
671
  throw new Error("useCartContext must be used within a CartProvider");
632
672
  }
633
673
  return context;
634
674
  }
635
675
 
636
676
  // src/hooks/cart/use-create-cart.ts
637
- function useCreateCart(options) {
677
+ function useCreateCart({
678
+ updateCookie = false,
679
+ options
680
+ }) {
638
681
  const { client, locale, cartCookieAdapter } = useShopify();
639
682
  const { mutateCart, metafieldIdentifiers } = useCartContext();
640
683
  const createNewCart = useCallback(
@@ -642,7 +685,8 @@ function useCreateCart(options) {
642
685
  let newCart = await createCart(client, {
643
686
  ...arg,
644
687
  metafieldIdentifiers,
645
- cookieAdapter: cartCookieAdapter
688
+ cookieAdapter: cartCookieAdapter,
689
+ updateCookie
646
690
  });
647
691
  if (newCart) {
648
692
  const unApplicableCodes = newCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
@@ -669,11 +713,23 @@ function useAddCartLines(options) {
669
713
  const { mutateCart, metafieldIdentifiers } = useCartContext();
670
714
  const addLines = useCallback(
671
715
  async (_key, { arg }) => {
672
- let updatedCart = await addCartLines(client, {
673
- ...arg,
674
- metafieldIdentifiers,
675
- cookieAdapter: cartCookieAdapter
676
- });
716
+ const { cartId, lines } = arg;
717
+ const id = cartId || cartCookieAdapter?.getCartId(locale);
718
+ let updatedCart;
719
+ if (!id) {
720
+ updatedCart = await createCart(client, {
721
+ lines,
722
+ metafieldIdentifiers,
723
+ cookieAdapter: cartCookieAdapter
724
+ });
725
+ } else {
726
+ updatedCart = await addCartLines(client, {
727
+ cartId: id,
728
+ lines,
729
+ metafieldIdentifiers,
730
+ cookieAdapter: cartCookieAdapter
731
+ });
732
+ }
677
733
  if (updatedCart) {
678
734
  const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
679
735
  if (unApplicableCodes.length > 0) {
@@ -720,7 +776,7 @@ var trackAddToCartGA = ({
720
776
  const currencyCode = variant.product?.price?.currencyCode;
721
777
  const totalPrice = lineItems?.reduce(
722
778
  (prev, { variant: variant2 }) => prev.plus(
723
- variant2?.finalPrice?.amount ?? variant2?.compareAtPrice?.amount ?? variant2?.price?.amount ?? 0
779
+ variant2?.finalPrice?.amount === void 0 ? Number(variant2?.price?.amount) || 0 : Number(variant2?.finalPrice?.amount) || 0
724
780
  ),
725
781
  new Decimal2(0)
726
782
  ).toNumber();
@@ -753,10 +809,10 @@ var trackBuyNowGA = ({
753
809
  return;
754
810
  }
755
811
  const { variant } = lineItems[0];
756
- const currencyCode = variant.price?.currencyCode;
812
+ const currencyCode = variant.product?.price?.currencyCode || variant.price?.currencyCode;
757
813
  const totalPrice = lineItems?.reduce(
758
814
  (prev, { variant: variant2 }) => prev.plus(
759
- variant2?.finalPrice?.amount ?? variant2?.compareAtPrice?.amount ?? (variant2?.price?.amount || 0)
815
+ variant2?.finalPrice?.amount === void 0 ? Number(variant2?.price?.amount) || 0 : Number(variant2?.finalPrice?.amount) || 0
760
816
  ),
761
817
  new Decimal2(0)
762
818
  ).toNumber();
@@ -830,7 +886,7 @@ function useApplyCartCodes(options) {
830
886
  if (!discountCodes?.length) {
831
887
  throw new Error("Invalid input used for this operation: Miss discountCode");
832
888
  }
833
- const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
889
+ const cartId = providedCartId || cart?.id;
834
890
  if (!cartId) {
835
891
  return void 0;
836
892
  }
@@ -843,12 +899,18 @@ function useApplyCartCodes(options) {
843
899
  cookieAdapter: cartCookieAdapter,
844
900
  metafieldIdentifiers
845
901
  });
902
+ const unApplicableCodes = discountCodes.filter(
903
+ (code) => updatedCart?.discountCodes?.find((item) => item.code === code && !item.applicable)
904
+ );
905
+ if (unApplicableCodes.length) {
906
+ throw new Error(`${unApplicableCodes.join(", ")} is not applicable to the cart`);
907
+ }
846
908
  if (updatedCart) {
847
909
  mutateCart(updatedCart);
848
910
  }
849
911
  return updatedCart;
850
912
  },
851
- [client, locale, cartCookieAdapter, mutateCart, cart]
913
+ [client, locale, cartCookieAdapter, mutateCart, cart, metafieldIdentifiers]
852
914
  );
853
915
  return useSWRMutation("apply-codes", applyCodes, options);
854
916
  }
@@ -858,7 +920,7 @@ function useRemoveCartCodes(options) {
858
920
  const removeCodes = useCallback(
859
921
  async (_key, { arg }) => {
860
922
  const { cartId: providedCartId, discountCodes } = arg;
861
- const cartId = providedCartId ? void 0 : providedCartId || cart?.id;
923
+ const cartId = providedCartId || cart?.id;
862
924
  const codes = cart?.discountCodes?.filter((code) => !!code.applicable) || [];
863
925
  const leftCodes = codes.filter((code) => discountCodes?.length ? !discountCodes.includes(code.code) : code.code).map((code) => code.code);
864
926
  const updatedCart = await updateCartCodes(client, {
@@ -872,225 +934,96 @@ function useRemoveCartCodes(options) {
872
934
  }
873
935
  return updatedCart;
874
936
  },
875
- [client, locale, cartCookieAdapter, mutateCart, cart]
937
+ [client, locale, cartCookieAdapter, mutateCart, cart, metafieldIdentifiers]
876
938
  );
877
939
  return useSWRMutation("remove-codes", removeCodes, options);
878
940
  }
879
-
880
- // src/hooks/cart/use-add-to-cart.ts
881
- function useAddToCart({ withTrack = true } = {}, swrOptions) {
882
- const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
883
- const { cart } = useCartContext();
884
- const { trigger: applyCartCodes } = useApplyCartCodes();
885
- const { trigger: removeInvalidCodes } = useRemoveCartCodes();
886
- const { trigger: addCartLines2 } = useAddCartLines();
887
- const addToCart = useCallback(
888
- async (_key, { arg }) => {
889
- const {
890
- lineItems,
891
- cartId: providedCartId,
892
- discountCodes,
893
- gtmParams = {},
894
- buyerIdentity,
895
- needCreateCart = false,
896
- onCodesInvalid,
897
- replaceExistingCodes
898
- } = arg;
899
- if (!lineItems || lineItems.length === 0) {
900
- return;
901
- }
902
- const lines = lineItems.map((item) => ({
903
- merchandiseId: item.variant?.id || "",
904
- quantity: item.quantity || 1,
905
- attributes: item.attributes,
906
- sellingPlanId: item.sellingPlanId
907
- })).filter((item) => item.merchandiseId && item.quantity);
908
- if (lines.length === 0) {
909
- return;
910
- }
911
- const cartId = needCreateCart ? void 0 : providedCartId || cart?.id;
912
- let resultCart = await addCartLines2({
913
- cartId,
914
- lines,
915
- buyerIdentity
916
- });
917
- if (!resultCart) {
918
- return void 0;
919
- }
920
- console.log("npm addCartLines resultCart", resultCart);
921
- if (resultCart.discountCodes && resultCart.discountCodes.length > 0) {
922
- const unapplicableCodes = resultCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
923
- if (unapplicableCodes.length > 0) {
924
- if (onCodesInvalid) {
925
- const handledCart = await onCodesInvalid(resultCart, unapplicableCodes);
926
- if (handledCart) {
927
- resultCart = handledCart;
928
- }
929
- } else {
930
- await removeInvalidCodes({
931
- discountCodes: unapplicableCodes
932
- });
933
- }
934
- }
935
- }
936
- if (discountCodes && discountCodes.length > 0) {
937
- applyCartCodes({
938
- replaceExistingCodes,
939
- discountCodes
940
- });
941
- }
942
- if (withTrack) {
943
- trackAddToCartGA({
944
- lineItems,
945
- gtmParams: { ...gtmParams, brand: config.getBrand() }
946
- });
947
- trackAddToCartFBQ({ lineItems });
948
- }
949
- return resultCart;
950
- },
951
- [client, locale, cartCookieAdapter, userAdapter, cart, withTrack]
941
+ var initSameLinesAttributes = ({
942
+ cart,
943
+ line
944
+ }) => {
945
+ const sameLineInCart = cart?.lineItems.find(
946
+ (lineInCart) => lineInCart.variant.sku === line.variant?.sku && lineInCart.product?.handle === line.variant?.product?.handle
952
947
  );
953
- return useSWRMutation("add-to-cart", addToCart, swrOptions);
954
- }
955
- function useUpdateCartLines(options) {
956
- const { client, locale, cartCookieAdapter } = useShopify();
957
- const { mutateCart, metafieldIdentifiers } = useCartContext();
958
- const updateLines = useCallback(
959
- async (_key, { arg }) => {
960
- const updatedCart = await updateCartLines(client, {
961
- ...arg,
962
- metafieldIdentifiers,
963
- cookieAdapter: cartCookieAdapter
964
- });
965
- if (updatedCart) {
966
- mutateCart(updatedCart);
967
- }
968
- return updatedCart;
969
- },
970
- [client, locale, cartCookieAdapter, mutateCart]
948
+ const codeAmountAttribute = sameLineInCart?.customAttributes?.find(
949
+ (attr) => attr.key === CODE_AMOUNT_KEY
971
950
  );
972
- return useSWRMutation("update-cart-lines", updateLines, options);
973
- }
974
- function useRemoveCartLines(options) {
975
- const { client, locale, cartCookieAdapter } = useShopify();
976
- const { mutateCart, metafieldIdentifiers } = useCartContext();
977
- const removeLines = useCallback(
978
- async (_key, { arg }) => {
979
- const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
980
- let updatedCart = await removeCartLines(client, {
981
- cartId,
982
- lineIds,
983
- metafieldIdentifiers,
984
- cookieAdapter: cartCookieAdapter
985
- });
986
- if (updatedCart && autoRemoveInvalidCodes) {
987
- const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
988
- if (unApplicableCodes.length > 0) {
989
- if (onCodesRemoved) {
990
- const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
991
- if (handledCart) {
992
- updatedCart = handledCart;
993
- }
994
- } else {
995
- updatedCart = await updateCartCodes(client, {
996
- cartId: updatedCart.id,
997
- discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
998
- metafieldIdentifiers,
999
- cookieAdapter: cartCookieAdapter
1000
- }) || updatedCart;
1001
- }
1002
- }
1003
- }
1004
- if (updatedCart) {
1005
- mutateCart(updatedCart);
1006
- }
1007
- return updatedCart;
1008
- },
1009
- [client, locale, cartCookieAdapter, mutateCart]
951
+ const scriptCodeAmountAttribute = sameLineInCart?.customAttributes?.find(
952
+ (attr) => attr.key === SCRIPT_CODE_AMOUNT_KEY
1010
953
  );
1011
- return useSWRMutation("remove-cart-lines", removeLines, options);
1012
- }
1013
- function useUpdateCartAttributes(mutate, metafieldIdentifiers, options) {
1014
- const { client, locale, cartCookieAdapter } = useShopify();
1015
- const updateAttributes = useCallback(
1016
- async (_key, { arg }) => {
1017
- const updatedCart = await updateCartAttributes(client, {
1018
- ...arg,
1019
- metafieldIdentifiers,
1020
- cookieAdapter: cartCookieAdapter
1021
- });
1022
- console.log("useUpdateCartAttributes updatedCart", updatedCart);
1023
- if (updatedCart) {
1024
- mutate(updatedCart);
954
+ let functionAttribute = null;
955
+ try {
956
+ functionAttribute = sameLineInCart?.customAttributes?.find(
957
+ (attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY && JSON.parse(attr.value)?.discounted_amount
958
+ );
959
+ } catch (error) {
960
+ }
961
+ if (codeAmountAttribute || functionAttribute || scriptCodeAmountAttribute) {
962
+ return {
963
+ ...line,
964
+ attributes: [
965
+ ...line.attributes || [],
966
+ codeAmountAttribute,
967
+ functionAttribute,
968
+ scriptCodeAmountAttribute
969
+ ].filter(Boolean)
970
+ };
971
+ }
972
+ return line;
973
+ };
974
+ var initDiscountAttributes = ({ line }) => {
975
+ let itemAttributes = line.attributes || [];
976
+ const functionEnvAttribute = itemAttributes.find((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY);
977
+ if (!functionEnvAttribute) {
978
+ itemAttributes = itemAttributes.concat([
979
+ {
980
+ key: CUSTOMER_ATTRIBUTE_KEY,
981
+ value: JSON.stringify({
982
+ is_gift: false,
983
+ discounted_amount: line.variant?.finalPrice?.amount === void 0 ? Number(line.variant?.price?.amount) * (line.quantity || 1) : Number(line.variant?.finalPrice?.amount) * (line.quantity || 1)
984
+ })
1025
985
  }
1026
- return updatedCart;
1027
- },
1028
- [client, locale, cartCookieAdapter, mutate]
986
+ ]);
987
+ }
988
+ const memberPriceAttribute = itemAttributes.find(
989
+ (attr) => attr.key === MEMBER_PRICE_ATTRIBUTE_KEY
1029
990
  );
1030
- return useSWRMutation("update-cart-attributes", updateAttributes, options);
1031
- }
1032
- function useBuyNow({ withTrack = true } = {}, swrOptions) {
1033
- const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
1034
- const isLoggedIn = userAdapter?.isLoggedIn || false;
1035
- const buyNow = useCallback(
1036
- async (_key, { arg }) => {
1037
- const {
1038
- lineItems,
1039
- discountCodes,
1040
- gtmParams = {},
1041
- buyerIdentity,
1042
- fbqTrackConfig,
1043
- customAttributes,
1044
- metafieldIdentifiers,
1045
- redirectToCheckout
1046
- } = arg;
1047
- if (!lineItems || lineItems.length === 0) {
1048
- return;
991
+ const coupon = line.coupon;
992
+ if (!memberPriceAttribute && coupon) {
993
+ itemAttributes = itemAttributes.concat([
994
+ {
995
+ key: MEMBER_PRICE_ATTRIBUTE_KEY,
996
+ value: JSON.stringify({ code: coupon.code })
1049
997
  }
1050
- const lines = lineItems.map((item) => ({
1051
- merchandiseId: item.variant?.id || "",
1052
- quantity: item.quantity || 1,
1053
- attributes: item.attributes,
1054
- sellingPlanId: item.sellingPlanId
1055
- })).filter((item) => item.merchandiseId && item.quantity);
1056
- if (lines.length === 0) {
1057
- return;
998
+ ]);
999
+ }
1000
+ const couponDiscountAttribute = itemAttributes.find(
1001
+ (attr) => attr.key === CODE_AMOUNT_KEY || attr.key === SCRIPT_CODE_AMOUNT_KEY
1002
+ );
1003
+ if (!couponDiscountAttribute && coupon && Number(coupon?.amount) > 0) {
1004
+ itemAttributes = itemAttributes.concat([
1005
+ {
1006
+ key: CODE_AMOUNT_KEY,
1007
+ value: new Decimal2(coupon.amount).times(line.quantity || 1).toString()
1008
+ },
1009
+ {
1010
+ key: SCRIPT_CODE_AMOUNT_KEY,
1011
+ value: new Decimal2(coupon.amount).times(line.quantity || 1).toString()
1058
1012
  }
1059
- const resultCart = await createCart(client, {
1060
- lines,
1061
- metafieldIdentifiers,
1062
- cookieAdapter: cartCookieAdapter,
1063
- buyerIdentity,
1064
- discountCodes,
1065
- customAttributes
1066
- });
1067
- if (!resultCart) {
1068
- throw new Error("Failed to create cart for buy now");
1069
- }
1070
- if (withTrack && resultCart.lineItems) {
1071
- trackBuyNowGA({
1072
- lineItems,
1073
- gtmParams: { ...gtmParams, brand: config.getBrand() }
1074
- });
1075
- if (fbqTrackConfig) {
1076
- trackBuyNowFBQ({ trackConfig: fbqTrackConfig });
1077
- }
1078
- }
1079
- if (redirectToCheckout) {
1080
- if (resultCart.url) {
1081
- if (typeof window !== "undefined") {
1082
- window.location.href = resultCart.url;
1083
- }
1084
- } else {
1085
- throw new Error("Failed to get checkout URL");
1086
- }
1087
- }
1088
- return resultCart;
1089
- },
1090
- [client, locale, isLoggedIn, cartCookieAdapter, withTrack]
1091
- );
1092
- return useSWRMutation("buy-now", buyNow, swrOptions);
1093
- }
1013
+ ]);
1014
+ }
1015
+ return { ...line, attributes: itemAttributes };
1016
+ };
1017
+ var getLinesWithAttributes = ({
1018
+ cart,
1019
+ lineItems
1020
+ }) => {
1021
+ return lineItems.map((line) => {
1022
+ const sameLine = initSameLinesAttributes({ cart, line });
1023
+ const functionLine = initDiscountAttributes({ line: sameLine });
1024
+ return functionLine;
1025
+ });
1026
+ };
1094
1027
  function useCalcGiftsFromLines({
1095
1028
  lines,
1096
1029
  customer,
@@ -1107,30 +1040,55 @@ function useCalcGiftsFromLines({
1107
1040
  lines
1108
1041
  });
1109
1042
  const allGiftLines = useMemo(() => {
1110
- const functionGiftLines = functionGift.qualifyingGift?.itemsToAdd || [];
1111
- const scriptGiftLines = scriptGift.freeGiftLevel ? scriptGift.freeGiftLevel.giveawayProducts.map((product) => {
1112
- const giftProduct = scriptGift.giftProductsResult?.find(
1113
- (p) => p.handle === product.handle
1043
+ const functionGiftLines = (functionGift.qualifyingGift?.itemsToAdd || []).map((item) => {
1044
+ const product = functionGift.giftProductsResult?.find(
1045
+ (product2) => product2.handle === item.variant.handle
1046
+ );
1047
+ const variants = product?.variants;
1048
+ const variant = Array.isArray(variants) ? variants.find((v) => v.sku === item.variant.sku) : void 0;
1049
+ if (!variant) {
1050
+ console.warn(
1051
+ `Function gift: Variant not found for handle=${item.variant.handle}, sku=${item.variant.sku}`
1052
+ );
1053
+ return null;
1054
+ }
1055
+ return {
1056
+ variant: {
1057
+ ...variant,
1058
+ product
1059
+ },
1060
+ quantity: item.quantity ?? 1,
1061
+ attributes: item.attributes
1062
+ };
1063
+ }).filter((item) => item !== null);
1064
+ const scriptGiftLines = scriptGift.freeGiftLevel ? scriptGift.freeGiftLevel.giveawayProducts.map((item) => {
1065
+ const product = scriptGift.giftProductsResult?.find(
1066
+ (product2) => product2.handle === item.handle
1114
1067
  );
1115
- const variant = giftProduct?.variants?.[0];
1068
+ const variants = product?.variants;
1069
+ const variant = Array.isArray(variants) ? variants.find((v) => v.sku === item.sku) : void 0;
1070
+ if (!variant) {
1071
+ console.warn(`Script gift: Variant not found for handle=${item.handle}, sku=${item.sku}`);
1072
+ return null;
1073
+ }
1116
1074
  return {
1117
1075
  variant: {
1118
- id: variant?.id || "",
1119
- handle: product.handle,
1120
- sku: product.sku
1076
+ ...variant,
1077
+ product
1121
1078
  },
1122
1079
  quantity: 1,
1123
1080
  attributes: [
1124
1081
  {
1125
1082
  key: scriptGiveawayKey,
1126
- value: "true"
1083
+ value: scriptGiveawayKey
1127
1084
  }
1128
1085
  ]
1129
1086
  };
1130
- }).filter((item) => item.variant.id) : [];
1087
+ }).filter((item) => item !== null) : [];
1131
1088
  return [...functionGiftLines, ...scriptGiftLines];
1132
1089
  }, [
1133
1090
  functionGift.qualifyingGift,
1091
+ functionGift.giftProductsResult,
1134
1092
  scriptGift.freeGiftLevel,
1135
1093
  scriptGift.giftProductsResult,
1136
1094
  scriptGiveawayKey
@@ -1165,7 +1123,7 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1165
1123
  const isCustomerLoading = useMemo(() => !customer ? true : false, [customer]);
1166
1124
  const dealsType = "";
1167
1125
  const { activeCampaign, subtotal } = useMemo(() => {
1168
- for (const campaign of orderDiscountConfig) {
1126
+ for (const campaign of orderDiscountConfig || []) {
1169
1127
  const { rule_conditions = [], result_detail } = campaign;
1170
1128
  const { main_product, order_discount_conf } = result_detail || {};
1171
1129
  const isPreCheckPassed = preCheck(rule_conditions, tags, []);
@@ -1195,9 +1153,12 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1195
1153
  discountAmount: 0
1196
1154
  };
1197
1155
  }
1198
- const tieredDiscounts = activeCampaign.result_detail.order_discount_conf.tiered_discounts;
1199
- const qualifyingTier = [...tieredDiscounts].reverse().find((tier) => subtotal >= Number(tier.amount));
1200
- const nextGoal = tieredDiscounts.find((tier) => subtotal < Number(tier.amount));
1156
+ const currentCurrency = cart?.currency?.code || "";
1157
+ console.log("currentCurrency", cart, currentCurrency);
1158
+ const orderDiscountConf = activeCampaign.result_detail.order_discount_conf;
1159
+ const tieredDiscounts = orderDiscountConf.tiered_discounts_markets?.[currentCurrency] || orderDiscountConf.tiered_discounts;
1160
+ const qualifyingTier = [...tieredDiscounts].sort((a, b) => Number(b.amount) - Number(a.amount)).find((tier) => subtotal >= Number(tier.amount));
1161
+ const nextGoal = [...tieredDiscounts].sort((a, b) => Number(a.amount) - Number(b.amount)).find((tier) => subtotal < Number(tier.amount));
1201
1162
  if (!qualifyingTier) {
1202
1163
  return {
1203
1164
  qualifyingDiscount: null,
@@ -1234,43 +1195,10 @@ var useCalcOrderDiscount = (cart, orderDiscountConfig, customer) => {
1234
1195
  isLoading: isCustomerLoading
1235
1196
  };
1236
1197
  };
1237
- function useHasPlusMemberInCart({
1238
- memberSetting,
1239
- cart
1240
- }) {
1241
- const { plus_monthly_product, plus_annual_product } = memberSetting || {};
1242
- return useMemo(() => {
1243
- if (!cart?.lineItems) {
1244
- return {
1245
- hasPlusMember: false,
1246
- hasMonthlyPlus: false,
1247
- hasAnnualPlus: false
1248
- };
1249
- }
1250
- const monthlyPlusItem = cart.lineItems.find(
1251
- (item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
1252
- );
1253
- const annualPlusItem = cart.lineItems.find(
1254
- (item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
1255
- );
1256
- const hasMonthlyPlus = !!monthlyPlusItem;
1257
- const hasAnnualPlus = !!annualPlusItem;
1258
- const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
1259
- return {
1260
- hasPlusMember,
1261
- hasMonthlyPlus,
1262
- hasAnnualPlus,
1263
- monthlyPlusItem,
1264
- annualPlusItem
1265
- };
1266
- }, [cart?.lineItems, plus_monthly_product, plus_annual_product]);
1267
- }
1268
-
1269
- // src/hooks/cart/feature/use-cart-attributes.ts
1270
1198
  var getReferralAttributes = () => {
1271
- const inviteCode = Cookies5.get("invite_code");
1272
- const playModeId = Cookies5.get("playModeId");
1273
- const popup = Cookies5.get("_popup");
1199
+ const inviteCode = getLocalStorage("inviteCode") || Cookies5.get("inviteCode");
1200
+ const playModeId = getLocalStorage("playModeId") || Cookies5.get("playModeId");
1201
+ const popup = getLocalStorage("_popup") || Cookies5.get("_popup");
1274
1202
  if (inviteCode && playModeId) {
1275
1203
  return popup ? [
1276
1204
  { key: "_invite_code", value: inviteCode ? inviteCode : "" },
@@ -1283,121 +1211,130 @@ var getReferralAttributes = () => {
1283
1211
  }
1284
1212
  return [];
1285
1213
  };
1214
+ var getUserType = (customer) => {
1215
+ let userInfo = Cookies5.get("userInfo");
1216
+ if (userInfo) {
1217
+ userInfo = JSON.parse(userInfo);
1218
+ let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
1219
+ userInfo.setId = arr[arr.length - 1];
1220
+ }
1221
+ const customerInfo = userInfo || customer;
1222
+ if (!customerInfo) {
1223
+ return "new_user_unlogin";
1224
+ }
1225
+ if (customer) {
1226
+ const { orders = {} } = customer;
1227
+ if (orders?.edges?.length === 1) {
1228
+ return "old_user_orders_once";
1229
+ } else if (orders?.edges?.length > 1) {
1230
+ return "old_user_orders_twice";
1231
+ }
1232
+ }
1233
+ return "new_user_login";
1234
+ };
1235
+ function getCartAttributes({
1236
+ profile,
1237
+ customer,
1238
+ cart,
1239
+ memberType,
1240
+ currentUrl = ""
1241
+ }) {
1242
+ const userType = getUserType(customer);
1243
+ const memberAttributes = [
1244
+ {
1245
+ key: "_token",
1246
+ value: profile?.token
1247
+ },
1248
+ {
1249
+ key: "_member_type",
1250
+ value: memberType ?? String(profile?.memberType ?? 0)
1251
+ },
1252
+ {
1253
+ key: "_user_type",
1254
+ value: userType
1255
+ },
1256
+ {
1257
+ key: "_is_login",
1258
+ value: profile?.token ? "true" : "false"
1259
+ }
1260
+ ];
1261
+ if (profile?.token) {
1262
+ memberAttributes.push({
1263
+ key: "_login_user",
1264
+ value: "1"
1265
+ });
1266
+ }
1267
+ const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
1268
+ const functionAttributes = [
1269
+ {
1270
+ key: CUSTOMER_ATTRIBUTE_KEY,
1271
+ value: JSON.stringify({
1272
+ discount_code: discountCodes,
1273
+ user_tags: customer?.tags || []
1274
+ })
1275
+ }
1276
+ ];
1277
+ const presellAttributes = [
1278
+ {
1279
+ key: "_presale",
1280
+ value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
1281
+ }
1282
+ ];
1283
+ const weightAttributes = [
1284
+ {
1285
+ key: "_weight",
1286
+ value: cart?.lineItems.reduce((acc, item) => {
1287
+ return new Decimal2(acc).plus(item.variant.weight ?? 0).toNumber();
1288
+ }, 0).toString()
1289
+ },
1290
+ {
1291
+ key: "_app_source_name",
1292
+ value: "dtc"
1293
+ }
1294
+ ];
1295
+ const trackingAttributes = [
1296
+ {
1297
+ key: "utm_params",
1298
+ value: currentUrl
1299
+ }
1300
+ ];
1301
+ const commonAttributes = [
1302
+ ...memberAttributes,
1303
+ ...functionAttributes,
1304
+ ...presellAttributes,
1305
+ ...weightAttributes,
1306
+ ...trackingAttributes,
1307
+ ...getReferralAttributes()
1308
+ ].filter((item) => item?.value);
1309
+ const extraAttributesInCart = cart?.customAttributes?.filter(
1310
+ (item) => !commonAttributes.some((attr) => attr.key === item.key)
1311
+ ) || [];
1312
+ return [...commonAttributes, ...extraAttributesInCart].filter((item) => item?.value);
1313
+ }
1286
1314
  var useCartAttributes = ({
1287
1315
  profile,
1288
1316
  customer,
1289
1317
  cart,
1290
- memberSetting
1318
+ memberType
1291
1319
  }) => {
1292
1320
  const [currentUrl, setCurrentUrl] = useState("");
1293
- const { hasPlusMember } = useHasPlusMemberInCart({
1294
- memberSetting,
1295
- cart
1296
- });
1297
1321
  useEffect(() => {
1298
1322
  setCurrentUrl(window.location.href);
1299
1323
  }, []);
1300
- const userType = useMemo(() => {
1301
- let userInfo = Cookies5.get("userInfo");
1302
- if (userInfo) {
1303
- userInfo = JSON.parse(userInfo);
1304
- let arr = typeof userInfo?.id == "string" && userInfo?.id.split("/");
1305
- userInfo.setId = arr[arr.length - 1];
1306
- }
1307
- const customerInfo = userInfo || customer;
1308
- if (!customerInfo) {
1309
- return "new_user_unlogin";
1310
- }
1311
- if (customer) {
1312
- const { orders = {} } = customer;
1313
- if (orders?.edges?.length === 1) {
1314
- return "old_user_orders_once";
1315
- } else if (orders?.edges?.length > 1) {
1316
- return "old_user_orders_twice";
1317
- }
1318
- }
1319
- return "new_user_login";
1320
- }, [customer]);
1321
- const memberAttributes = useMemo(() => {
1322
- return [
1323
- {
1324
- key: "_token",
1325
- value: profile?.token
1326
- //是否登录
1327
- },
1328
- {
1329
- key: "_member_type",
1330
- value: hasPlusMember ? "2" : profile?.memberType
1331
- //:0(游客),1(普通会员),2(付费会员)
1332
- },
1333
- {
1334
- key: "_user_type",
1335
- value: userType
1336
- // n
1337
- },
1338
- {
1339
- key: "_is_login",
1340
- value: profile?.token ? "true" : "false"
1341
- }
1342
- ];
1343
- }, [profile?.memberType, profile?.token, userType, hasPlusMember]);
1344
- const functionAttributes = useMemo(() => {
1345
- const hasFunctionEnvAttribute = cart?.lineItems.some(
1346
- (item) => item.customAttributes?.some((attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY)
1347
- );
1348
- const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
1349
- return hasFunctionEnvAttribute ? [
1350
- {
1351
- key: "_discounts_function_env",
1352
- value: JSON.stringify({
1353
- discount_code: discountCodes,
1354
- user_tags: customer?.tags || []
1355
- })
1356
- }
1357
- ] : [];
1358
- }, [cart]);
1359
- const presellAttributes = useMemo(() => {
1360
- return [
1361
- {
1362
- key: "_presale",
1363
- value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
1364
- }
1365
- ];
1366
- }, [cart]);
1367
- const weightAttributes = useMemo(() => {
1368
- return [
1369
- {
1370
- key: "_weight",
1371
- value: cart?.lineItems.reduce((acc, item) => {
1372
- return new Decimal2(acc).plus(item.variant.weight ?? 0).toNumber();
1373
- }, 0).toString()
1374
- },
1375
- {
1376
- key: "_app_source_name",
1377
- value: "dtc"
1378
- }
1379
- ];
1380
- }, [cart]);
1381
- const trackingAttributes = useMemo(() => {
1382
- return [
1383
- {
1384
- key: "utm_params",
1385
- value: currentUrl
1386
- }
1387
- ];
1388
- }, [currentUrl]);
1324
+ const attributes = useMemo(() => {
1325
+ return getCartAttributes({
1326
+ profile,
1327
+ customer,
1328
+ cart,
1329
+ memberType,
1330
+ currentUrl
1331
+ });
1332
+ }, [profile, customer, cart, memberType, currentUrl]);
1389
1333
  return useMemo(
1390
1334
  () => ({
1391
- attributes: [
1392
- ...memberAttributes,
1393
- ...functionAttributes,
1394
- ...presellAttributes,
1395
- ...weightAttributes,
1396
- ...trackingAttributes,
1397
- ...getReferralAttributes()
1398
- ].filter((item) => item?.value)
1335
+ attributes
1399
1336
  }),
1400
- [memberAttributes, functionAttributes, presellAttributes, weightAttributes, trackingAttributes]
1337
+ [attributes]
1401
1338
  );
1402
1339
  };
1403
1340
  var DEFAULT_MIN = 1;
@@ -1460,7 +1397,7 @@ var useUpdateLineCodeAmountAttributes = ({
1460
1397
  );
1461
1398
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
1462
1399
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
1463
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute) {
1400
+ if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
1464
1401
  attrNeedUpdate.push({
1465
1402
  key: CUSTOMER_ATTRIBUTE_KEY,
1466
1403
  value: JSON.stringify({
@@ -1499,29 +1436,22 @@ var useUpdateLineCodeAmountAttributes = ({
1499
1436
  }).filter(
1500
1437
  ({ attrNeedUpdate, attrNeedDelete }) => attrNeedUpdate.length || attrNeedDelete.length
1501
1438
  ).map(({ line, attrNeedUpdate, attrNeedDelete }) => {
1439
+ let lineId = line.id;
1440
+ let attributes = line.customAttributes || [];
1441
+ if (attrNeedDelete.length) {
1442
+ attributes = attributes.filter(
1443
+ (attr) => !attrNeedDelete.includes(attr.key)
1444
+ );
1445
+ }
1502
1446
  if (attrNeedUpdate.length) {
1503
- return {
1504
- id: line.id,
1505
- attributes: [
1506
- ...line.customAttributes?.filter(
1507
- (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
1508
- ) || [],
1509
- ...attrNeedUpdate
1510
- ]
1511
- };
1512
- } else if (attrNeedDelete.length) {
1513
- return {
1514
- id: line.id,
1515
- attributes: line.customAttributes?.filter(
1516
- (attr) => !attrNeedDelete.includes(attr.key)
1517
- ) || []
1518
- };
1519
- } else {
1520
- return {
1521
- id: line.id,
1522
- attributes: line.customAttributes || []
1523
- };
1447
+ attributes = attributes.filter(
1448
+ (attr) => !attrNeedUpdate.some((updateAttr) => updateAttr.key === attr.key)
1449
+ ).concat(attrNeedUpdate);
1524
1450
  }
1451
+ return {
1452
+ id: lineId,
1453
+ attributes
1454
+ };
1525
1455
  }),
1526
1456
  [cart?.lineItems, mainProductDiscountCodes]
1527
1457
  );
@@ -1556,45 +1486,61 @@ var useUpdateLineCodeAmountAttributes = ({
1556
1486
  }, [loading, setLoadingState]);
1557
1487
  };
1558
1488
 
1559
- // src/hooks/cart/types/price-discount.ts
1560
- var PriceDiscountType = /* @__PURE__ */ ((PriceDiscountType2) => {
1561
- PriceDiscountType2[PriceDiscountType2["PERCENTAGE"] = 1] = "PERCENTAGE";
1562
- PriceDiscountType2[PriceDiscountType2["FIXED_AMOUNT"] = 2] = "FIXED_AMOUNT";
1563
- return PriceDiscountType2;
1564
- })(PriceDiscountType || {});
1565
- var PriceBasePriceType = /* @__PURE__ */ ((PriceBasePriceType2) => {
1566
- PriceBasePriceType2[PriceBasePriceType2["MIN_DISCOUNTED_PRICE"] = 1] = "MIN_DISCOUNTED_PRICE";
1567
- PriceBasePriceType2[PriceBasePriceType2["MIN_TOTAL_PRICE"] = 2] = "MIN_TOTAL_PRICE";
1568
- return PriceBasePriceType2;
1569
- })(PriceBasePriceType || {});
1570
- function useProduct(options = {}) {
1571
- const { client, locale } = useShopify();
1572
- const { handle, metafieldIdentifiers, ...swrOptions } = options;
1573
- return useSWR(
1574
- handle ? ["product", locale, handle, metafieldIdentifiers] : null,
1575
- () => getProduct(client, {
1576
- handle,
1577
- locale,
1578
- metafieldIdentifiers
1579
- }),
1580
- swrOptions
1581
- );
1582
- }
1583
- function useAllProducts(options = {}) {
1584
- const { client, locale } = useShopify();
1585
- const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
1586
- return useSWR(
1587
- ["all-products", locale, first, query, sortKey, reverse, metafieldIdentifiers],
1588
- () => getAllProducts(client, {
1589
- locale,
1590
- first,
1591
- query,
1592
- sortKey,
1593
- reverse,
1594
- metafieldIdentifiers
1595
- }),
1596
- swrOptions
1597
- );
1489
+ // src/hooks/member/plus/types.ts
1490
+ var PLUS_MEMBER_TYPE = /* @__PURE__ */ ((PLUS_MEMBER_TYPE2) => {
1491
+ PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["FREE"] = 0] = "FREE";
1492
+ PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["MONTHLY"] = 1] = "MONTHLY";
1493
+ PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["ANNUAL"] = 2] = "ANNUAL";
1494
+ return PLUS_MEMBER_TYPE2;
1495
+ })(PLUS_MEMBER_TYPE || {});
1496
+ var PlusMemberMode = /* @__PURE__ */ ((PlusMemberMode2) => {
1497
+ PlusMemberMode2["MONTHLY"] = "monthly";
1498
+ PlusMemberMode2["ANNUAL"] = "annual";
1499
+ return PlusMemberMode2;
1500
+ })(PlusMemberMode || {});
1501
+ var DeliveryPlusType = /* @__PURE__ */ ((DeliveryPlusType2) => {
1502
+ DeliveryPlusType2["FREE"] = "free";
1503
+ DeliveryPlusType2["MONTHLY"] = "monthly";
1504
+ DeliveryPlusType2["ANNUAL"] = "annual";
1505
+ return DeliveryPlusType2;
1506
+ })(DeliveryPlusType || {});
1507
+ var ShippingMethodMode = /* @__PURE__ */ ((ShippingMethodMode2) => {
1508
+ ShippingMethodMode2["FREE"] = "free";
1509
+ ShippingMethodMode2["TDD"] = "tdd";
1510
+ ShippingMethodMode2["NDD"] = "ndd";
1511
+ return ShippingMethodMode2;
1512
+ })(ShippingMethodMode || {});
1513
+ var createInitialValue = () => ({
1514
+ plusMemberMetafields: {},
1515
+ selectedPlusMemberMode: "free",
1516
+ setSelectedPlusMemberMode: () => {
1517
+ },
1518
+ selectedShippingMethod: void 0,
1519
+ setSelectedShippingMethod: () => {
1520
+ },
1521
+ showMoreShippingMethod: false,
1522
+ setShowMoreShippingMethod: () => {
1523
+ },
1524
+ variant: {},
1525
+ product: {},
1526
+ shippingMethodsContext: {
1527
+ freeShippingMethods: [],
1528
+ paymentShippingMethods: [],
1529
+ nddOverweight: false,
1530
+ tddOverweight: false,
1531
+ nddCoupon: void 0,
1532
+ tddCoupon: void 0,
1533
+ isLoadingCoupon: false
1534
+ },
1535
+ selectedPlusMemberVariant: void 0,
1536
+ showPlusMemberBenefit: false,
1537
+ setShowPlusMemberBenefit: () => {
1538
+ },
1539
+ profile: void 0
1540
+ });
1541
+ var PlusMemberContext = createContext(createInitialValue());
1542
+ function usePlusMemberContext() {
1543
+ return useContext(PlusMemberContext);
1598
1544
  }
1599
1545
  function useProductsByHandles(options = {}) {
1600
1546
  const { client, locale } = useShopify();
@@ -1614,1213 +1560,1349 @@ function useProductsByHandles(options = {}) {
1614
1560
  metafieldIdentifiers
1615
1561
  });
1616
1562
  },
1617
- swrOptions || {
1618
- revalidateOnFocus: false
1563
+ {
1564
+ revalidateOnFocus: false,
1565
+ ...swrOptions
1619
1566
  }
1620
1567
  );
1621
1568
  }
1622
- function getFirstAvailableVariant(product) {
1623
- const availableVariant = product.variants.find((v) => v.availableForSale);
1624
- return availableVariant || product.variants[0];
1625
- }
1626
- function getVariantFromSelectedOptions(product, selectedOptions) {
1627
- return product.variants.find((variant) => {
1628
- return variant.selectedOptions.every((option) => {
1629
- return selectedOptions[option.name] === option.value;
1630
- });
1569
+
1570
+ // src/hooks/member/plus/use-plus-member-variants.ts
1571
+ function usePlusMemberVariants({
1572
+ memberSetting
1573
+ }) {
1574
+ const plusMonthly = memberSetting?.plus_monthly_product;
1575
+ const plusAnnual = memberSetting?.plus_annual_product;
1576
+ const plusMemberHandles = useMemo(() => {
1577
+ return [plusMonthly?.handle, plusAnnual?.handle].filter(Boolean);
1578
+ }, [plusMonthly?.handle, plusAnnual?.handle]);
1579
+ const { data: plusMemberProducts = [] } = useProductsByHandles({
1580
+ handles: plusMemberHandles
1631
1581
  });
1582
+ const monthlyProduct = useMemo(() => {
1583
+ return plusMemberProducts?.find((item) => item?.handle === plusMonthly?.handle);
1584
+ }, [plusMemberProducts, plusMonthly]);
1585
+ const annualProduct = useMemo(() => {
1586
+ return plusMemberProducts?.find((item) => item?.handle === plusAnnual?.handle);
1587
+ }, [plusMemberProducts, plusAnnual]);
1588
+ const monthlyVariant = useMemo(() => {
1589
+ return monthlyProduct?.variants?.find((item) => item.sku === plusMonthly?.sku);
1590
+ }, [monthlyProduct, plusMonthly]);
1591
+ const annualVariant = useMemo(() => {
1592
+ return annualProduct?.variants?.find((item) => item.sku === plusAnnual?.sku);
1593
+ }, [annualProduct, plusAnnual]);
1594
+ return {
1595
+ monthlyVariant: monthlyVariant ? {
1596
+ ...monthlyVariant,
1597
+ product: monthlyProduct
1598
+ } : void 0,
1599
+ annualVariant: annualVariant ? {
1600
+ ...annualVariant,
1601
+ product: annualProduct
1602
+ } : void 0
1603
+ };
1632
1604
  }
1633
- function useVariant({
1634
- product,
1635
- selectedOptions
1636
- }) {
1637
- const [variant, setVariant] = useState(
1638
- product ? getFirstAvailableVariant(product) : void 0
1639
- );
1640
- useEffect(() => {
1641
- if (!product) {
1642
- setVariant(void 0);
1643
- return;
1644
- }
1645
- const newVariant = getVariantFromSelectedOptions(product, selectedOptions);
1646
- if (newVariant && newVariant.id !== variant?.id) {
1647
- setVariant(newVariant);
1648
- } else if (!newVariant) {
1649
- setVariant(getFirstAvailableVariant(product));
1605
+ var useAvailableDeliveryCoupon = ({
1606
+ profile
1607
+ }) => {
1608
+ const { data: availableDeliveryCoupon, isLoading } = useSWR(
1609
+ profile?.email ? ["/api/multipass/subsrv/v1/prime/delivery_coupons/current/available", profile?.email] : void 0,
1610
+ async ([apiPath]) => {
1611
+ return fetch(apiPath).then((res) => res.json());
1650
1612
  }
1651
- }, [selectedOptions, product, variant?.id]);
1652
- return variant;
1653
- }
1654
- var FAKE_PRICE = 999999999e-2;
1655
- function formatPrice({
1656
- amount,
1657
- currencyCode,
1658
- locale,
1659
- maximumFractionDigits,
1660
- minimumFractionDigits,
1661
- removeTrailingZeros
1662
- }) {
1663
- const formatter = new Intl.NumberFormat(locale, {
1664
- style: "currency",
1665
- currency: currencyCode,
1666
- maximumFractionDigits: maximumFractionDigits ?? 2,
1667
- minimumFractionDigits: minimumFractionDigits ?? 2
1668
- });
1669
- let formatted = formatter.format(amount);
1670
- if (removeTrailingZeros) {
1671
- formatted = formatted.replace(/\.00$/, "");
1672
- }
1673
- return formatted;
1674
- }
1675
- function formatVariantPrice({
1676
- amount,
1677
- baseAmount,
1678
- currencyCode,
1679
- locale,
1680
- maximumFractionDigits,
1681
- minimumFractionDigits,
1682
- removeTrailingZeros
1683
- }) {
1613
+ );
1614
+ console.log("availableDeliveryCoupon", availableDeliveryCoupon);
1615
+ const { ndd_coupon: nddCoupon, tdd_coupon: tddCoupon } = availableDeliveryCoupon?.data?.data || {};
1684
1616
  return {
1685
- price: formatPrice({
1686
- amount,
1687
- currencyCode,
1688
- locale,
1689
- maximumFractionDigits,
1690
- minimumFractionDigits,
1691
- removeTrailingZeros
1692
- }),
1693
- basePrice: formatPrice({
1694
- amount: baseAmount,
1695
- currencyCode,
1696
- locale,
1697
- maximumFractionDigits,
1698
- minimumFractionDigits,
1699
- removeTrailingZeros
1700
- })
1617
+ nddCoupon,
1618
+ tddCoupon,
1619
+ isLoading
1701
1620
  };
1702
- }
1703
- function usePrice({
1704
- amount,
1705
- baseAmount,
1706
- currencyCode,
1707
- soldOutDescription = "",
1708
- maximumFractionDigits,
1709
- minimumFractionDigits,
1710
- removeTrailingZeros
1711
- }) {
1712
- const { locale } = useShopify();
1713
- const value = useMemo(() => {
1714
- if (typeof amount !== "number" || !currencyCode) {
1715
- return "";
1716
- }
1717
- if (soldOutDescription && amount >= FAKE_PRICE) {
1718
- return soldOutDescription;
1719
- }
1720
- return baseAmount ? formatVariantPrice({
1721
- amount,
1722
- baseAmount,
1723
- currencyCode,
1724
- locale,
1725
- maximumFractionDigits,
1726
- minimumFractionDigits,
1727
- removeTrailingZeros
1728
- }) : formatPrice({
1729
- amount,
1730
- currencyCode,
1731
- locale,
1732
- maximumFractionDigits,
1733
- minimumFractionDigits,
1734
- removeTrailingZeros
1621
+ };
1622
+
1623
+ // src/hooks/member/plus/use-shipping-methods.ts
1624
+ function useShippingMethods(options) {
1625
+ const { variant, plusMemberMetafields, selectedPlusMemberMode, profile } = options;
1626
+ const isPlus = profile?.isPlus || false;
1627
+ const { nddCoupon, tddCoupon, isLoading } = useAvailableDeliveryCoupon({ profile });
1628
+ const { plus_shipping, shippingMethod } = plusMemberMetafields || {};
1629
+ const nddOverweight = useMemo(() => {
1630
+ return (variant?.weight || 0) > (shippingMethod?.overWeight_ndd || Infinity);
1631
+ }, [shippingMethod?.overWeight_ndd, variant?.weight]);
1632
+ const tddOverweight = useMemo(() => {
1633
+ return (variant?.weight || 0) > (shippingMethod?.overWeight_tdd || Infinity);
1634
+ }, [shippingMethod?.overWeight_tdd, variant?.weight]);
1635
+ const paymentShippingMethods = useMemo(() => {
1636
+ const weight = variant?.weight || 0;
1637
+ const methods = plus_shipping?.shipping_methods?.filter(({ weight_low, weight_high, __mode, __plus }) => {
1638
+ const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
1639
+ return __mode !== "free" /* FREE */ && !__plus && fitWeight;
1640
+ }) || [];
1641
+ return methods.map((method) => {
1642
+ let disabled = false;
1643
+ const selectedFreeMember = selectedPlusMemberMode === "free";
1644
+ if (method.__mode === "ndd" /* NDD */) {
1645
+ disabled = selectedFreeMember || nddOverweight;
1646
+ } else if (method.__mode === "tdd" /* TDD */) {
1647
+ disabled = selectedFreeMember || tddOverweight;
1648
+ }
1649
+ return {
1650
+ ...method,
1651
+ id: method.__mode + method.__code,
1652
+ useCoupon: false,
1653
+ subtitle: plus_shipping?.directly || "",
1654
+ disabled
1655
+ };
1735
1656
  });
1736
1657
  }, [
1737
- amount,
1738
- baseAmount,
1739
- currencyCode,
1740
- locale,
1741
- maximumFractionDigits,
1742
- minimumFractionDigits,
1743
- soldOutDescription,
1744
- removeTrailingZeros
1658
+ nddOverweight,
1659
+ plus_shipping?.directly,
1660
+ plus_shipping?.shipping_methods,
1661
+ selectedPlusMemberMode,
1662
+ tddOverweight,
1663
+ variant?.weight
1745
1664
  ]);
1746
- const result = useMemo(() => {
1747
- const free = Boolean(amount && amount <= 0);
1748
- return typeof value === "string" ? { price: value, basePrice: value, free } : { ...value, free };
1749
- }, [value, amount]);
1750
- return result;
1751
- }
1752
- function optionsConstructor(selectedOptions) {
1753
- return selectedOptions.reduce((acc, option) => {
1754
- acc[option.name] = option.value;
1755
- return acc;
1756
- }, {});
1757
- }
1758
- function decodeShopifyId(gid) {
1759
- try {
1760
- const base64 = gid.split("/").pop() || "";
1761
- return atob(base64);
1762
- } catch {
1763
- return gid;
1764
- }
1765
- }
1766
- function useSelectedOptions(product, sku) {
1767
- const [options, setOptions] = useState({});
1768
- useEffect(() => {
1769
- if (!product || !product.variants.length) {
1770
- setOptions({});
1771
- return;
1772
- }
1773
- let variant = product.variants[0];
1774
- if (typeof window !== "undefined") {
1775
- const searchParams = new URLSearchParams(window.location.search);
1776
- const variantIdParam = searchParams.get("variant");
1777
- if (variantIdParam) {
1778
- const foundVariant = product.variants.find((v) => {
1779
- if (sku) return v.sku === sku;
1780
- return v.id === variantIdParam || v.id.includes(variantIdParam) || decodeShopifyId(v.id) === variantIdParam;
1781
- });
1782
- if (foundVariant) {
1783
- variant = foundVariant;
1784
- }
1665
+ const nddPrice = useMemo(() => {
1666
+ const weight = variant?.weight || 0;
1667
+ const nddMethod = paymentShippingMethods.find(({ __mode, weight_high, weight_low }) => {
1668
+ const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
1669
+ return __mode === "ndd" && fitWeight;
1670
+ });
1671
+ return nddMethod?.price || 0;
1672
+ }, [variant?.weight, paymentShippingMethods]);
1673
+ const tddPrice = useMemo(() => {
1674
+ const weight = variant?.weight || 0;
1675
+ const tddMethod = paymentShippingMethods.find(({ __mode, weight_high, weight_low }) => {
1676
+ const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
1677
+ return __mode === "tdd" && fitWeight;
1678
+ });
1679
+ return tddMethod?.price || 0;
1680
+ }, [variant?.weight, paymentShippingMethods]);
1681
+ const freeShippingMethods = useMemo(() => {
1682
+ const weight = variant?.weight || 0;
1683
+ let methods = plus_shipping?.shipping_methods?.filter(({ __mode, __plus, weight_low, weight_high }) => {
1684
+ if (__mode === "free" /* FREE */) {
1685
+ return true;
1785
1686
  }
1687
+ if (isPlus) {
1688
+ const hasCoupon = isPlus && __mode === "ndd" /* NDD */ && nddCoupon || isPlus && __mode === "tdd" /* TDD */ && (tddCoupon || nddCoupon);
1689
+ const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
1690
+ return hasCoupon && fitWeight && !__plus;
1691
+ } else {
1692
+ return __plus;
1693
+ }
1694
+ }) || [];
1695
+ if (isPlus) {
1696
+ methods = methods.sort((a, b) => {
1697
+ if (b.__mode === "free" /* FREE */) return -1;
1698
+ return 0;
1699
+ });
1786
1700
  }
1787
- if (variant) {
1788
- const newOptions = optionsConstructor(variant.selectedOptions);
1789
- setOptions(newOptions);
1790
- }
1791
- }, [product, sku]);
1792
- return [options, setOptions];
1793
- }
1794
- function decodeShopifyId2(gid) {
1795
- try {
1796
- const parts = gid.split("/");
1797
- return parts[parts.length - 1] || gid;
1798
- } catch {
1799
- return gid;
1800
- }
1801
- }
1802
- function useProductUrl(otherQuery) {
1803
- const { routerAdapter } = useShopify();
1804
- return useCallback(
1805
- ({ product, variant }) => {
1806
- if (!product) return "";
1807
- const queryParams = new URLSearchParams();
1808
- if (variant?.id) {
1809
- const variantId = decodeShopifyId2(variant.id);
1810
- if (variantId) {
1811
- queryParams.set("variant", variantId);
1701
+ return methods.map((method) => {
1702
+ let price = 0;
1703
+ let coupon;
1704
+ let disabled;
1705
+ if (method.__mode !== "free" /* FREE */) {
1706
+ switch (method.__mode) {
1707
+ case "tdd":
1708
+ price = tddPrice;
1709
+ coupon = tddCoupon || nddCoupon;
1710
+ break;
1711
+ case "ndd":
1712
+ price = nddPrice;
1713
+ coupon = nddCoupon;
1714
+ break;
1715
+ }
1716
+ disabled = selectedPlusMemberMode === "free";
1717
+ if (method.__mode === "ndd" /* NDD */) {
1718
+ disabled = disabled || nddOverweight;
1719
+ } else if (method.__mode === "tdd" /* TDD */) {
1720
+ disabled = disabled || tddOverweight;
1812
1721
  }
1813
1722
  }
1814
- if (otherQuery) {
1815
- Object.entries(otherQuery).forEach(([key, value]) => {
1816
- queryParams.set(key, value);
1817
- });
1723
+ return {
1724
+ ...method,
1725
+ id: method.__mode + method.__code,
1726
+ useCoupon: true,
1727
+ disabled,
1728
+ coupon,
1729
+ price
1730
+ };
1731
+ });
1732
+ }, [
1733
+ variant?.weight,
1734
+ plus_shipping?.shipping_methods,
1735
+ isPlus,
1736
+ nddCoupon,
1737
+ tddCoupon,
1738
+ selectedPlusMemberMode,
1739
+ tddPrice,
1740
+ nddPrice,
1741
+ nddOverweight,
1742
+ tddOverweight
1743
+ ]);
1744
+ return {
1745
+ freeShippingMethods,
1746
+ paymentShippingMethods,
1747
+ nddOverweight,
1748
+ tddOverweight,
1749
+ nddCoupon,
1750
+ tddCoupon,
1751
+ isLoadingCoupon: isLoading
1752
+ };
1753
+ }
1754
+ var useReplaceCartPlusMember = () => {
1755
+ const { plusMemberMetafields, selectedPlusMemberMode } = usePlusMemberContext();
1756
+ const { trigger: removeCartLines2 } = useRemoveCartLines();
1757
+ const { cart } = useCartContext();
1758
+ const plusMonthly = plusMemberMetafields?.plus_monthly_product;
1759
+ const plusAnnual = plusMemberMetafields?.plus_annual_product;
1760
+ const handler = useCallback(async () => {
1761
+ const plusMonthlyInCart = cart?.lineItems.find(
1762
+ (item) => item.variant?.sku === plusMonthly?.sku
1763
+ );
1764
+ const plusAnnualInCart = cart?.lineItems.find(
1765
+ (item) => item.variant?.sku === plusAnnual?.sku
1766
+ );
1767
+ if (selectedPlusMemberMode === "annual" /* ANNUAL */ && plusMonthlyInCart) {
1768
+ await removeCartLines2({
1769
+ lineIds: [plusMonthlyInCart.id]
1770
+ });
1771
+ } else if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && plusAnnualInCart) {
1772
+ await removeCartLines2({
1773
+ lineIds: [plusAnnualInCart.id]
1774
+ });
1775
+ }
1776
+ }, [
1777
+ cart?.lineItems,
1778
+ selectedPlusMemberMode,
1779
+ plusMonthly?.sku,
1780
+ plusAnnual?.sku,
1781
+ removeCartLines2
1782
+ ]);
1783
+ return handler;
1784
+ };
1785
+ var usePlusMemberCheckoutCustomAttributes = ({
1786
+ disableShipping = false,
1787
+ isPresaleContains = false
1788
+ }) => {
1789
+ const { profile, selectedShippingMethod, selectedPlusMemberMode } = usePlusMemberContext();
1790
+ return useMemo(() => {
1791
+ const checkoutCustomAttributes = [
1792
+ {
1793
+ key: "_last_url",
1794
+ value: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
1818
1795
  }
1819
- const queryString = queryParams.toString();
1820
- const path = `/products/${product.handle}${queryString ? `?${queryString}` : ""}`;
1821
- if (routerAdapter?.getLocalizedPath) {
1822
- return routerAdapter.getLocalizedPath(path);
1796
+ ];
1797
+ checkoutCustomAttributes.push({
1798
+ key: "_checkout_delivery_custom",
1799
+ value: JSON.stringify({
1800
+ allow_nextday_delivery: true,
1801
+ allow_thirdday_delivery: true,
1802
+ selected_delivery_option: {
1803
+ code: selectedShippingMethod?.__code,
1804
+ mode: selectedShippingMethod?.__mode
1805
+ },
1806
+ is_presale: isPresaleContains,
1807
+ discount_code: selectedShippingMethod?.coupon ? [selectedShippingMethod.coupon] : [],
1808
+ plus_type: profile?.isPlus ? "free" /* FREE */ : selectedPlusMemberMode,
1809
+ is_prime: profile?.isPlus
1810
+ })
1811
+ });
1812
+ if (disableShipping) {
1813
+ checkoutCustomAttributes.push({
1814
+ key: "_hide_shipping",
1815
+ value: "true"
1816
+ });
1817
+ }
1818
+ return checkoutCustomAttributes;
1819
+ }, [profile, selectedShippingMethod, selectedPlusMemberMode, isPresaleContains]);
1820
+ };
1821
+ function useRemoveCartLines(options) {
1822
+ const { client, locale, cartCookieAdapter } = useShopify();
1823
+ const { mutateCart, metafieldIdentifiers } = useCartContext();
1824
+ const removeLines = useCallback(
1825
+ async (_key, { arg }) => {
1826
+ const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
1827
+ let updatedCart = await removeCartLines(client, {
1828
+ cartId,
1829
+ lineIds,
1830
+ metafieldIdentifiers,
1831
+ cookieAdapter: cartCookieAdapter
1832
+ });
1833
+ if (updatedCart && autoRemoveInvalidCodes) {
1834
+ const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
1835
+ if (unApplicableCodes.length > 0) {
1836
+ if (onCodesRemoved) {
1837
+ const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
1838
+ if (handledCart) {
1839
+ updatedCart = handledCart;
1840
+ }
1841
+ } else {
1842
+ updatedCart = await updateCartCodes(client, {
1843
+ cartId: updatedCart.id,
1844
+ discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
1845
+ metafieldIdentifiers,
1846
+ cookieAdapter: cartCookieAdapter
1847
+ }) || updatedCart;
1848
+ }
1849
+ }
1823
1850
  }
1824
- return path;
1851
+ if (updatedCart) {
1852
+ mutateCart(updatedCart);
1853
+ }
1854
+ return updatedCart;
1825
1855
  },
1826
- [routerAdapter, otherQuery]
1856
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
1827
1857
  );
1858
+ return useSWRMutation("remove-cart-lines", removeLines, options);
1828
1859
  }
1829
- function decodeShopifyId3(gid) {
1830
- try {
1831
- const parts = gid.split("/");
1832
- return parts[parts.length - 1] || gid;
1833
- } catch {
1834
- return gid;
1835
- }
1836
- }
1837
- function useUpdateVariantQuery(variant) {
1860
+
1861
+ // src/hooks/member/plus/use-auto-remove-plus-member-in-cart.ts
1862
+ function useAutoRemovePlusMemberInCart({
1863
+ cart,
1864
+ profile,
1865
+ memberSetting
1866
+ }) {
1867
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
1868
+ const { trigger: removeCartLines2 } = useRemoveCartLines();
1838
1869
  useEffect(() => {
1839
- if (!variant || typeof window === "undefined") {
1840
- return;
1870
+ if (!cart || !plus_monthly_product || !plus_annual_product) return;
1871
+ const removePlusProduct = async (productType) => {
1872
+ if (!productType) return;
1873
+ const product = cart.lineItems?.find(
1874
+ (item) => item.product?.handle === productType?.handle && item.variant?.sku === productType?.sku
1875
+ );
1876
+ if (product) {
1877
+ await removeCartLines2({
1878
+ lineIds: [product.id]
1879
+ });
1880
+ }
1881
+ };
1882
+ if (profile?.isMonthlyPlus) {
1883
+ removePlusProduct(plus_monthly_product);
1841
1884
  }
1842
- const searchParams = new URLSearchParams(window.location.search);
1843
- const currentVariantId = searchParams.get("variant");
1844
- const newVariantId = decodeShopifyId3(variant.id);
1845
- if (newVariantId && currentVariantId !== newVariantId) {
1846
- searchParams.set("variant", newVariantId);
1847
- const newUrl = `${window.location.pathname}?${searchParams.toString()}${window.location.hash}`;
1848
- window.history.replaceState({}, "", newUrl);
1885
+ if (profile?.isAnnualPlus) {
1886
+ removePlusProduct(plus_annual_product);
1849
1887
  }
1850
- }, [variant]);
1888
+ }, [cart, plus_annual_product, plus_monthly_product, profile, removeCartLines2]);
1851
1889
  }
1852
- function getVariantMediaList({
1853
- product,
1854
- variant
1890
+ function hasPlusMemberInCart({
1891
+ memberSetting,
1892
+ cart
1855
1893
  }) {
1856
- if (variant.image?.url) {
1857
- const variantMediaId = variant.image.url;
1858
- const variantMedia = product.media.filter((media) => {
1859
- if (media.mediaContentType === "IMAGE" && media.previewImage) {
1860
- return media.previewImage?.url === variantMediaId;
1861
- }
1862
- return false;
1863
- });
1864
- if (variantMedia.length > 0) {
1865
- const otherMedia = product.media.filter((media) => {
1866
- if (media.mediaContentType === "IMAGE" && media.previewImage) {
1867
- return media.previewImage.url !== variantMediaId;
1868
- }
1869
- return true;
1870
- });
1871
- return [...variantMedia, ...otherMedia];
1872
- }
1894
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
1895
+ if (!cart?.lineItems) {
1896
+ return {
1897
+ hasPlusMember: false,
1898
+ hasMonthlyPlus: false,
1899
+ hasAnnualPlus: false
1900
+ };
1873
1901
  }
1874
- return product.media;
1875
- }
1876
- function useVariantMedia({
1877
- product,
1878
- variant
1879
- }) {
1880
- const [imageList, setImageList] = useState([]);
1881
- const [sceneList, setSceneList] = useState([]);
1882
- const [videoList, setVideoList] = useState([]);
1883
- useEffect(() => {
1884
- if (!product || !variant) {
1885
- setImageList([]);
1886
- setSceneList([]);
1887
- setVideoList([]);
1888
- return;
1889
- }
1890
- const mediaList = getVariantMediaList({ product, variant });
1891
- const images = mediaList.filter((media) => media.mediaContentType === "IMAGE");
1892
- const videos = mediaList.filter(
1893
- (media) => media.mediaContentType === "VIDEO" || media.mediaContentType === "EXTERNAL_VIDEO"
1894
- );
1895
- setImageList(images.length > 0 && images[0] ? [images[0]] : []);
1896
- setSceneList(images.length > 1 ? images.slice(1) : []);
1897
- setVideoList(videos);
1898
- }, [product, variant]);
1899
- return {
1900
- productList: imageList,
1901
- sceneList,
1902
- videoList
1903
- };
1904
- }
1905
- function useCollection(options = {}) {
1906
- const { client, locale } = useShopify();
1907
- const { handle, metafieldIdentifiers, ...swrOptions } = options;
1908
- return useSWR(
1909
- handle ? ["collection", locale, handle, metafieldIdentifiers] : null,
1910
- () => getCollection(client, {
1911
- handle,
1912
- locale,
1913
- metafieldIdentifiers
1914
- }),
1915
- swrOptions
1916
- );
1917
- }
1918
- function useAllCollections(options = {}) {
1919
- const { client, locale } = useShopify();
1920
- const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
1921
- return useSWR(
1922
- ["all-collections", locale, first, query, sortKey, reverse, metafieldIdentifiers],
1923
- () => getAllCollections(client, {
1924
- locale,
1925
- first,
1926
- query,
1927
- sortKey,
1928
- reverse,
1929
- metafieldIdentifiers
1930
- }),
1931
- swrOptions
1932
- );
1933
- }
1934
- function useCollections(options = {}) {
1935
- const { client, locale } = useShopify();
1936
- const { first, after, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
1937
- return useSWR(
1938
- ["collections", locale, first, after, query, sortKey, reverse, metafieldIdentifiers],
1939
- () => getCollections(client, {
1940
- locale,
1941
- first,
1942
- after,
1943
- query,
1944
- sortKey,
1945
- reverse,
1946
- metafieldIdentifiers
1947
- }),
1948
- swrOptions
1902
+ const monthlyPlusItem = cart.lineItems.find(
1903
+ (item) => item.product?.handle === plus_monthly_product?.handle && item.variant?.sku === plus_monthly_product?.sku
1949
1904
  );
1950
- }
1951
- function useBlog(options = {}) {
1952
- const { client, locale } = useShopify();
1953
- const { handle, metafieldIdentifiers, ...swrOptions } = options;
1954
- return useSWR(
1955
- handle ? ["blog", locale, handle, metafieldIdentifiers] : null,
1956
- () => getBlog(client, { handle, locale, metafieldIdentifiers }),
1957
- swrOptions
1905
+ const annualPlusItem = cart.lineItems.find(
1906
+ (item) => item.product?.handle === plus_annual_product?.handle && item.variant?.sku === plus_annual_product?.sku
1958
1907
  );
1908
+ const hasMonthlyPlus = !!monthlyPlusItem;
1909
+ const hasAnnualPlus = !!annualPlusItem;
1910
+ const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
1911
+ return {
1912
+ hasPlusMember,
1913
+ hasMonthlyPlus,
1914
+ hasAnnualPlus,
1915
+ monthlyPlusItem,
1916
+ annualPlusItem
1917
+ };
1959
1918
  }
1960
- function useAllBlogs(options = {}) {
1961
- const { client, locale } = useShopify();
1962
- const { first, query, metafieldIdentifiers, ...swrOptions } = options;
1963
- return useSWR(
1964
- ["all-blogs", locale, first, query, metafieldIdentifiers],
1965
- () => getAllBlogs(client, {
1966
- locale,
1967
- first,
1968
- query,
1969
- metafieldIdentifiers
1919
+ function useHasPlusMemberInCart({
1920
+ memberSetting,
1921
+ cart
1922
+ }) {
1923
+ return useMemo(
1924
+ () => hasPlusMemberInCart({
1925
+ memberSetting,
1926
+ cart
1970
1927
  }),
1971
- swrOptions
1928
+ [memberSetting, cart]
1972
1929
  );
1973
1930
  }
1974
- function useArticle(options = {}) {
1975
- const { client, locale } = useShopify();
1976
- const { blogHandle, articleHandle, metafieldIdentifiers, ...swrOptions } = options;
1977
- return useSWR(
1978
- blogHandle && articleHandle ? ["article", locale, blogHandle, articleHandle, metafieldIdentifiers] : null,
1979
- () => getArticle(client, {
1980
- blogHandle,
1981
- articleHandle,
1982
- locale,
1983
- metafieldIdentifiers
1984
- }),
1985
- swrOptions
1986
- );
1931
+ function hasPlusMemberInLines({
1932
+ memberSetting,
1933
+ lines
1934
+ }) {
1935
+ const { plus_monthly_product, plus_annual_product } = memberSetting || {};
1936
+ if (!lines || lines.length === 0) {
1937
+ return {
1938
+ hasPlusMember: false,
1939
+ hasMonthlyPlus: false,
1940
+ hasAnnualPlus: false
1941
+ };
1942
+ }
1943
+ const monthlyPlusLine = lines.find((line) => {
1944
+ const variantHandle = line.variant?.product?.handle;
1945
+ const variantSku = line.variant?.sku;
1946
+ return variantHandle === plus_monthly_product?.handle && variantSku === plus_monthly_product?.sku;
1947
+ });
1948
+ const annualPlusLine = lines.find((line) => {
1949
+ const variantHandle = line.variant?.product?.handle;
1950
+ const variantSku = line.variant?.sku;
1951
+ return variantHandle === plus_annual_product?.handle && variantSku === plus_annual_product?.sku;
1952
+ });
1953
+ const hasMonthlyPlus = !!monthlyPlusLine;
1954
+ const hasAnnualPlus = !!annualPlusLine;
1955
+ const hasPlusMember = hasMonthlyPlus || hasAnnualPlus;
1956
+ return {
1957
+ hasPlusMember,
1958
+ hasMonthlyPlus,
1959
+ hasAnnualPlus,
1960
+ monthlyPlusLine,
1961
+ annualPlusLine
1962
+ };
1987
1963
  }
1988
- function useArticles(options = {}) {
1989
- const { client, locale } = useShopify();
1990
- const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
1991
- return useSWR(
1992
- ["articles", locale, first, query, sortKey, reverse, metafieldIdentifiers],
1993
- () => getArticles(client, {
1994
- locale,
1995
- first,
1996
- query,
1997
- sortKey,
1998
- reverse,
1999
- metafieldIdentifiers
1964
+ function useHasPlusMemberInLines({
1965
+ memberSetting,
1966
+ lines
1967
+ }) {
1968
+ return useMemo(
1969
+ () => hasPlusMemberInLines({
1970
+ memberSetting,
1971
+ lines
2000
1972
  }),
2001
- swrOptions
1973
+ [memberSetting, lines]
2002
1974
  );
2003
1975
  }
2004
- function useArticlesInBlog(options = {}) {
2005
- const { client, locale } = useShopify();
2006
- const { blogHandle, first, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2007
- return useSWR(
2008
- blogHandle ? ["articles-in-blog", locale, blogHandle, first, sortKey, reverse, metafieldIdentifiers] : null,
2009
- () => getArticlesInBlog(client, {
2010
- blogHandle,
2011
- locale,
2012
- first,
2013
- sortKey,
2014
- reverse,
2015
- metafieldIdentifiers
2016
- }),
2017
- swrOptions
2018
- );
1976
+ function usePlusMemberNeedAddToCart({
1977
+ cart,
1978
+ profile
1979
+ }) {
1980
+ const { selectedPlusMemberMode, selectedPlusMemberVariant, plusMemberMetafields } = usePlusMemberContext();
1981
+ const { hasMonthlyPlus, hasAnnualPlus } = useHasPlusMemberInCart({
1982
+ memberSetting: plusMemberMetafields,
1983
+ cart
1984
+ });
1985
+ const plusMemberVariant = useMemo(() => {
1986
+ if (!selectedPlusMemberVariant || selectedPlusMemberMode === "free" /* FREE */) {
1987
+ return void 0;
1988
+ }
1989
+ if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && hasMonthlyPlus) {
1990
+ return void 0;
1991
+ }
1992
+ if (selectedPlusMemberMode === "annual" /* ANNUAL */ && hasAnnualPlus) {
1993
+ return void 0;
1994
+ }
1995
+ if (profile?.isMonthlyPlus && selectedPlusMemberMode === "monthly" /* MONTHLY */) {
1996
+ return void 0;
1997
+ }
1998
+ if (profile?.isAnnualPlus && selectedPlusMemberMode === "annual" /* ANNUAL */) {
1999
+ return void 0;
2000
+ }
2001
+ return selectedPlusMemberVariant;
2002
+ }, [selectedPlusMemberMode, selectedPlusMemberVariant, hasMonthlyPlus, hasAnnualPlus]);
2003
+ return plusMemberVariant;
2019
2004
  }
2020
- async function performSearch(client, locale, searchQuery, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"]) {
2021
- if (!searchQuery) {
2022
- return void 0;
2023
- }
2024
- const query = (
2025
- /* GraphQL */
2026
- `
2027
- query search($query: String!, $first: Int!, $types: [SearchType!])
2028
- @inContext(language: $language) {
2029
- search(query: $query, first: $first, types: $types, unavailableProducts: HIDE) {
2030
- totalCount
2031
- edges {
2032
- node {
2033
- ... on Article {
2034
- __typename
2035
- id
2036
- handle
2037
- title
2038
- excerpt
2039
- image {
2040
- url
2041
- altText
2042
- }
2043
- }
2044
- ... on Page {
2045
- __typename
2046
- id
2047
- handle
2048
- title
2049
- }
2050
- ... on Product {
2051
- __typename
2052
- id
2053
- handle
2054
- title
2055
- description
2056
- featuredImage {
2057
- url
2058
- altText
2005
+ var PlusMemberProvider = ({
2006
+ variant,
2007
+ product,
2008
+ memberSetting,
2009
+ initialSelectedPlusMemberMode = "free",
2010
+ profile,
2011
+ children
2012
+ }) => {
2013
+ const [selectedPlusMemberMode, setSelectedPlusMemberMode] = useState(
2014
+ initialSelectedPlusMemberMode
2015
+ );
2016
+ const [selectedShippingMethod, setSelectedShippingMethod] = useState();
2017
+ const [showMoreShippingMethod, setShowMoreShippingMethod] = useState(false);
2018
+ const [showPlusMemberBenefit, setShowPlusMemberBenefit] = useState(false);
2019
+ const shippingMethodsContext = useShippingMethods({
2020
+ variant,
2021
+ plusMemberMetafields: memberSetting,
2022
+ selectedPlusMemberMode,
2023
+ profile
2024
+ });
2025
+ const { monthlyVariant, annualVariant } = usePlusMemberVariants({
2026
+ memberSetting
2027
+ });
2028
+ const selectedPlusMemberVariant = useMemo(() => {
2029
+ if (selectedPlusMemberMode === "free" /* FREE */) {
2030
+ return void 0;
2031
+ }
2032
+ return selectedPlusMemberMode === "monthly" /* MONTHLY */ ? monthlyVariant : annualVariant;
2033
+ }, [monthlyVariant, annualVariant, selectedPlusMemberMode]);
2034
+ return /* @__PURE__ */ jsx(
2035
+ PlusMemberContext.Provider,
2036
+ {
2037
+ value: {
2038
+ variant,
2039
+ plusMemberMetafields: memberSetting,
2040
+ selectedPlusMemberMode,
2041
+ setSelectedPlusMemberMode,
2042
+ selectedShippingMethod,
2043
+ setSelectedShippingMethod,
2044
+ shippingMethodsContext,
2045
+ showMoreShippingMethod,
2046
+ setShowMoreShippingMethod,
2047
+ selectedPlusMemberVariant,
2048
+ product,
2049
+ showPlusMemberBenefit,
2050
+ setShowPlusMemberBenefit,
2051
+ profile
2052
+ },
2053
+ children
2054
+ }
2055
+ );
2056
+ };
2057
+
2058
+ // src/hooks/cart/use-add-to-cart.ts
2059
+ function useAddToCart({ withTrack = true } = {}, swrOptions) {
2060
+ const { client, config, locale, cartCookieAdapter, userAdapter, performanceAdapter } = useShopify();
2061
+ const { cart, addCustomAttributes, memberSetting, profile, customer } = useCartContext();
2062
+ const { trigger: applyCartCodes } = useApplyCartCodes();
2063
+ const { trigger: removeInvalidCodes } = useRemoveCartCodes();
2064
+ const { trigger: addCartLines2 } = useAddCartLines();
2065
+ const { trigger: createCart4 } = useCreateCart({
2066
+ updateCookie: true
2067
+ });
2068
+ const { hasPlusMember } = useHasPlusMemberInCart({
2069
+ memberSetting,
2070
+ cart
2071
+ });
2072
+ const { attributes: cartAttributes } = useCartAttributes({
2073
+ profile,
2074
+ customer,
2075
+ cart,
2076
+ memberType: hasPlusMember ? "2" : String(profile?.memberType ?? 0)
2077
+ });
2078
+ const addToCart = useCallback(
2079
+ async (_key, { arg }) => {
2080
+ const {
2081
+ lineItems,
2082
+ cartId: providedCartId,
2083
+ discountCodes,
2084
+ gtmParams = {},
2085
+ buyerIdentity,
2086
+ needCreateCart = false,
2087
+ onCodesInvalid,
2088
+ replaceExistingCodes,
2089
+ customAttributes
2090
+ } = arg;
2091
+ if (!lineItems || lineItems.length === 0) {
2092
+ return;
2093
+ }
2094
+ performanceAdapter?.addToCartStart();
2095
+ const linesWithFunctionAttributes = getLinesWithAttributes({ cart, lineItems });
2096
+ const lines = linesWithFunctionAttributes.map((item) => ({
2097
+ merchandiseId: item.variant?.id || "",
2098
+ quantity: item.quantity || 1,
2099
+ attributes: item.attributes,
2100
+ sellingPlanId: item.sellingPlanId
2101
+ })).filter((item) => item.merchandiseId && item.quantity);
2102
+ if (lines.length === 0) {
2103
+ return;
2104
+ }
2105
+ let cartId = needCreateCart ? void 0 : providedCartId || cart?.id;
2106
+ let resultCart = null;
2107
+ if (!cartId) {
2108
+ resultCart = await createCart4({
2109
+ lines,
2110
+ buyerIdentity,
2111
+ discountCodes,
2112
+ customAttributes: [...cartAttributes, ...customAttributes || []]
2113
+ // 初次加购时,就把所有 cart attributes 带上
2114
+ });
2115
+ } else {
2116
+ resultCart = await addCartLines2({
2117
+ cartId,
2118
+ lines
2119
+ });
2120
+ console.log("npm addCartLines resultCart", resultCart);
2121
+ if (resultCart && resultCart.discountCodes && resultCart.discountCodes.length > 0) {
2122
+ const unapplicableCodes = resultCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
2123
+ if (unapplicableCodes.length > 0) {
2124
+ if (onCodesInvalid) {
2125
+ const handledCart = await onCodesInvalid(resultCart, unapplicableCodes);
2126
+ if (handledCart) {
2127
+ resultCart = handledCart;
2059
2128
  }
2129
+ } else {
2130
+ await removeInvalidCodes({
2131
+ discountCodes: unapplicableCodes
2132
+ });
2060
2133
  }
2061
2134
  }
2062
2135
  }
2063
- pageInfo {
2064
- hasNextPage
2065
- endCursor
2136
+ if (resultCart && discountCodes && discountCodes.length > 0) {
2137
+ applyCartCodes({
2138
+ replaceExistingCodes,
2139
+ discountCodes
2140
+ });
2141
+ }
2142
+ if (customAttributes && customAttributes.length > 0) {
2143
+ addCustomAttributes(customAttributes);
2066
2144
  }
2067
2145
  }
2068
- }
2069
- `
2146
+ if (withTrack) {
2147
+ trackAddToCartGA({
2148
+ lineItems,
2149
+ gtmParams: { ...gtmParams, brand: config.getBrand() }
2150
+ });
2151
+ trackAddToCartFBQ({ lineItems });
2152
+ }
2153
+ performanceAdapter?.addToCartEnd();
2154
+ return resultCart;
2155
+ },
2156
+ [
2157
+ client,
2158
+ locale,
2159
+ cartCookieAdapter,
2160
+ userAdapter,
2161
+ cart,
2162
+ withTrack,
2163
+ performanceAdapter,
2164
+ createCart4,
2165
+ addCartLines2,
2166
+ applyCartCodes,
2167
+ removeInvalidCodes,
2168
+ addCustomAttributes,
2169
+ config
2170
+ ]
2070
2171
  );
2071
- const data = await client.query(query, {
2072
- query: searchQuery,
2073
- first,
2074
- types
2075
- });
2076
- if (!data || !data.search) {
2077
- return void 0;
2078
- }
2079
- const items = data.search.edges?.map((edge) => {
2080
- const node = edge.node;
2081
- const item = {
2082
- type: node.__typename.toUpperCase(),
2083
- id: node.id,
2084
- handle: node.handle,
2085
- title: node.title
2086
- };
2087
- if (node.__typename === "Product") {
2088
- item.description = node.description;
2089
- item.image = node.featuredImage ? {
2090
- url: node.featuredImage.url,
2091
- altText: node.featuredImage.altText
2092
- } : void 0;
2093
- } else if (node.__typename === "Article") {
2094
- item.description = node.excerpt;
2095
- item.image = node.image ? {
2096
- url: node.image.url,
2097
- altText: node.image.altText
2098
- } : void 0;
2099
- }
2100
- return item;
2101
- }) || [];
2102
- return {
2103
- items,
2104
- totalCount: data.search.totalCount || 0,
2105
- pageInfo: data.search.pageInfo
2106
- };
2172
+ return useSWRMutation("add-to-cart", addToCart, swrOptions);
2107
2173
  }
2108
- function useSearch(options = {}) {
2109
- const { client, locale } = useShopify();
2110
- const { query, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"], ...swrOptions } = options;
2111
- return useSWR(
2112
- query ? ["search", locale, query, first, types] : null,
2113
- () => performSearch(client, locale, query, first, types),
2114
- swrOptions
2174
+ function useUpdateCartLines(options) {
2175
+ const { client, locale, cartCookieAdapter } = useShopify();
2176
+ const { mutateCart, metafieldIdentifiers } = useCartContext();
2177
+ const updateLines = useCallback(
2178
+ async (_key, { arg }) => {
2179
+ const updatedCart = await updateCartLines(client, {
2180
+ ...arg,
2181
+ metafieldIdentifiers,
2182
+ cookieAdapter: cartCookieAdapter
2183
+ });
2184
+ if (updatedCart) {
2185
+ mutateCart(updatedCart);
2186
+ }
2187
+ console.log("use-update-cart-lines updatedCart", metafieldIdentifiers, updatedCart);
2188
+ return updatedCart;
2189
+ },
2190
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
2115
2191
  );
2192
+ return useSWRMutation("update-cart-lines", updateLines, options);
2116
2193
  }
2117
- async function getSiteInfo(client, locale, metafieldIdentifiers) {
2118
- const hasMetafields = metafieldIdentifiers && metafieldIdentifiers.length > 0;
2119
- const query = (
2120
- /* GraphQL */
2121
- `
2122
- query getSiteInfo(
2123
- ${hasMetafields ? "$shopMetafieldIdentifiers: [HasMetafieldsIdentifier!]!" : ""}
2124
- ) @inContext(language: $language) {
2125
- shop {
2126
- name
2127
- description
2128
- primaryDomain {
2129
- url
2130
- host
2194
+ function useUpdateCartAttributes({
2195
+ mutate,
2196
+ metafieldIdentifiers,
2197
+ disabled = false,
2198
+ swrOptions
2199
+ }) {
2200
+ const { client, locale, cartCookieAdapter } = useShopify();
2201
+ const updateAttributes = useCallback(
2202
+ async (_key, { arg }) => {
2203
+ if (disabled) {
2204
+ return void 0;
2205
+ }
2206
+ const updatedCart = await updateCartAttributes(client, {
2207
+ ...arg,
2208
+ metafieldIdentifiers,
2209
+ cookieAdapter: cartCookieAdapter
2210
+ });
2211
+ if (updatedCart) {
2212
+ mutate(updatedCart);
2213
+ }
2214
+ return updatedCart;
2215
+ },
2216
+ [client, locale, cartCookieAdapter, mutate, metafieldIdentifiers, disabled]
2217
+ );
2218
+ return useSWRMutation("update-cart-attributes", updateAttributes, swrOptions);
2219
+ }
2220
+ function useBuyNow({ withTrack = true } = {}, swrOptions) {
2221
+ const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
2222
+ const { profile, customer, memberSetting } = useCartContext();
2223
+ const isLoggedIn = userAdapter?.isLoggedIn || false;
2224
+ const buyNow = useCallback(
2225
+ async (_key, { arg }) => {
2226
+ const {
2227
+ lineItems,
2228
+ discountCodes,
2229
+ gtmParams = {},
2230
+ buyerIdentity,
2231
+ fbqTrackConfig,
2232
+ customAttributes,
2233
+ metafieldIdentifiers,
2234
+ redirectToCheckout = true
2235
+ } = arg;
2236
+ if (!lineItems || lineItems.length === 0) {
2237
+ return;
2238
+ }
2239
+ const { hasPlusMember } = hasPlusMemberInLines({
2240
+ memberSetting,
2241
+ lines: lineItems
2242
+ });
2243
+ const memberType = hasPlusMember ? "2" : String(profile?.memberType ?? 0);
2244
+ const cartAttributes = getCartAttributes({
2245
+ profile,
2246
+ customer,
2247
+ memberType,
2248
+ currentUrl: window.location.href
2249
+ });
2250
+ const linesWithFunctionAttributes = getLinesWithAttributes({
2251
+ lineItems
2252
+ });
2253
+ const lines = linesWithFunctionAttributes.map((item) => ({
2254
+ merchandiseId: item.variant?.id || "",
2255
+ quantity: item.quantity || 1,
2256
+ attributes: item.attributes,
2257
+ sellingPlanId: item.sellingPlanId
2258
+ })).filter((item) => item.merchandiseId);
2259
+ if (lines.length === 0) {
2260
+ return;
2261
+ }
2262
+ const resultCart = await createCart(client, {
2263
+ lines,
2264
+ metafieldIdentifiers,
2265
+ cookieAdapter: cartCookieAdapter,
2266
+ buyerIdentity,
2267
+ discountCodes,
2268
+ customAttributes: [...cartAttributes, ...customAttributes || []]
2269
+ });
2270
+ if (!resultCart) {
2271
+ throw new Error("Failed to create cart for buy now");
2272
+ }
2273
+ if (withTrack && resultCart.lineItems) {
2274
+ trackBuyNowGA({
2275
+ lineItems,
2276
+ gtmParams: { ...gtmParams, brand: config.getBrand() }
2277
+ });
2278
+ if (fbqTrackConfig) {
2279
+ trackBuyNowFBQ({ trackConfig: fbqTrackConfig });
2131
2280
  }
2132
- brand {
2133
- logo {
2134
- image {
2135
- url
2136
- }
2137
- }
2138
- colors {
2139
- primary {
2140
- background
2141
- }
2142
- secondary {
2143
- background
2144
- }
2281
+ }
2282
+ if (redirectToCheckout) {
2283
+ if (resultCart.url) {
2284
+ if (typeof window !== "undefined") {
2285
+ window.location.href = resultCart.url;
2145
2286
  }
2287
+ } else {
2288
+ throw new Error("Failed to get checkout URL");
2146
2289
  }
2147
- ${hasMetafields ? "metafields(identifiers: $shopMetafieldIdentifiers) { key value }" : ""}
2148
2290
  }
2149
- }
2150
- `
2291
+ return resultCart;
2292
+ },
2293
+ [client, locale, isLoggedIn, cartCookieAdapter, withTrack, customer, profile, memberSetting]
2151
2294
  );
2152
- const variables = {};
2153
- if (hasMetafields) {
2154
- variables.shopMetafieldIdentifiers = metafieldIdentifiers;
2155
- }
2156
- const data = await client.query(query, variables);
2157
- if (!data || !data.shop) {
2158
- return void 0;
2159
- }
2160
- const shop = data.shop;
2161
- const metafields = shop.metafields?.reduce((acc, mf) => {
2162
- if (mf && mf.key) {
2163
- acc[mf.key] = mf.value;
2164
- }
2165
- return acc;
2166
- }, {});
2167
- return {
2168
- name: shop.name,
2169
- description: shop.description,
2170
- primaryDomain: shop.primaryDomain,
2171
- brand: shop.brand ? {
2172
- logo: shop.brand.logo,
2173
- colors: shop.brand.colors ? {
2174
- primary: shop.brand.colors.primary?.background,
2175
- secondary: shop.brand.colors.secondary?.background
2176
- } : void 0
2177
- } : void 0,
2178
- metafields
2179
- };
2295
+ return useSWRMutation("buy-now", buyNow, swrOptions);
2180
2296
  }
2181
- function useSite(options = {}) {
2297
+
2298
+ // src/hooks/cart/types/price-discount.ts
2299
+ var PriceDiscountType = /* @__PURE__ */ ((PriceDiscountType2) => {
2300
+ PriceDiscountType2[PriceDiscountType2["PERCENTAGE"] = 1] = "PERCENTAGE";
2301
+ PriceDiscountType2[PriceDiscountType2["FIXED_AMOUNT"] = 2] = "FIXED_AMOUNT";
2302
+ return PriceDiscountType2;
2303
+ })(PriceDiscountType || {});
2304
+ var PriceBasePriceType = /* @__PURE__ */ ((PriceBasePriceType2) => {
2305
+ PriceBasePriceType2[PriceBasePriceType2["MIN_DISCOUNTED_PRICE"] = 1] = "MIN_DISCOUNTED_PRICE";
2306
+ PriceBasePriceType2[PriceBasePriceType2["MIN_TOTAL_PRICE"] = 2] = "MIN_TOTAL_PRICE";
2307
+ return PriceBasePriceType2;
2308
+ })(PriceBasePriceType || {});
2309
+ function useProduct(options = {}) {
2182
2310
  const { client, locale } = useShopify();
2183
- const { metafieldIdentifiers, ...swrOptions } = options;
2311
+ const { handle, metafieldIdentifiers, ...swrOptions } = options;
2184
2312
  return useSWR(
2185
- ["site", locale, metafieldIdentifiers],
2186
- () => getSiteInfo(client, locale, metafieldIdentifiers),
2313
+ handle ? ["product", locale, handle, metafieldIdentifiers] : null,
2314
+ () => getProduct(client, {
2315
+ handle,
2316
+ locale,
2317
+ metafieldIdentifiers
2318
+ }),
2187
2319
  swrOptions
2188
2320
  );
2189
2321
  }
2190
-
2191
- // src/hooks/member/plus/types.ts
2192
- var PLUS_MEMBER_TYPE = /* @__PURE__ */ ((PLUS_MEMBER_TYPE2) => {
2193
- PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["FREE"] = 0] = "FREE";
2194
- PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["MONTHLY"] = 1] = "MONTHLY";
2195
- PLUS_MEMBER_TYPE2[PLUS_MEMBER_TYPE2["ANNUAL"] = 2] = "ANNUAL";
2196
- return PLUS_MEMBER_TYPE2;
2197
- })(PLUS_MEMBER_TYPE || {});
2198
- var PlusMemberMode = /* @__PURE__ */ ((PlusMemberMode2) => {
2199
- PlusMemberMode2["MONTHLY"] = "monthly";
2200
- PlusMemberMode2["ANNUAL"] = "annual";
2201
- return PlusMemberMode2;
2202
- })(PlusMemberMode || {});
2203
- var DeliveryPlusType = /* @__PURE__ */ ((DeliveryPlusType2) => {
2204
- DeliveryPlusType2["FREE"] = "free";
2205
- DeliveryPlusType2["MONTHLY"] = "monthly";
2206
- DeliveryPlusType2["ANNUAL"] = "annual";
2207
- return DeliveryPlusType2;
2208
- })(DeliveryPlusType || {});
2209
- var ShippingMethodMode = /* @__PURE__ */ ((ShippingMethodMode2) => {
2210
- ShippingMethodMode2["FREE"] = "free";
2211
- ShippingMethodMode2["TDD"] = "tdd";
2212
- ShippingMethodMode2["NDD"] = "ndd";
2213
- return ShippingMethodMode2;
2214
- })(ShippingMethodMode || {});
2215
- var createInitialValue = () => ({
2216
- zipCode: "",
2217
- plusMemberMetafields: {},
2218
- setZipCode: () => {
2219
- },
2220
- allowNextDayDelivery: false,
2221
- setAllowNextDayDelivery: () => {
2222
- },
2223
- allowThirdDayDelivery: false,
2224
- setAllowThirdDayDelivery: () => {
2225
- },
2226
- selectedPlusMemberMode: "free",
2227
- setSelectedPlusMemberMode: () => {
2228
- },
2229
- showAreaCheckModal: false,
2230
- setShowAreaCheckModal: () => {
2231
- },
2232
- selectedShippingMethod: void 0,
2233
- setSelectedShippingMethod: () => {
2234
- },
2235
- showTip: false,
2236
- setShowTip: () => {
2237
- },
2238
- showMoreShippingMethod: false,
2239
- setShowMoreShippingMethod: () => {
2240
- },
2241
- variant: {},
2242
- product: {},
2243
- shippingMethodsContext: {
2244
- freeShippingMethods: [],
2245
- paymentShippingMethods: [],
2246
- nddOverweight: false,
2247
- tddOverweight: false
2248
- },
2249
- selectedPlusMemberProduct: null,
2250
- plusMemberProducts: [],
2251
- showPlusMemberBenefit: false,
2252
- setShowPlusMemberBenefit: () => {
2253
- },
2254
- deleteMarginBottom: false,
2255
- setDeleteMarginBottom: () => {
2256
- },
2257
- profile: void 0,
2258
- locale: void 0
2259
- });
2260
- var PlusMemberContext = createContext(createInitialValue());
2261
- function usePlusMemberContext() {
2262
- return useContext(PlusMemberContext);
2322
+ function useAllProducts(options = {}) {
2323
+ const { client, locale } = useShopify();
2324
+ const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2325
+ return useSWR(
2326
+ ["all-products", locale, first, query, sortKey, reverse, metafieldIdentifiers],
2327
+ () => getAllProducts(client, {
2328
+ locale,
2329
+ first,
2330
+ query,
2331
+ sortKey,
2332
+ reverse,
2333
+ metafieldIdentifiers
2334
+ }),
2335
+ swrOptions
2336
+ );
2263
2337
  }
2264
- function usePlusMonthlyProductVariant() {
2265
- const { plusMemberProducts, plusMemberMetafields } = usePlusMemberContext();
2266
- const plusMonthly = plusMemberMetafields?.plus_monthly_product;
2267
- const plusMonthlyProductVariant = useMemo(() => {
2268
- const product = plusMemberProducts?.find(
2269
- (item) => item?.handle === plusMonthly?.handle
2270
- );
2271
- const productVariant = product?.variants?.find(
2272
- (item) => item.sku === plusMonthly?.sku
2273
- );
2274
- return productVariant;
2275
- }, [plusMemberProducts, plusMonthly]);
2276
- return plusMonthlyProductVariant;
2338
+ function getFirstAvailableVariant(product) {
2339
+ const availableVariant = product.variants.find((v) => v.availableForSale);
2340
+ return availableVariant || product.variants[0];
2277
2341
  }
2278
- function usePlusAnnualProductVariant() {
2279
- const { plusMemberProducts, plusMemberMetafields } = usePlusMemberContext();
2280
- const plusAnnual = plusMemberMetafields?.plus_annual_product;
2281
- const plusAnnualProductVariant = useMemo(() => {
2282
- const product = plusMemberProducts?.find(
2283
- (item) => item?.handle === plusAnnual?.handle
2284
- );
2285
- const productVariant = product?.variants?.find(
2286
- (item) => item.sku === plusAnnual?.sku
2287
- );
2288
- return productVariant;
2289
- }, [plusMemberProducts, plusAnnual]);
2290
- return plusAnnualProductVariant;
2342
+ function getVariantFromSelectedOptions(product, selectedOptions) {
2343
+ return product.variants.find((variant) => {
2344
+ return variant.selectedOptions.every((option) => {
2345
+ return selectedOptions[option.name] === option.value;
2346
+ });
2347
+ });
2348
+ }
2349
+ function useVariant({
2350
+ product,
2351
+ selectedOptions
2352
+ }) {
2353
+ const [variant, setVariant] = useState(
2354
+ product ? getFirstAvailableVariant(product) : void 0
2355
+ );
2356
+ useEffect(() => {
2357
+ if (!product) {
2358
+ setVariant(void 0);
2359
+ return;
2360
+ }
2361
+ const newVariant = getVariantFromSelectedOptions(product, selectedOptions);
2362
+ if (newVariant && newVariant.id !== variant?.id) {
2363
+ setVariant(newVariant);
2364
+ } else if (!newVariant) {
2365
+ setVariant(getFirstAvailableVariant(product));
2366
+ }
2367
+ }, [selectedOptions, product, variant?.id]);
2368
+ return variant;
2369
+ }
2370
+ var FAKE_PRICE = 999999999e-2;
2371
+ function formatPrice({
2372
+ amount,
2373
+ currencyCode,
2374
+ locale,
2375
+ maximumFractionDigits,
2376
+ minimumFractionDigits,
2377
+ removeTrailingZeros
2378
+ }) {
2379
+ const formatter = new Intl.NumberFormat(locale, {
2380
+ style: "currency",
2381
+ currency: currencyCode,
2382
+ maximumFractionDigits: maximumFractionDigits ?? 2,
2383
+ minimumFractionDigits: minimumFractionDigits ?? 2
2384
+ });
2385
+ let formatted = formatter.format(amount);
2386
+ if (removeTrailingZeros) {
2387
+ formatted = formatted.replace(/\.00$/, "");
2388
+ }
2389
+ return formatted;
2390
+ }
2391
+ function formatVariantPrice({
2392
+ amount,
2393
+ baseAmount,
2394
+ currencyCode,
2395
+ locale,
2396
+ maximumFractionDigits,
2397
+ minimumFractionDigits,
2398
+ removeTrailingZeros
2399
+ }) {
2400
+ return {
2401
+ price: formatPrice({
2402
+ amount,
2403
+ currencyCode,
2404
+ locale,
2405
+ maximumFractionDigits,
2406
+ minimumFractionDigits,
2407
+ removeTrailingZeros
2408
+ }),
2409
+ basePrice: formatPrice({
2410
+ amount: baseAmount,
2411
+ currencyCode,
2412
+ locale,
2413
+ maximumFractionDigits,
2414
+ minimumFractionDigits,
2415
+ removeTrailingZeros
2416
+ })
2417
+ };
2291
2418
  }
2292
- function useShippingMethods(options) {
2293
- const {
2294
- variant,
2295
- plusMemberMetafields,
2296
- selectedPlusMemberMode,
2297
- isPlus = false,
2298
- nddCoupon,
2299
- tddCoupon
2300
- } = options;
2301
- const { plus_shipping, shippingMethod } = plusMemberMetafields || {};
2302
- const nddOverweight = useMemo(() => {
2303
- return (variant?.weight || 0) > (shippingMethod?.overWeight_ndd || Infinity);
2304
- }, [shippingMethod?.overWeight_ndd, variant?.weight]);
2305
- const tddOverweight = useMemo(() => {
2306
- return (variant?.weight || 0) > (shippingMethod?.overWeight_tdd || Infinity);
2307
- }, [shippingMethod?.overWeight_tdd, variant?.weight]);
2308
- const paymentShippingMethods = useMemo(() => {
2309
- const weight = variant?.weight || 0;
2310
- const methods = plus_shipping?.shipping_methods?.filter(
2311
- ({ weight_low, weight_high, __mode, __plus }) => {
2312
- const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
2313
- return __mode !== "free" /* FREE */ && !__plus && fitWeight;
2314
- }
2315
- ) || [];
2316
- return methods.map((method) => {
2317
- let disabled = false;
2318
- const selectedFreeMember = selectedPlusMemberMode === "free";
2319
- if (method.__mode === "ndd" /* NDD */) {
2320
- disabled = selectedFreeMember || nddOverweight;
2321
- } else if (method.__mode === "tdd" /* TDD */) {
2322
- disabled = selectedFreeMember || tddOverweight;
2323
- }
2324
- return {
2325
- ...method,
2326
- id: method.__mode + method.__code,
2327
- useCoupon: false,
2328
- subtitle: plus_shipping?.directly || "",
2329
- disabled
2330
- };
2331
- });
2332
- }, [
2333
- nddOverweight,
2334
- plus_shipping?.directly,
2335
- plus_shipping?.shipping_methods,
2336
- selectedPlusMemberMode,
2337
- tddOverweight,
2338
- variant?.weight
2339
- ]);
2340
- const nddPrice = useMemo(() => {
2341
- const weight = variant?.weight || 0;
2342
- const nddMethod = paymentShippingMethods.find(
2343
- ({ __mode, weight_high, weight_low }) => {
2344
- const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
2345
- return __mode === "ndd" && fitWeight;
2346
- }
2347
- );
2348
- return nddMethod?.price || 0;
2349
- }, [variant?.weight, paymentShippingMethods]);
2350
- const tddPrice = useMemo(() => {
2351
- const weight = variant?.weight || 0;
2352
- const tddMethod = paymentShippingMethods.find(
2353
- ({ __mode, weight_high, weight_low }) => {
2354
- const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
2355
- return __mode === "tdd" && fitWeight;
2356
- }
2357
- );
2358
- return tddMethod?.price || 0;
2359
- }, [variant?.weight, paymentShippingMethods]);
2360
- const freeShippingMethods = useMemo(() => {
2361
- const weight = variant?.weight || 0;
2362
- let methods = plus_shipping?.shipping_methods?.filter(
2363
- ({ __mode, __plus, weight_low, weight_high }) => {
2364
- if (__mode === "free" /* FREE */) {
2365
- return true;
2366
- }
2367
- if (isPlus) {
2368
- const hasCoupon = isPlus && __mode === "ndd" /* NDD */ && nddCoupon || isPlus && __mode === "tdd" /* TDD */ && (tddCoupon || nddCoupon);
2369
- const fitWeight = (!weight_low || weight >= weight_low) && (!weight_high || weight <= weight_high);
2370
- return hasCoupon && fitWeight && !__plus;
2371
- } else {
2372
- return __plus;
2373
- }
2374
- }
2375
- ) || [];
2376
- if (isPlus) {
2377
- methods = methods.sort((a, b) => {
2378
- if (b.__mode === "free" /* FREE */) return -1;
2379
- return 0;
2380
- });
2419
+ function usePrice({
2420
+ amount,
2421
+ baseAmount,
2422
+ currencyCode,
2423
+ soldOutDescription = "",
2424
+ maximumFractionDigits,
2425
+ minimumFractionDigits,
2426
+ removeTrailingZeros
2427
+ }) {
2428
+ const { locale } = useShopify();
2429
+ const value = useMemo(() => {
2430
+ if (typeof amount !== "number" || !currencyCode) {
2431
+ return "";
2381
2432
  }
2382
- return methods.map((method) => {
2383
- let price = 0;
2384
- let coupon;
2385
- let disabled;
2386
- if (method.__mode !== "free" /* FREE */) {
2387
- switch (method.__mode) {
2388
- case "tdd":
2389
- price = tddPrice;
2390
- coupon = tddCoupon || nddCoupon;
2391
- break;
2392
- case "ndd":
2393
- price = nddPrice;
2394
- coupon = nddCoupon;
2395
- break;
2396
- }
2397
- disabled = selectedPlusMemberMode === "free";
2398
- if (method.__mode === "ndd" /* NDD */) {
2399
- disabled = disabled || nddOverweight;
2400
- } else if (method.__mode === "tdd" /* TDD */) {
2401
- disabled = disabled || tddOverweight;
2402
- }
2403
- }
2404
- return {
2405
- ...method,
2406
- id: method.__mode + method.__code,
2407
- useCoupon: true,
2408
- disabled,
2409
- coupon,
2410
- price
2411
- };
2433
+ if (soldOutDescription && amount >= FAKE_PRICE) {
2434
+ return soldOutDescription;
2435
+ }
2436
+ return baseAmount ? formatVariantPrice({
2437
+ amount,
2438
+ baseAmount,
2439
+ currencyCode,
2440
+ locale,
2441
+ maximumFractionDigits,
2442
+ minimumFractionDigits,
2443
+ removeTrailingZeros
2444
+ }) : formatPrice({
2445
+ amount,
2446
+ currencyCode,
2447
+ locale,
2448
+ maximumFractionDigits,
2449
+ minimumFractionDigits,
2450
+ removeTrailingZeros
2412
2451
  });
2413
2452
  }, [
2414
- variant?.weight,
2415
- plus_shipping?.shipping_methods,
2416
- isPlus,
2417
- nddCoupon,
2418
- tddCoupon,
2419
- selectedPlusMemberMode,
2420
- tddPrice,
2421
- nddPrice,
2422
- nddOverweight,
2423
- tddOverweight
2453
+ amount,
2454
+ baseAmount,
2455
+ currencyCode,
2456
+ locale,
2457
+ maximumFractionDigits,
2458
+ minimumFractionDigits,
2459
+ soldOutDescription,
2460
+ removeTrailingZeros
2424
2461
  ]);
2425
- return {
2426
- freeShippingMethods,
2427
- paymentShippingMethods,
2428
- nddOverweight,
2429
- tddOverweight
2430
- };
2462
+ const result = useMemo(() => {
2463
+ const free = Boolean(amount && amount <= 0);
2464
+ return typeof value === "string" ? { price: value, basePrice: value, free } : { ...value, free };
2465
+ }, [value, amount]);
2466
+ return result;
2431
2467
  }
2432
- function useShippingMethodAvailableCheck() {
2433
- const {
2434
- zipCode,
2435
- allowNextDayDelivery,
2436
- allowThirdDayDelivery,
2437
- selectedShippingMethod,
2438
- setSelectedShippingMethod,
2439
- setShowTip,
2440
- shippingMethodsContext
2441
- } = usePlusMemberContext();
2468
+ function optionsConstructor(selectedOptions) {
2469
+ return selectedOptions.reduce((acc, option) => {
2470
+ acc[option.name] = option.value;
2471
+ return acc;
2472
+ }, {});
2473
+ }
2474
+ function decodeShopifyId(gid) {
2475
+ try {
2476
+ const base64 = gid.split("/").pop() || "";
2477
+ return atob(base64);
2478
+ } catch {
2479
+ return gid;
2480
+ }
2481
+ }
2482
+ function useSelectedOptions(product, sku) {
2483
+ const [options, setOptions] = useState({});
2442
2484
  useEffect(() => {
2443
- const freeShippingMethod = shippingMethodsContext.freeShippingMethods[0];
2444
- const standardShippingMethod = shippingMethodsContext.freeShippingMethods?.find(
2445
- (item) => item.__mode === "free" /* FREE */
2446
- );
2447
- const freeTDD = shippingMethodsContext.freeShippingMethods.find(
2448
- (item) => item.__mode === "tdd" /* TDD */
2449
- );
2450
- const paymentTDD = shippingMethodsContext.paymentShippingMethods.find(
2451
- (item) => item.__mode === "tdd" /* TDD */
2452
- );
2453
- if (zipCode) {
2454
- console.log(
2455
- "allowNextDayDelivery, allowThirdDayDelivery:",
2456
- allowNextDayDelivery,
2457
- allowThirdDayDelivery
2458
- );
2459
- if (!allowNextDayDelivery && !allowThirdDayDelivery) {
2460
- setShowTip(true);
2461
- setSelectedShippingMethod(standardShippingMethod);
2462
- } else {
2463
- if (selectedShippingMethod?.__mode === "ndd" /* NDD */ && !allowNextDayDelivery) {
2464
- setShowTip(true);
2465
- if (allowThirdDayDelivery) {
2466
- if (selectedShippingMethod.useCoupon) {
2467
- const method = freeTDD || freeShippingMethod;
2468
- if (method) setSelectedShippingMethod(method);
2469
- } else {
2470
- const method = paymentTDD || freeShippingMethod;
2471
- if (method) setSelectedShippingMethod(method);
2472
- }
2473
- } else {
2474
- if (freeShippingMethod) setSelectedShippingMethod(freeShippingMethod);
2475
- }
2476
- } else if (
2477
- // TDD 无法使用
2478
- selectedShippingMethod?.__mode === "tdd" /* TDD */ && !allowThirdDayDelivery
2479
- ) {
2480
- setShowTip(true);
2481
- if (freeShippingMethod) setSelectedShippingMethod(freeShippingMethod);
2485
+ if (!product || !product.variants.length) {
2486
+ setOptions({});
2487
+ return;
2488
+ }
2489
+ let variant = product.variants[0];
2490
+ if (typeof window !== "undefined") {
2491
+ const searchParams = new URLSearchParams(window.location.search);
2492
+ const variantIdParam = searchParams.get("variant");
2493
+ if (variantIdParam) {
2494
+ const foundVariant = product.variants.find((v) => {
2495
+ if (sku) return v.sku === sku;
2496
+ return v.id === variantIdParam || v.id.includes(variantIdParam) || decodeShopifyId(v.id) === variantIdParam;
2497
+ });
2498
+ if (foundVariant) {
2499
+ variant = foundVariant;
2482
2500
  }
2483
2501
  }
2484
2502
  }
2485
- }, [
2486
- allowNextDayDelivery,
2487
- allowThirdDayDelivery,
2488
- zipCode,
2489
- shippingMethodsContext,
2490
- selectedShippingMethod,
2491
- setSelectedShippingMethod,
2492
- setShowTip
2493
- ]);
2494
- }
2495
- var useReplaceCartPlusMember = () => {
2496
- const { plusMemberMetafields, selectedPlusMemberMode } = usePlusMemberContext();
2497
- const { trigger: removeCartLines2 } = useRemoveCartLines();
2498
- const { cart } = useCartContext();
2499
- const plusMonthly = plusMemberMetafields?.plus_monthly_product;
2500
- const plusAnnual = plusMemberMetafields?.plus_annual_product;
2501
- const handler = useCallback(async () => {
2502
- const plusMonthlyInCart = cart?.lineItems.find(
2503
- (item) => item.variant?.sku === plusMonthly?.sku
2504
- );
2505
- const plusAnnualInCart = cart?.lineItems.find(
2506
- (item) => item.variant?.sku === plusAnnual?.sku
2507
- );
2508
- if (selectedPlusMemberMode === "annual" /* ANNUAL */ && plusMonthlyInCart) {
2509
- await removeCartLines2({
2510
- lineIds: [plusMonthlyInCart.id]
2511
- });
2512
- } else if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && plusAnnualInCart) {
2513
- await removeCartLines2({
2514
- lineIds: [plusAnnualInCart.id]
2515
- });
2503
+ if (variant) {
2504
+ const newOptions = optionsConstructor(variant.selectedOptions);
2505
+ setOptions(newOptions);
2516
2506
  }
2517
- }, [
2518
- cart?.lineItems,
2519
- selectedPlusMemberMode,
2520
- plusMonthly?.sku,
2521
- plusAnnual?.sku,
2522
- removeCartLines2
2523
- ]);
2524
- return handler;
2525
- };
2526
- var usePlusMemberDeliveryCodes = ({
2527
- deliveryData
2528
- }) => {
2529
- return useMemo(
2530
- () => deliveryData?.deliveryCustomData?.discount_code,
2531
- [deliveryData]
2532
- );
2533
- };
2534
- function useUpdateCartDeliveryOptions(mutate, metafieldIdentifiers, options) {
2535
- const { client, locale, cartCookieAdapter } = useShopify();
2536
- const updateDeliveryOptions = useCallback(
2537
- async (_key, { arg }) => {
2538
- const updatedCart = await updateCartDeliveryOptions(client, {
2539
- ...arg,
2540
- metafieldIdentifiers,
2541
- cookieAdapter: cartCookieAdapter
2542
- });
2543
- console.log("useUpdateCartDeliveryOptions updatedCart", updatedCart);
2544
- if (updatedCart) {
2545
- mutate(updatedCart);
2507
+ }, [product, sku]);
2508
+ return [options, setOptions];
2509
+ }
2510
+ function decodeShopifyId2(gid) {
2511
+ try {
2512
+ const parts = gid.split("/");
2513
+ return parts[parts.length - 1] || gid;
2514
+ } catch {
2515
+ return gid;
2516
+ }
2517
+ }
2518
+ function useProductUrl(otherQuery) {
2519
+ const { routerAdapter } = useShopify();
2520
+ return useCallback(
2521
+ ({ product, variant }) => {
2522
+ if (!product) return "";
2523
+ const queryParams = new URLSearchParams();
2524
+ if (variant?.id) {
2525
+ const variantId = decodeShopifyId2(variant.id);
2526
+ if (variantId) {
2527
+ queryParams.set("variant", variantId);
2528
+ }
2546
2529
  }
2547
- return updatedCart;
2530
+ if (otherQuery) {
2531
+ Object.entries(otherQuery).forEach(([key, value]) => {
2532
+ queryParams.set(key, value);
2533
+ });
2534
+ }
2535
+ const queryString = queryParams.toString();
2536
+ const path = `/products/${product.handle}${queryString ? `?${queryString}` : ""}`;
2537
+ if (routerAdapter?.getLocalizedPath) {
2538
+ return routerAdapter.getLocalizedPath(path);
2539
+ }
2540
+ return path;
2548
2541
  },
2549
- [client, locale, cartCookieAdapter, mutate]
2542
+ [routerAdapter, otherQuery]
2550
2543
  );
2551
- return useSWRMutation("update-cart-delivery-options", updateDeliveryOptions, options);
2552
2544
  }
2553
-
2554
- // src/hooks/member/plus/use-update-plus-member-delivery-options.ts
2555
- var useUpdatePlusMemberDeliveryOptions = ({
2556
- deliveryData,
2557
- options
2558
- }) => {
2559
- const { cart, mutateCart: mutate, metafieldIdentifiers } = useCartContext();
2560
- const { trigger: updateCartDeliveryOptions2, isMutating } = useUpdateCartDeliveryOptions(
2561
- mutate,
2562
- metafieldIdentifiers
2563
- );
2564
- const deliveryOptions = useMemo(() => {
2565
- const deliveryGroupId = cart?.deliveryGroups?.[0]?.id;
2566
- const selectedOptionCode = deliveryData?.deliveryCustomData?.selected_delivery_option;
2567
- if (!deliveryGroupId || !selectedOptionCode) {
2568
- return [];
2569
- }
2570
- const deliveryGroup = cart?.deliveryGroups?.find((group) => group?.id === deliveryGroupId);
2571
- const matchedOption = deliveryGroup?.deliveryOptions?.find(
2572
- (option) => option?.code === selectedOptionCode
2573
- );
2574
- if (!matchedOption?.handle) {
2575
- return [];
2576
- }
2577
- return [
2578
- {
2579
- deliveryGroupId,
2580
- deliveryOptionHandle: matchedOption.handle
2581
- }
2582
- ];
2583
- }, [deliveryData, cart]);
2584
- const handler = useCallback(async () => {
2585
- const updatedCart = await updateCartDeliveryOptions2({
2586
- selectedDeliveryOptions: deliveryOptions
2587
- });
2588
- if (updatedCart && mutate) {
2589
- mutate(updatedCart);
2545
+ function decodeShopifyId3(gid) {
2546
+ try {
2547
+ const parts = gid.split("/");
2548
+ return parts[parts.length - 1] || gid;
2549
+ } catch {
2550
+ return gid;
2551
+ }
2552
+ }
2553
+ function useUpdateVariantQuery(variant) {
2554
+ useEffect(() => {
2555
+ if (!variant || typeof window === "undefined") {
2556
+ return;
2590
2557
  }
2591
- return updatedCart;
2592
- }, [deliveryOptions, mutate, updateCartDeliveryOptions2]);
2593
- return useSWRMutation("update-cart-delivery-options", handler, options);
2594
- };
2595
- var usePlusMemberItemCustomAttributes = ({
2596
- deliveryData
2597
- }) => {
2598
- const { deliveryCustomData } = deliveryData || {};
2599
- return useMemo(() => {
2600
- const itemCustomAttributes = [];
2601
- if (deliveryCustomData?.is_presale) {
2602
- itemCustomAttributes.push({
2603
- key: "_is_presale",
2604
- value: "true"
2605
- });
2558
+ const searchParams = new URLSearchParams(window.location.search);
2559
+ const currentVariantId = searchParams.get("variant");
2560
+ const newVariantId = decodeShopifyId3(variant.id);
2561
+ if (newVariantId && currentVariantId !== newVariantId) {
2562
+ searchParams.set("variant", newVariantId);
2563
+ const newUrl = `${window.location.pathname}?${searchParams.toString()}${window.location.hash}`;
2564
+ window.history.replaceState({}, "", newUrl);
2606
2565
  }
2607
- return itemCustomAttributes;
2608
- }, [deliveryCustomData]);
2609
- };
2610
- var usePlusMemberCheckoutCustomAttributes = ({
2611
- deliveryData,
2566
+ }, [variant]);
2567
+ }
2568
+ function getVariantMediaList({
2612
2569
  product,
2613
- variant,
2614
- customer,
2615
- isShowShippingBenefits
2616
- }) => {
2617
- const { deliveryCustomData } = deliveryData || {};
2618
- const { profile } = usePlusMemberContext();
2619
- const userType = useMemo(() => {
2620
- const customerInfo = customer;
2621
- if (!customerInfo) {
2622
- return "new_user_unlogin";
2623
- }
2624
- if (customer) {
2625
- const { orders = {} } = customer;
2626
- const edgesLength = orders?.edges?.length;
2627
- if (edgesLength === 1) {
2628
- return "old_user_orders_once";
2629
- } else if (edgesLength && edgesLength > 1) {
2630
- return "old_user_orders_twice";
2631
- }
2632
- }
2633
- return "new_user_login";
2634
- }, [customer]);
2635
- return useMemo(() => {
2636
- const checkoutCustomAttributes = [
2637
- {
2638
- key: "_token",
2639
- value: profile?.token || ""
2640
- },
2641
- {
2642
- key: "_last_url",
2643
- value: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
2644
- },
2645
- {
2646
- key: "_user_type",
2647
- value: userType
2570
+ variant
2571
+ }) {
2572
+ if (variant.image?.url) {
2573
+ const variantMediaId = variant.image.url;
2574
+ const variantMedia = product.media.filter((media) => {
2575
+ if (media.mediaContentType === "IMAGE" && media.previewImage) {
2576
+ return media.previewImage?.url === variantMediaId;
2648
2577
  }
2649
- ];
2650
- if (profile) {
2651
- checkoutCustomAttributes.push({
2652
- key: "_login_user",
2653
- value: "1"
2654
- });
2655
- }
2656
- if (deliveryCustomData) {
2657
- checkoutCustomAttributes.push({
2658
- key: "_checkout_delivery_custom",
2659
- value: JSON.stringify({
2660
- ...deliveryCustomData,
2661
- is_prime: profile?.isPlus
2662
- })
2663
- });
2664
- }
2665
- if (variant?.metafields?.presell) {
2666
- checkoutCustomAttributes.push({
2667
- key: "_presale",
2668
- value: "true"
2669
- });
2670
- }
2671
- if (isShowShippingBenefits && !isShowShippingBenefits({ variant, product, setting: {} })) {
2672
- checkoutCustomAttributes.push({
2673
- key: "_hide_shipping",
2674
- value: "true"
2578
+ return false;
2579
+ });
2580
+ if (variantMedia.length > 0) {
2581
+ const otherMedia = product.media.filter((media) => {
2582
+ if (media.mediaContentType === "IMAGE" && media.previewImage) {
2583
+ return media.previewImage.url !== variantMediaId;
2584
+ }
2585
+ return true;
2675
2586
  });
2587
+ return [...variantMedia, ...otherMedia];
2676
2588
  }
2677
- return checkoutCustomAttributes;
2678
- }, [deliveryCustomData, product, profile, userType, variant, isShowShippingBenefits]);
2679
- };
2680
- function useAutoRemovePlusMemberInCart({
2681
- cart,
2682
- profile,
2683
- memberSetting
2589
+ }
2590
+ return product.media;
2591
+ }
2592
+ function useVariantMedia({
2593
+ product,
2594
+ variant
2684
2595
  }) {
2685
- const { plus_monthly_product, plus_annual_product } = memberSetting || {};
2686
- const { trigger: removeCartLines2 } = useRemoveCartLines();
2596
+ const [imageList, setImageList] = useState([]);
2597
+ const [sceneList, setSceneList] = useState([]);
2598
+ const [videoList, setVideoList] = useState([]);
2687
2599
  useEffect(() => {
2688
- if (!cart || !plus_monthly_product || !plus_annual_product) return;
2689
- const removePlusProduct = async (productType) => {
2690
- if (!productType) return;
2691
- const product = cart.lineItems?.find(
2692
- (item) => item.product?.handle === productType?.handle && item.variant?.sku === productType?.sku
2693
- );
2694
- if (product) {
2695
- await removeCartLines2({
2696
- lineIds: [product.id]
2697
- });
2600
+ if (!product || !variant) {
2601
+ setImageList([]);
2602
+ setSceneList([]);
2603
+ setVideoList([]);
2604
+ return;
2605
+ }
2606
+ const mediaList = getVariantMediaList({ product, variant });
2607
+ const images = mediaList.filter((media) => media.mediaContentType === "IMAGE");
2608
+ const videos = mediaList.filter(
2609
+ (media) => media.mediaContentType === "VIDEO" || media.mediaContentType === "EXTERNAL_VIDEO"
2610
+ );
2611
+ setImageList(images.length > 0 && images[0] ? [images[0]] : []);
2612
+ setSceneList(images.length > 1 ? images.slice(1) : []);
2613
+ setVideoList(videos);
2614
+ }, [product, variant]);
2615
+ return {
2616
+ productList: imageList,
2617
+ sceneList,
2618
+ videoList
2619
+ };
2620
+ }
2621
+ function useCollection(options = {}) {
2622
+ const { client, locale } = useShopify();
2623
+ const { handle, metafieldIdentifiers, ...swrOptions } = options;
2624
+ return useSWR(
2625
+ handle ? ["collection", locale, handle, metafieldIdentifiers] : null,
2626
+ () => getCollection(client, {
2627
+ handle,
2628
+ locale,
2629
+ metafieldIdentifiers
2630
+ }),
2631
+ swrOptions
2632
+ );
2633
+ }
2634
+ function useAllCollections(options = {}) {
2635
+ const { client, locale } = useShopify();
2636
+ const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2637
+ return useSWR(
2638
+ ["all-collections", locale, first, query, sortKey, reverse, metafieldIdentifiers],
2639
+ () => getAllCollections(client, {
2640
+ locale,
2641
+ first,
2642
+ query,
2643
+ sortKey,
2644
+ reverse,
2645
+ metafieldIdentifiers
2646
+ }),
2647
+ swrOptions
2648
+ );
2649
+ }
2650
+ function useCollections(options = {}) {
2651
+ const { client, locale } = useShopify();
2652
+ const { first, after, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2653
+ return useSWR(
2654
+ ["collections", locale, first, after, query, sortKey, reverse, metafieldIdentifiers],
2655
+ () => getCollections(client, {
2656
+ locale,
2657
+ first,
2658
+ after,
2659
+ query,
2660
+ sortKey,
2661
+ reverse,
2662
+ metafieldIdentifiers
2663
+ }),
2664
+ swrOptions
2665
+ );
2666
+ }
2667
+ function useBlog(options = {}) {
2668
+ const { client, locale } = useShopify();
2669
+ const { handle, metafieldIdentifiers, ...swrOptions } = options;
2670
+ return useSWR(
2671
+ handle ? ["blog", locale, handle, metafieldIdentifiers] : null,
2672
+ () => getBlog(client, { handle, locale, metafieldIdentifiers }),
2673
+ swrOptions
2674
+ );
2675
+ }
2676
+ function useAllBlogs(options = {}) {
2677
+ const { client, locale } = useShopify();
2678
+ const { first, query, metafieldIdentifiers, ...swrOptions } = options;
2679
+ return useSWR(
2680
+ ["all-blogs", locale, first, query, metafieldIdentifiers],
2681
+ () => getAllBlogs(client, {
2682
+ locale,
2683
+ first,
2684
+ query,
2685
+ metafieldIdentifiers
2686
+ }),
2687
+ swrOptions
2688
+ );
2689
+ }
2690
+ function useArticle(options = {}) {
2691
+ const { client, locale } = useShopify();
2692
+ const { blogHandle, articleHandle, metafieldIdentifiers, ...swrOptions } = options;
2693
+ return useSWR(
2694
+ blogHandle && articleHandle ? ["article", locale, blogHandle, articleHandle, metafieldIdentifiers] : null,
2695
+ () => getArticle(client, {
2696
+ blogHandle,
2697
+ articleHandle,
2698
+ locale,
2699
+ metafieldIdentifiers
2700
+ }),
2701
+ swrOptions
2702
+ );
2703
+ }
2704
+ function useArticles(options = {}) {
2705
+ const { client, locale } = useShopify();
2706
+ const { first, query, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2707
+ return useSWR(
2708
+ ["articles", locale, first, query, sortKey, reverse, metafieldIdentifiers],
2709
+ () => getArticles(client, {
2710
+ locale,
2711
+ first,
2712
+ query,
2713
+ sortKey,
2714
+ reverse,
2715
+ metafieldIdentifiers
2716
+ }),
2717
+ swrOptions
2718
+ );
2719
+ }
2720
+ function useArticlesInBlog(options = {}) {
2721
+ const { client, locale } = useShopify();
2722
+ const { blogHandle, first, sortKey, reverse, metafieldIdentifiers, ...swrOptions } = options;
2723
+ return useSWR(
2724
+ blogHandle ? ["articles-in-blog", locale, blogHandle, first, sortKey, reverse, metafieldIdentifiers] : null,
2725
+ () => getArticlesInBlog(client, {
2726
+ blogHandle,
2727
+ locale,
2728
+ first,
2729
+ sortKey,
2730
+ reverse,
2731
+ metafieldIdentifiers
2732
+ }),
2733
+ swrOptions
2734
+ );
2735
+ }
2736
+ async function performSearch(client, locale, searchQuery, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"]) {
2737
+ if (!searchQuery) {
2738
+ return void 0;
2739
+ }
2740
+ const query = (
2741
+ /* GraphQL */
2742
+ `
2743
+ query search($query: String!, $first: Int!, $types: [SearchType!])
2744
+ @inContext(language: $language) {
2745
+ search(query: $query, first: $first, types: $types, unavailableProducts: HIDE) {
2746
+ totalCount
2747
+ edges {
2748
+ node {
2749
+ ... on Article {
2750
+ __typename
2751
+ id
2752
+ handle
2753
+ title
2754
+ excerpt
2755
+ image {
2756
+ url
2757
+ altText
2758
+ }
2759
+ }
2760
+ ... on Page {
2761
+ __typename
2762
+ id
2763
+ handle
2764
+ title
2765
+ }
2766
+ ... on Product {
2767
+ __typename
2768
+ id
2769
+ handle
2770
+ title
2771
+ description
2772
+ featuredImage {
2773
+ url
2774
+ altText
2775
+ }
2776
+ }
2777
+ }
2778
+ }
2779
+ pageInfo {
2780
+ hasNextPage
2781
+ endCursor
2782
+ }
2698
2783
  }
2699
- };
2700
- if (profile?.isMonthlyPlus) {
2701
- removePlusProduct(plus_monthly_product);
2702
- }
2703
- if (profile?.isAnnualPlus) {
2704
- removePlusProduct(plus_annual_product);
2705
2784
  }
2706
- }, [cart, plus_annual_product, plus_monthly_product, profile, removeCartLines2]);
2707
- }
2708
- function useAddPlusMemberProductsToCart({
2709
- cart,
2710
- profile
2711
- }) {
2712
- const { selectedPlusMemberMode, selectedPlusMemberProduct, plusMemberMetafields } = usePlusMemberContext();
2713
- const { hasMonthlyPlus, hasAnnualPlus } = useHasPlusMemberInCart({
2714
- memberSetting: plusMemberMetafields,
2715
- cart
2785
+ `
2786
+ );
2787
+ const data = await client.query(query, {
2788
+ query: searchQuery,
2789
+ first,
2790
+ types
2716
2791
  });
2717
- const plusMemberProduct = useMemo(() => {
2718
- if (!selectedPlusMemberProduct || selectedPlusMemberMode === "free" /* FREE */) {
2719
- return void 0;
2720
- }
2721
- if (selectedPlusMemberMode === "monthly" /* MONTHLY */ && hasMonthlyPlus) {
2722
- return void 0;
2723
- }
2724
- if (selectedPlusMemberMode === "annual" /* ANNUAL */ && hasAnnualPlus) {
2725
- return void 0;
2726
- }
2727
- if (profile?.isMonthlyPlus && selectedPlusMemberMode === "monthly" /* MONTHLY */) {
2728
- return void 0;
2729
- }
2730
- if (!profile?.isAnnualPlus && selectedPlusMemberMode === "annual" /* ANNUAL */) {
2731
- return void 0;
2792
+ if (!data || !data.search) {
2793
+ return void 0;
2794
+ }
2795
+ const items = data.search.edges?.map((edge) => {
2796
+ const node = edge.node;
2797
+ const item = {
2798
+ type: node.__typename.toUpperCase(),
2799
+ id: node.id,
2800
+ handle: node.handle,
2801
+ title: node.title
2802
+ };
2803
+ if (node.__typename === "Product") {
2804
+ item.description = node.description;
2805
+ item.image = node.featuredImage ? {
2806
+ url: node.featuredImage.url,
2807
+ altText: node.featuredImage.altText
2808
+ } : void 0;
2809
+ } else if (node.__typename === "Article") {
2810
+ item.description = node.excerpt;
2811
+ item.image = node.image ? {
2812
+ url: node.image.url,
2813
+ altText: node.image.altText
2814
+ } : void 0;
2732
2815
  }
2733
- return selectedPlusMemberProduct;
2734
- }, [
2735
- selectedPlusMemberMode,
2736
- selectedPlusMemberProduct?.variant,
2737
- selectedPlusMemberProduct?.product,
2738
- hasMonthlyPlus,
2739
- hasAnnualPlus
2740
- ]);
2741
- return plusMemberProduct;
2816
+ return item;
2817
+ }) || [];
2818
+ return {
2819
+ items,
2820
+ totalCount: data.search.totalCount || 0,
2821
+ pageInfo: data.search.pageInfo
2822
+ };
2742
2823
  }
2743
- var PlusMemberProvider = ({
2744
- variant,
2745
- product,
2746
- memberSetting,
2747
- initialSelectedPlusMemberMode = "free",
2748
- profile,
2749
- locale,
2750
- children
2751
- }) => {
2752
- const [zipCode, setZipCode] = useState("");
2753
- const [showTip, setShowTip] = useState(false);
2754
- const [selectedPlusMemberMode, setSelectedPlusMemberMode] = useState(
2755
- initialSelectedPlusMemberMode
2824
+ function useSearch(options = {}) {
2825
+ const { client, locale } = useShopify();
2826
+ const { query, first = 20, types = ["PRODUCT", "ARTICLE", "PAGE"], ...swrOptions } = options;
2827
+ return useSWR(
2828
+ query ? ["search", locale, query, first, types] : null,
2829
+ () => performSearch(client, locale, query, first, types),
2830
+ swrOptions
2756
2831
  );
2757
- const [selectedShippingMethod, setSelectedShippingMethod] = useState();
2758
- const [allowNextDayDelivery, setAllowNextDayDelivery] = useState(false);
2759
- const [allowThirdDayDelivery, setAllowThirdDayDelivery] = useState(false);
2760
- const [showAreaCheckModal, setShowAreaCheckModal] = useState(false);
2761
- const [showMoreShippingMethod, setShowMoreShippingMethod] = useState(false);
2762
- const [showPlusMemberBenefit, setShowPlusMemberBenefit] = useState(false);
2763
- const [deleteMarginBottom, setDeleteMarginBottom] = useState(false);
2764
- const shippingMethodsContext = useShippingMethods({
2765
- variant,
2766
- plusMemberMetafields: memberSetting,
2767
- selectedPlusMemberMode});
2768
- const plusMemberHandles = useMemo(() => {
2769
- return [
2770
- memberSetting?.plus_monthly_product?.handle,
2771
- memberSetting?.plus_annual_product?.handle
2772
- ].filter(Boolean);
2773
- }, [memberSetting]);
2774
- const { data: plusMemberProducts = [] } = useProductsByHandles({
2775
- handles: plusMemberHandles
2776
- });
2777
- const selectedPlusMemberProduct = useMemo(() => {
2778
- if (selectedPlusMemberMode === "free" /* FREE */) {
2779
- return null;
2832
+ }
2833
+ async function getSiteInfo(client, locale, metafieldIdentifiers) {
2834
+ const hasMetafields = metafieldIdentifiers && metafieldIdentifiers.length > 0;
2835
+ const query = (
2836
+ /* GraphQL */
2837
+ `
2838
+ query getSiteInfo(
2839
+ ${hasMetafields ? "$shopMetafieldIdentifiers: [HasMetafieldsIdentifier!]!" : ""}
2840
+ ) @inContext(language: $language) {
2841
+ shop {
2842
+ name
2843
+ description
2844
+ primaryDomain {
2845
+ url
2846
+ host
2847
+ }
2848
+ brand {
2849
+ logo {
2850
+ image {
2851
+ url
2852
+ }
2853
+ }
2854
+ colors {
2855
+ primary {
2856
+ background
2857
+ }
2858
+ secondary {
2859
+ background
2860
+ }
2861
+ }
2862
+ }
2863
+ ${hasMetafields ? "metafields(identifiers: $shopMetafieldIdentifiers) { key value }" : ""}
2864
+ }
2780
2865
  }
2781
- const handle = selectedPlusMemberMode === "monthly" /* MONTHLY */ ? memberSetting?.plus_monthly_product?.handle : memberSetting?.plus_annual_product?.handle;
2782
- const sku = selectedPlusMemberMode === "monthly" /* MONTHLY */ ? memberSetting?.plus_monthly_product?.sku : memberSetting?.plus_annual_product?.sku;
2783
- const product2 = plusMemberProducts?.find((p) => p.handle === handle);
2784
- const variant2 = product2?.variants?.find((v) => v.sku === sku);
2785
- return product2 && variant2 ? { product: product2, variant: variant2 } : null;
2786
- }, [plusMemberProducts, memberSetting, selectedPlusMemberMode]);
2787
- return /* @__PURE__ */ jsx(
2788
- PlusMemberContext.Provider,
2789
- {
2790
- value: {
2791
- variant,
2792
- zipCode,
2793
- setZipCode,
2794
- allowNextDayDelivery,
2795
- setAllowNextDayDelivery,
2796
- allowThirdDayDelivery,
2797
- setAllowThirdDayDelivery,
2798
- plusMemberMetafields: memberSetting,
2799
- selectedPlusMemberMode,
2800
- setSelectedPlusMemberMode,
2801
- showAreaCheckModal,
2802
- setShowAreaCheckModal,
2803
- selectedShippingMethod,
2804
- setSelectedShippingMethod,
2805
- shippingMethodsContext,
2806
- showTip,
2807
- setShowTip,
2808
- showMoreShippingMethod,
2809
- setShowMoreShippingMethod,
2810
- selectedPlusMemberProduct,
2811
- plusMemberProducts,
2812
- product,
2813
- showPlusMemberBenefit,
2814
- setShowPlusMemberBenefit,
2815
- deleteMarginBottom,
2816
- setDeleteMarginBottom,
2817
- profile,
2818
- locale
2819
- },
2820
- children
2866
+ `
2867
+ );
2868
+ const variables = {};
2869
+ if (hasMetafields) {
2870
+ variables.shopMetafieldIdentifiers = metafieldIdentifiers;
2871
+ }
2872
+ const data = await client.query(query, variables);
2873
+ if (!data || !data.shop) {
2874
+ return void 0;
2875
+ }
2876
+ const shop = data.shop;
2877
+ const metafields = shop.metafields?.reduce((acc, mf) => {
2878
+ if (mf && mf.key) {
2879
+ acc[mf.key] = mf.value;
2821
2880
  }
2881
+ return acc;
2882
+ }, {});
2883
+ return {
2884
+ name: shop.name,
2885
+ description: shop.description,
2886
+ primaryDomain: shop.primaryDomain,
2887
+ brand: shop.brand ? {
2888
+ logo: shop.brand.logo,
2889
+ colors: shop.brand.colors ? {
2890
+ primary: shop.brand.colors.primary?.background,
2891
+ secondary: shop.brand.colors.secondary?.background
2892
+ } : void 0
2893
+ } : void 0,
2894
+ metafields
2895
+ };
2896
+ }
2897
+ function useSite(options = {}) {
2898
+ const { client, locale } = useShopify();
2899
+ const { metafieldIdentifiers, ...swrOptions } = options;
2900
+ return useSWR(
2901
+ ["site", locale, metafieldIdentifiers],
2902
+ () => getSiteInfo(client, locale, metafieldIdentifiers),
2903
+ swrOptions
2822
2904
  );
2823
- };
2905
+ }
2824
2906
  function useIntersection(targetRef, options) {
2825
2907
  const {
2826
2908
  callback,
@@ -3001,6 +3083,6 @@ function clearGeoLocationCache(cacheKey = "geoLocation") {
3001
3083
  }
3002
3084
  }
3003
3085
 
3004
- export { BuyRuleType, CODE_AMOUNT_KEY, CUSTOMER_ATTRIBUTE_KEY, CUSTOMER_SCRIPT_GIFT_KEY, DeliveryPlusType, MAIN_PRODUCT_CODE, OrderBasePriceType, OrderDiscountType, PLUS_MEMBER_TYPE, PlusMemberContext, PlusMemberMode, PlusMemberProvider, PriceBasePriceType, PriceDiscountType, RuleType, SCRIPT_CODE_AMOUNT_KEY, ShippingMethodMode, SpendMoneyType, atobID, btoaID, checkAttributesUpdateNeeded, clearGeoLocationCache, createMockCartFromLines, currencyCodeMapping, defaultSWRMutationConfiguration, formatFunctionAutoFreeGift, formatScriptAutoFreeGift, getCachedGeoLocation, getDiscountEnvAttributeValue, getMatchedMainProductSubTotal, getQuery, getReferralAttributes, normalizeAddToCartLines, preCheck, safeParse, useAddCartLines, useAddPlusMemberProductsToCart, useAddToCart, useAllBlogs, useAllCollections, useAllProducts, useApplyCartCodes, useArticle, useArticles, useArticlesInBlog, useAutoRemovePlusMemberInCart, useBlog, useBuyNow, useCalcAutoFreeGift, useCalcGiftsFromLines, useCalcOrderDiscount, useCartAttributes, useCartItemQuantityLimit, useCollection, useCollections, useCreateCart, useExposure, useGeoLocation, useHasPlusMemberInCart, useIntersection, usePlusAnnualProductVariant, usePlusMemberCheckoutCustomAttributes, usePlusMemberContext, usePlusMemberDeliveryCodes, usePlusMemberItemCustomAttributes, usePlusMonthlyProductVariant, usePrice, useProduct, useProductUrl, useProductsByHandles, useRemoveCartCodes, useRemoveCartLines, useReplaceCartPlusMember, useScriptAutoFreeGift, useSearch, useSelectedOptions, useShippingMethodAvailableCheck, useShippingMethods, useSite, useUpdateCartAttributes, useUpdateCartLines, useUpdateLineCodeAmountAttributes, useUpdatePlusMemberDeliveryOptions, useUpdateVariantQuery, useVariant, useVariantMedia };
3086
+ export { BuyRuleType, CODE_AMOUNT_KEY, CUSTOMER_ATTRIBUTE_KEY, CUSTOMER_SCRIPT_GIFT_KEY, DeliveryPlusType, MAIN_PRODUCT_CODE, MEMBER_PRICE_ATTRIBUTE_KEY, OrderBasePriceType, OrderDiscountType, PLUS_MEMBER_TYPE, PlusMemberContext, PlusMemberMode, PlusMemberProvider, PriceBasePriceType, PriceDiscountType, RuleType, SCRIPT_CODE_AMOUNT_KEY, ShippingMethodMode, SpendMoneyType, clearGeoLocationCache, createMockCartFromLines, currencyCodeMapping, defaultSWRMutationConfiguration, formatFunctionAutoFreeGift, formatScriptAutoFreeGift, getCachedGeoLocation, getCartAttributes, getDiscountEnvAttributeValue, getMatchedMainProductSubTotal, getQuery, getReferralAttributes, getUserType, hasPlusMemberInCart, hasPlusMemberInLines, normalizeAddToCartLines, preCheck, safeParse, useAddCartLines, useAddToCart, useAllBlogs, useAllCollections, useAllProducts, useApplyCartCodes, useArticle, useArticles, useArticlesInBlog, useAutoRemovePlusMemberInCart, useAvailableDeliveryCoupon, useBlog, useBuyNow, useCalcAutoFreeGift, useCalcGiftsFromLines, useCalcOrderDiscount, useCartAttributes, useCartItemQuantityLimit, useCollection, useCollections, useCreateCart, useExposure, useGeoLocation, useHasPlusMemberInCart, useHasPlusMemberInLines, useIntersection, usePlusMemberCheckoutCustomAttributes, usePlusMemberContext, usePlusMemberNeedAddToCart, usePlusMemberVariants, usePrice, useProduct, useProductUrl, useProductsByHandles, useRemoveCartCodes, useRemoveCartLines, useReplaceCartPlusMember, useScriptAutoFreeGift, useSearch, useSelectedOptions, useShippingMethods, useSite, useUpdateCartAttributes, useUpdateCartLines, useUpdateLineCodeAmountAttributes, useUpdateVariantQuery, useVariant, useVariantMedia };
3005
3087
  //# sourceMappingURL=index.mjs.map
3006
3088
  //# sourceMappingURL=index.mjs.map