@anker-in/shopify-react 1.3.0-beta.1 → 1.3.0-beta.11

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,12 +1,12 @@
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, removeCartLines, getLocalStorage, updateCartLines, updateCartAttributes, updateBuyerIdentity, getProduct, getAllProducts, getCollection, getAllCollections, getCollections, getBlog, getAllBlogs, getArticle, getArticles, getArticlesInBlog, setLocalStorage } from '@anker-in/shopify-sdk';
3
+ import { getProductsByHandles, removeCartLines, updateCartCodes, createCart, addCartLines, updateCartLines, getLocalStorage, updateCartAttributes, updateBuyerIdentity, getProduct, getAllProducts, getCollection, getAllCollections, getCollections, getBlog, getAllBlogs, getArticle, getArticles, getArticlesInBlog, getShop, setLocalStorage } from '@anker-in/shopify-sdk';
4
4
  import Cookies5 from 'js-cookie';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
  import Decimal3 from 'decimal.js';
7
7
  import { atobID, btoaID } from '@anker-in/shopify-core';
8
8
  import useSWR from 'swr';
9
- import { useRequest } from 'ahooks';
9
+ import { useDebounceEffect, useRequest } from 'ahooks';
10
10
 
11
11
  // src/hooks/cart/use-create-cart.ts
12
12
  var ShopifyContext = createContext(null);
@@ -662,6 +662,177 @@ var useScriptAutoFreeGift = ({
662
662
  giftProductsResult: finalGiftProductsResult
663
663
  };
664
664
  };
665
+ function useRemoveCartLines(options) {
666
+ const { client, locale, cartCookieAdapter } = useShopify();
667
+ const { mutateCart, metafieldIdentifiers } = useCartContext();
668
+ const removeLines = useCallback(
669
+ async (_key, { arg }) => {
670
+ const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
671
+ let updatedCart = await removeCartLines(client, {
672
+ cartId,
673
+ lineIds,
674
+ metafieldIdentifiers,
675
+ cookieAdapter: cartCookieAdapter
676
+ });
677
+ if (updatedCart && autoRemoveInvalidCodes) {
678
+ const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
679
+ if (unApplicableCodes.length > 0) {
680
+ if (onCodesRemoved) {
681
+ const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
682
+ if (handledCart) {
683
+ updatedCart = handledCart;
684
+ }
685
+ } else {
686
+ updatedCart = await updateCartCodes(client, {
687
+ cartId: updatedCart.id,
688
+ discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
689
+ metafieldIdentifiers,
690
+ cookieAdapter: cartCookieAdapter
691
+ }) || updatedCart;
692
+ }
693
+ }
694
+ }
695
+ if (updatedCart) {
696
+ mutateCart(updatedCart);
697
+ }
698
+ return updatedCart;
699
+ },
700
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
701
+ );
702
+ return useSWRMutation("remove-cart-lines", removeLines, options);
703
+ }
704
+
705
+ // src/hooks/cart/feature/use-auto-remove-free-gifts.ts
706
+ function useAutoRemoveFreeGifts(options = {}) {
707
+ const {
708
+ removeFunctionGifts = true,
709
+ removeScriptGifts = true,
710
+ isGiftLineItem,
711
+ runOnlyOnceAfterInit = false,
712
+ initDelay = 500
713
+ } = options;
714
+ const [isRemoving, setIsRemoving] = useState(false);
715
+ const [isInitialized, setIsInitialized] = useState(!runOnlyOnceAfterInit);
716
+ const [isFinished, setIsFinished] = useState(false);
717
+ const { cart } = useCartContext();
718
+ const { trigger: removeCartLines2 } = useRemoveCartLines();
719
+ const giftsToRemove = useMemo(() => {
720
+ if (!cart?.lineItems) {
721
+ return [];
722
+ }
723
+ return cart.lineItems.filter((item) => {
724
+ if (removeFunctionGifts) {
725
+ const functionAttr = item.customAttributes?.find(
726
+ (attr) => attr.key === "_discounts_function_env"
727
+ )?.value;
728
+ if (functionAttr) {
729
+ try {
730
+ const functionAttrObj = JSON.parse(functionAttr);
731
+ if (functionAttrObj.is_gift && functionAttrObj.rule_id && functionAttrObj.spend_sum_money) {
732
+ return true;
733
+ }
734
+ } catch (error) {
735
+ console.error("Failed to parse _discounts_function_env:", error);
736
+ }
737
+ }
738
+ }
739
+ if (removeScriptGifts) {
740
+ const scriptGiftAttr = item.customAttributes?.find(
741
+ (attr) => attr.key === "_giveaway_gradient_gifts"
742
+ );
743
+ if (scriptGiftAttr) {
744
+ return true;
745
+ }
746
+ }
747
+ if (isGiftLineItem && isGiftLineItem(item)) {
748
+ return true;
749
+ }
750
+ return false;
751
+ });
752
+ }, [cart, removeFunctionGifts, removeScriptGifts, isGiftLineItem]);
753
+ useDebounceEffect(
754
+ () => {
755
+ if (!runOnlyOnceAfterInit || isInitialized || isFinished) {
756
+ return;
757
+ }
758
+ if (!cart?.lineItems?.length) {
759
+ return;
760
+ }
761
+ setIsInitialized(true);
762
+ if (giftsToRemove.length === 0) {
763
+ setIsFinished(true);
764
+ }
765
+ },
766
+ [runOnlyOnceAfterInit, isInitialized, isFinished, cart?.lineItems, giftsToRemove.length],
767
+ {
768
+ trailing: true,
769
+ wait: initDelay
770
+ }
771
+ );
772
+ useEffect(() => {
773
+ if (runOnlyOnceAfterInit && (!isInitialized || isFinished)) {
774
+ return;
775
+ }
776
+ if (isRemoving || giftsToRemove.length === 0) {
777
+ return;
778
+ }
779
+ const performRemoval = async () => {
780
+ setIsRemoving(true);
781
+ try {
782
+ await removeCartLines2({
783
+ lineIds: giftsToRemove.map((item) => item.id)
784
+ });
785
+ } catch (error) {
786
+ console.error("Failed to remove free gifts:", error);
787
+ } finally {
788
+ setIsRemoving(false);
789
+ if (runOnlyOnceAfterInit) {
790
+ setIsFinished(true);
791
+ }
792
+ }
793
+ };
794
+ performRemoval();
795
+ }, [
796
+ runOnlyOnceAfterInit,
797
+ isInitialized,
798
+ isFinished,
799
+ isRemoving,
800
+ giftsToRemove,
801
+ removeCartLines2
802
+ ]);
803
+ return {
804
+ isRemoving
805
+ };
806
+ }
807
+ function isFunctionGift(line) {
808
+ const functionAttr = line.customAttributes?.find(
809
+ (attr) => attr.key === "_discounts_function_env"
810
+ )?.value;
811
+ if (!functionAttr) {
812
+ return false;
813
+ }
814
+ try {
815
+ const functionAttrObj = JSON.parse(functionAttr);
816
+ return Boolean(
817
+ functionAttrObj.is_gift && functionAttrObj.rule_id && functionAttrObj.spend_sum_money
818
+ );
819
+ } catch {
820
+ return false;
821
+ }
822
+ }
823
+ function isScriptGift(line) {
824
+ return line.customAttributes?.some(
825
+ (attr) => attr.key === "_giveaway_gradient_gifts"
826
+ ) ?? false;
827
+ }
828
+ function isBuyGetGift(line) {
829
+ return line.customAttributes?.some(
830
+ (attr) => attr.key === "_freegift_related_handlesku"
831
+ ) ?? false;
832
+ }
833
+ function isAnyGift(line) {
834
+ return isFunctionGift(line) || isScriptGift(line) || isBuyGetGift(line);
835
+ }
665
836
  var CartContext = createContext(null);
666
837
  function useCartContext(options) {
667
838
  const context = useContext(CartContext);
@@ -985,6 +1156,26 @@ function useRemoveCartCodes(options) {
985
1156
  );
986
1157
  return useSWRMutation("remove-codes", removeCodes, options);
987
1158
  }
1159
+ function useUpdateCartLines(options) {
1160
+ const { client, locale, cartCookieAdapter } = useShopify();
1161
+ const { mutateCart, metafieldIdentifiers } = useCartContext();
1162
+ const updateLines = useCallback(
1163
+ async (_key, { arg }) => {
1164
+ const updatedCart = await updateCartLines(client, {
1165
+ ...arg,
1166
+ metafieldIdentifiers,
1167
+ cookieAdapter: cartCookieAdapter
1168
+ });
1169
+ if (updatedCart) {
1170
+ mutateCart(updatedCart);
1171
+ }
1172
+ console.log("use-update-cart-lines updatedCart", metafieldIdentifiers, updatedCart);
1173
+ return updatedCart;
1174
+ },
1175
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
1176
+ );
1177
+ return useSWRMutation("update-cart-lines", updateLines, options);
1178
+ }
988
1179
  var initSameLinesAttributes = ({
989
1180
  cart,
990
1181
  line
@@ -1072,145 +1263,6 @@ var getLinesWithAttributes = ({
1072
1263
  return functionLine;
1073
1264
  });
1074
1265
  };
1075
- function useRemoveCartLines(options) {
1076
- const { client, locale, cartCookieAdapter } = useShopify();
1077
- const { mutateCart, metafieldIdentifiers } = useCartContext();
1078
- const removeLines = useCallback(
1079
- async (_key, { arg }) => {
1080
- const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
1081
- let updatedCart = await removeCartLines(client, {
1082
- cartId,
1083
- lineIds,
1084
- metafieldIdentifiers,
1085
- cookieAdapter: cartCookieAdapter
1086
- });
1087
- if (updatedCart && autoRemoveInvalidCodes) {
1088
- const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
1089
- if (unApplicableCodes.length > 0) {
1090
- if (onCodesRemoved) {
1091
- const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
1092
- if (handledCart) {
1093
- updatedCart = handledCart;
1094
- }
1095
- } else {
1096
- updatedCart = await updateCartCodes(client, {
1097
- cartId: updatedCart.id,
1098
- discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
1099
- metafieldIdentifiers,
1100
- cookieAdapter: cartCookieAdapter
1101
- }) || updatedCart;
1102
- }
1103
- }
1104
- }
1105
- if (updatedCart) {
1106
- mutateCart(updatedCart);
1107
- }
1108
- return updatedCart;
1109
- },
1110
- [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
1111
- );
1112
- return useSWRMutation("remove-cart-lines", removeLines, options);
1113
- }
1114
-
1115
- // src/hooks/cart/feature/use-auto-remove-free-gifts.ts
1116
- function useAutoRemoveFreeGifts(options = {}) {
1117
- const {
1118
- removeFunctionGifts = true,
1119
- removeScriptGifts = true,
1120
- isGiftLineItem
1121
- } = options;
1122
- const [isRemoving, setIsRemoving] = useState(false);
1123
- const { cart } = useCartContext();
1124
- const { trigger: removeCartLines2 } = useRemoveCartLines();
1125
- const giftsToRemove = useMemo(() => {
1126
- if (!cart?.lineItems) {
1127
- return [];
1128
- }
1129
- return cart.lineItems.filter((item) => {
1130
- if (removeFunctionGifts) {
1131
- const functionAttr = item.customAttributes?.find(
1132
- (attr) => attr.key === "_discounts_function_env"
1133
- )?.value;
1134
- if (functionAttr) {
1135
- try {
1136
- const functionAttrObj = JSON.parse(functionAttr);
1137
- if (functionAttrObj.is_gift && functionAttrObj.rule_id && functionAttrObj.spend_sum_money) {
1138
- return true;
1139
- }
1140
- } catch (error) {
1141
- console.error("Failed to parse _discounts_function_env:", error);
1142
- }
1143
- }
1144
- }
1145
- if (removeScriptGifts) {
1146
- const scriptGiftAttr = item.customAttributes?.find(
1147
- (attr) => attr.key === "_giveaway_gradient_gifts"
1148
- );
1149
- if (scriptGiftAttr) {
1150
- return true;
1151
- }
1152
- }
1153
- if (isGiftLineItem && isGiftLineItem(item)) {
1154
- return true;
1155
- }
1156
- return false;
1157
- });
1158
- }, [cart, removeFunctionGifts, removeScriptGifts, isGiftLineItem]);
1159
- useEffect(() => {
1160
- if (isRemoving || giftsToRemove.length === 0) {
1161
- return;
1162
- }
1163
- const performRemoval = async () => {
1164
- setIsRemoving(true);
1165
- try {
1166
- await removeCartLines2({
1167
- lineIds: giftsToRemove.map((item) => item.id)
1168
- });
1169
- } catch (error) {
1170
- console.error("Failed to remove free gifts:", error);
1171
- } finally {
1172
- setIsRemoving(false);
1173
- }
1174
- };
1175
- performRemoval();
1176
- }, [
1177
- isRemoving,
1178
- giftsToRemove,
1179
- removeCartLines2
1180
- ]);
1181
- return {
1182
- isRemoving
1183
- };
1184
- }
1185
- function isFunctionGift(line) {
1186
- const functionAttr = line.customAttributes?.find(
1187
- (attr) => attr.key === "_discounts_function_env"
1188
- )?.value;
1189
- if (!functionAttr) {
1190
- return false;
1191
- }
1192
- try {
1193
- const functionAttrObj = JSON.parse(functionAttr);
1194
- return Boolean(
1195
- functionAttrObj.is_gift && functionAttrObj.rule_id && functionAttrObj.spend_sum_money
1196
- );
1197
- } catch {
1198
- return false;
1199
- }
1200
- }
1201
- function isScriptGift(line) {
1202
- return line.customAttributes?.some(
1203
- (attr) => attr.key === "_giveaway_gradient_gifts"
1204
- ) ?? false;
1205
- }
1206
- function isBuyGetGift(line) {
1207
- return line.customAttributes?.some(
1208
- (attr) => attr.key === "_freegift_related_handlesku"
1209
- ) ?? false;
1210
- }
1211
- function isAnyGift(line) {
1212
- return isFunctionGift(line) || isScriptGift(line) || isBuyGetGift(line);
1213
- }
1214
1266
  function useCalcGiftsFromLines({
1215
1267
  lines,
1216
1268
  customer,
@@ -2285,6 +2337,7 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
2285
2337
  const { trigger: applyCartCodes } = useApplyCartCodes();
2286
2338
  const { trigger: removeInvalidCodes } = useRemoveCartCodes();
2287
2339
  const { trigger: addCartLines2 } = useAddCartLines();
2340
+ const { trigger: updateCartLines3 } = useUpdateCartLines();
2288
2341
  const { trigger: createCart4 } = useCreateCart({
2289
2342
  updateCookie: true
2290
2343
  });
@@ -2337,10 +2390,36 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
2337
2390
  // 初次加购时,就把所有 cart attributes 带上
2338
2391
  });
2339
2392
  } else {
2340
- resultCart = await addCartLines2({
2341
- cartId,
2342
- lines
2393
+ const linesToUpdate = [];
2394
+ const linesToAddNew = lines.filter((lineToAdd) => {
2395
+ const existingLine = cart?.lineItems?.find(
2396
+ (item) => item.variant?.id === lineToAdd.merchandiseId
2397
+ );
2398
+ if (existingLine) {
2399
+ linesToUpdate.push({
2400
+ id: existingLine.id,
2401
+ quantity: existingLine.quantity + (lineToAdd.quantity || 1),
2402
+ attributes: lineToAdd.attributes || void 0
2403
+ });
2404
+ return false;
2405
+ }
2406
+ return true;
2343
2407
  });
2408
+ if (linesToUpdate.length > 0) {
2409
+ resultCart = await updateCartLines3({
2410
+ cartId,
2411
+ lines: linesToUpdate
2412
+ });
2413
+ }
2414
+ if (linesToAddNew.length > 0) {
2415
+ resultCart = await addCartLines2({
2416
+ cartId: resultCart?.id || cartId,
2417
+ lines: linesToAddNew
2418
+ });
2419
+ }
2420
+ if (!resultCart) {
2421
+ resultCart = cart;
2422
+ }
2344
2423
  console.log("npm addCartLines resultCart", resultCart);
2345
2424
  if (resultCart && resultCart.discountCodes && resultCart.discountCodes.length > 0) {
2346
2425
  const unapplicableCodes = resultCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
@@ -2401,6 +2480,7 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
2401
2480
  performanceAdapter,
2402
2481
  createCart4,
2403
2482
  addCartLines2,
2483
+ updateCartLines3,
2404
2484
  applyCartCodes,
2405
2485
  removeInvalidCodes,
2406
2486
  addCustomAttributes,
@@ -2410,26 +2490,6 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
2410
2490
  );
2411
2491
  return useSWRMutation("add-to-cart", addToCart, swrOptions);
2412
2492
  }
2413
- function useUpdateCartLines(options) {
2414
- const { client, locale, cartCookieAdapter } = useShopify();
2415
- const { mutateCart, metafieldIdentifiers } = useCartContext();
2416
- const updateLines = useCallback(
2417
- async (_key, { arg }) => {
2418
- const updatedCart = await updateCartLines(client, {
2419
- ...arg,
2420
- metafieldIdentifiers,
2421
- cookieAdapter: cartCookieAdapter
2422
- });
2423
- if (updatedCart) {
2424
- mutateCart(updatedCart);
2425
- }
2426
- console.log("use-update-cart-lines updatedCart", metafieldIdentifiers, updatedCart);
2427
- return updatedCart;
2428
- },
2429
- [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
2430
- );
2431
- return useSWRMutation("update-cart-lines", updateLines, options);
2432
- }
2433
2493
  function useUpdateCartAttributes({
2434
2494
  mutate,
2435
2495
  metafieldIdentifiers,
@@ -3028,8 +3088,7 @@ async function performSearch(client, locale, searchQuery, first = 20, types = ["
3028
3088
  const query = (
3029
3089
  /* GraphQL */
3030
3090
  `
3031
- query search($query: String!, $first: Int!, $types: [SearchType!])
3032
- @inContext(language: $language) {
3091
+ query search($query: String!, $first: Int!, $types: [SearchType!]) {
3033
3092
  search(query: $query, first: $first, types: $types, unavailableProducts: HIDE) {
3034
3093
  totalCount
3035
3094
  edges {
@@ -3118,76 +3177,15 @@ function useSearch(options = {}) {
3118
3177
  swrOptions
3119
3178
  );
3120
3179
  }
3121
- async function getSiteInfo(client, locale, metafieldIdentifiers) {
3122
- const hasMetafields = metafieldIdentifiers && metafieldIdentifiers.length > 0;
3123
- const query = (
3124
- /* GraphQL */
3125
- `
3126
- query getSiteInfo(
3127
- ${hasMetafields ? "$shopMetafieldIdentifiers: [HasMetafieldsIdentifier!]!" : ""}
3128
- ) @inContext(language: $language) {
3129
- shop {
3130
- name
3131
- description
3132
- primaryDomain {
3133
- url
3134
- host
3135
- }
3136
- brand {
3137
- logo {
3138
- image {
3139
- url
3140
- }
3141
- }
3142
- colors {
3143
- primary {
3144
- background
3145
- }
3146
- secondary {
3147
- background
3148
- }
3149
- }
3150
- }
3151
- ${hasMetafields ? "metafields(identifiers: $shopMetafieldIdentifiers) { key value }" : ""}
3152
- }
3153
- }
3154
- `
3155
- );
3156
- const variables = {};
3157
- if (hasMetafields) {
3158
- variables.shopMetafieldIdentifiers = metafieldIdentifiers;
3159
- }
3160
- const data = await client.query(query, variables);
3161
- if (!data || !data.shop) {
3162
- return void 0;
3163
- }
3164
- const shop = data.shop;
3165
- const metafields = shop.metafields?.reduce((acc, mf) => {
3166
- if (mf && mf.key) {
3167
- acc[mf.key] = mf.value;
3168
- }
3169
- return acc;
3170
- }, {});
3171
- return {
3172
- name: shop.name,
3173
- description: shop.description,
3174
- primaryDomain: shop.primaryDomain,
3175
- brand: shop.brand ? {
3176
- logo: shop.brand.logo,
3177
- colors: shop.brand.colors ? {
3178
- primary: shop.brand.colors.primary?.background,
3179
- secondary: shop.brand.colors.secondary?.background
3180
- } : void 0
3181
- } : void 0,
3182
- metafields
3183
- };
3184
- }
3185
3180
  function useSite(options = {}) {
3186
3181
  const { client, locale } = useShopify();
3187
3182
  const { metafieldIdentifiers, ...swrOptions } = options;
3188
3183
  return useSWR(
3189
3184
  ["site", locale, metafieldIdentifiers],
3190
- () => getSiteInfo(client, locale, metafieldIdentifiers),
3185
+ () => getShop(client, {
3186
+ locale,
3187
+ metafieldIdentifiers
3188
+ }),
3191
3189
  swrOptions
3192
3190
  );
3193
3191
  }