@anker-in/shopify-react 1.1.1 → 1.2.0-beta.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.
package/dist/index.js CHANGED
@@ -885,15 +885,23 @@ var trackAddToCartGA = ({
885
885
  currency: currencyCode,
886
886
  value: totalPrice,
887
887
  position: gtmParams?.position || "",
888
- items: lineItems.map(({ variant: variant2, quantity }) => ({
889
- item_id: variant2?.sku,
890
- item_name: variant2?.product?.title || variant2?.product?.title,
891
- item_brand: gtmParams?.brand || "",
892
- item_category: variant2?.product?.productType || "",
893
- item_variant: variant2?.title || variant2?.title,
894
- price: variant2?.compareAtPrice?.amount ?? variant2?.price?.amount,
895
- quantity: quantity || 1
896
- })),
888
+ items: lineItems.map((item) => {
889
+ const imageUrl = item.variant?.image?.url || item.variant?.product?.images?.[0]?.url;
890
+ const itemCategoryId = item.gtmParams?.item_category_id;
891
+ const itemVariantId = item.variant?.id ? shopifyCore.atobID(item.variant.id) : void 0;
892
+ return {
893
+ item_id: item.variant?.sku,
894
+ item_name: item.variant?.product?.title || item.variant?.product?.title,
895
+ item_brand: gtmParams?.brand || "",
896
+ item_category: item.variant?.product?.productType || "",
897
+ item_variant: item.variant?.title || item.variant?.title,
898
+ price: item.variant?.compareAtPrice?.amount ?? item.variant?.price?.amount,
899
+ quantity: item.quantity || 1,
900
+ ...imageUrl && { image_url: imageUrl },
901
+ ...itemCategoryId && { item_category_id: itemCategoryId },
902
+ ...itemVariantId && { item_variant_id: itemVariantId }
903
+ };
904
+ }),
897
905
  ...gtmParams?.ga4Params
898
906
  }
899
907
  });
@@ -920,15 +928,23 @@ var trackBeginCheckoutGA = ({
920
928
  position: gtmParams?.position,
921
929
  currency: currencyCode,
922
930
  value: totalPrice,
923
- items: lineItems.map((item) => ({
924
- item_id: item.variant?.sku,
925
- item_name: item.variant?.product?.title,
926
- item_brand: gtmParams?.brand || "",
927
- item_category: item.variant?.product?.productType,
928
- item_variant: item.variant?.title,
929
- price: item.variant?.compareAtPrice?.amount ?? item.variant?.price?.amount,
930
- quantity: item.quantity || 1
931
- })),
931
+ items: lineItems.map((item) => {
932
+ const imageUrl = item.variant?.image?.url || item.variant?.product?.images?.[0]?.url;
933
+ const itemCategoryId = item.gtmParams?.item_category_id;
934
+ const itemVariantId = item.variant?.id ? shopifyCore.atobID(item.variant.id) : void 0;
935
+ return {
936
+ item_id: item.variant?.sku,
937
+ item_name: item.variant?.product?.title,
938
+ item_brand: gtmParams?.brand || "",
939
+ item_category: item.variant?.product?.productType,
940
+ item_variant: item.variant?.title,
941
+ price: item.variant?.compareAtPrice?.amount ?? item.variant?.price?.amount,
942
+ quantity: item.quantity || 1,
943
+ ...imageUrl && { image_url: imageUrl },
944
+ ...itemCategoryId !== void 0 && { item_category_id: itemCategoryId },
945
+ ...itemVariantId && { item_variant_id: itemVariantId }
946
+ };
947
+ }),
932
948
  ...gtmParams?.ga4Params
933
949
  }
934
950
  });
@@ -956,19 +972,111 @@ var trackBuyNowGA = ({
956
972
  position: gtmParams?.position,
957
973
  currency: currencyCode,
958
974
  value: totalPrice,
959
- items: lineItems.map((item) => ({
960
- item_id: item.variant?.sku,
961
- item_name: item.variant?.product?.title || item.variant?.title,
962
- item_brand: gtmParams?.brand || "",
963
- item_category: item.variant?.product?.productType || "",
964
- item_variant: item.variant?.title,
965
- price: item.variant?.compareAtPrice?.amount ?? item.variant?.price?.amount,
966
- quantity: item.quantity || 1
967
- })),
975
+ items: lineItems.map((item) => {
976
+ const imageUrl = item.variant?.image?.url || item.variant?.product?.images?.[0]?.url;
977
+ const itemCategoryId = item.gtmParams?.item_category_id;
978
+ const itemVariantId = item.variant?.id ? shopifyCore.atobID(item.variant.id) : void 0;
979
+ return {
980
+ item_id: item.variant?.sku,
981
+ item_name: item.variant?.product?.title || item.variant?.title,
982
+ item_brand: gtmParams?.brand || "",
983
+ item_category: item.variant?.product?.productType || "",
984
+ item_variant: item.variant?.title,
985
+ price: item.variant?.compareAtPrice?.amount ?? item.variant?.price?.amount,
986
+ quantity: item.quantity || 1,
987
+ ...imageUrl && { image_url: imageUrl },
988
+ ...itemCategoryId !== void 0 && { item_category_id: itemCategoryId },
989
+ ...itemVariantId && { item_variant_id: itemVariantId }
990
+ };
991
+ }),
968
992
  ...gtmParams?.ga4Params
969
993
  }
970
994
  });
971
995
  };
996
+ function waitForGtagReady(timeout = 1e4) {
997
+ return new Promise((resolve, reject) => {
998
+ const start = Date.now();
999
+ function check() {
1000
+ if (typeof window !== "undefined" && typeof window.gtag !== "undefined") {
1001
+ resolve();
1002
+ } else if (Date.now() - start > timeout) {
1003
+ reject(new Error("GA4 gtag not loaded"));
1004
+ } else {
1005
+ setTimeout(check, 50);
1006
+ }
1007
+ }
1008
+ check();
1009
+ });
1010
+ }
1011
+ var getGA4ClientId = async (measurementId = "G-R0BRMRK4CY") => {
1012
+ try {
1013
+ await waitForGtagReady();
1014
+ return new Promise((resolve, reject) => {
1015
+ if (!window.gtag) {
1016
+ reject(new Error("gtag is not defined"));
1017
+ return;
1018
+ }
1019
+ window.gtag("get", measurementId, "client_id", (clientId) => {
1020
+ if (clientId) {
1021
+ resolve(clientId);
1022
+ } else {
1023
+ reject(new Error("Failed to get client_id"));
1024
+ }
1025
+ });
1026
+ });
1027
+ } catch (error) {
1028
+ console.error("Failed to get GA4 client_id:", error);
1029
+ return "";
1030
+ }
1031
+ };
1032
+ var getGA4SessionId = async (measurementId = "G-R0BRMRK4CY") => {
1033
+ try {
1034
+ await waitForGtagReady();
1035
+ return new Promise((resolve) => {
1036
+ if (!window.gtag) {
1037
+ resolve("");
1038
+ return;
1039
+ }
1040
+ window.gtag("get", measurementId, "session_id", (sessionId) => {
1041
+ resolve(sessionId || "");
1042
+ });
1043
+ });
1044
+ } catch (error) {
1045
+ console.error("Failed to get GA4 session_id:", error);
1046
+ return "";
1047
+ }
1048
+ };
1049
+ var getGA4Data = async (measurementId = "G-R0BRMRK4CY") => {
1050
+ try {
1051
+ await waitForGtagReady();
1052
+ const timeoutPromise = new Promise((resolve) => {
1053
+ setTimeout(() => {
1054
+ resolve({ clientId: "", sessionId: "" });
1055
+ }, 300);
1056
+ });
1057
+ const dataPromise = new Promise((resolve) => {
1058
+ if (!window.gtag) {
1059
+ resolve({ clientId: "", sessionId: "" });
1060
+ return;
1061
+ }
1062
+ window.gtag("get", measurementId, "client_id", (clientId) => {
1063
+ window.gtag("get", measurementId, "session_id", (sessionId) => {
1064
+ resolve({
1065
+ clientId: clientId || "",
1066
+ sessionId: sessionId || ""
1067
+ });
1068
+ });
1069
+ });
1070
+ });
1071
+ return Promise.race([dataPromise, timeoutPromise]);
1072
+ } catch (error) {
1073
+ console.error("Failed to get GA4 data:", error);
1074
+ return {
1075
+ clientId: "",
1076
+ sessionId: ""
1077
+ };
1078
+ }
1079
+ };
972
1080
 
973
1081
  // src/tracking/fbq.ts
974
1082
  var trackAddToCartFBQ = ({ lineItems = [] }) => {
@@ -1151,16 +1259,155 @@ var getLinesWithAttributes = ({
1151
1259
  return functionLine;
1152
1260
  });
1153
1261
  };
1262
+ function useRemoveCartLines(options) {
1263
+ const { client, locale, cartCookieAdapter } = useShopify();
1264
+ const { mutateCart, metafieldIdentifiers } = useCartContext();
1265
+ const removeLines = react.useCallback(
1266
+ async (_key, { arg }) => {
1267
+ const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
1268
+ let updatedCart = await shopifySdk.removeCartLines(client, {
1269
+ cartId,
1270
+ lineIds,
1271
+ metafieldIdentifiers,
1272
+ cookieAdapter: cartCookieAdapter
1273
+ });
1274
+ if (updatedCart && autoRemoveInvalidCodes) {
1275
+ const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
1276
+ if (unApplicableCodes.length > 0) {
1277
+ if (onCodesRemoved) {
1278
+ const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
1279
+ if (handledCart) {
1280
+ updatedCart = handledCart;
1281
+ }
1282
+ } else {
1283
+ updatedCart = await shopifySdk.updateCartCodes(client, {
1284
+ cartId: updatedCart.id,
1285
+ discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
1286
+ metafieldIdentifiers,
1287
+ cookieAdapter: cartCookieAdapter
1288
+ }) || updatedCart;
1289
+ }
1290
+ }
1291
+ }
1292
+ if (updatedCart) {
1293
+ mutateCart(updatedCart);
1294
+ }
1295
+ return updatedCart;
1296
+ },
1297
+ [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
1298
+ );
1299
+ return useSWRMutation__default.default("remove-cart-lines", removeLines, options);
1300
+ }
1301
+
1302
+ // src/hooks/cart/feature/use-auto-remove-free-gifts.ts
1303
+ function useAutoRemoveFreeGifts(options = {}) {
1304
+ const {
1305
+ removeFunctionGifts = true,
1306
+ removeScriptGifts = true,
1307
+ isGiftLineItem
1308
+ } = options;
1309
+ const [isRemoving, setIsRemoving] = react.useState(false);
1310
+ const { cart } = useCartContext();
1311
+ const { trigger: removeCartLines2 } = useRemoveCartLines();
1312
+ const giftsToRemove = react.useMemo(() => {
1313
+ if (!cart?.lineItems) {
1314
+ return [];
1315
+ }
1316
+ return cart.lineItems.filter((item) => {
1317
+ if (removeFunctionGifts) {
1318
+ const functionAttr = item.customAttributes?.find(
1319
+ (attr) => attr.key === "_discounts_function_env"
1320
+ )?.value;
1321
+ if (functionAttr) {
1322
+ try {
1323
+ const functionAttrObj = JSON.parse(functionAttr);
1324
+ if (functionAttrObj.is_gift && functionAttrObj.rule_id && functionAttrObj.spend_sum_money) {
1325
+ return true;
1326
+ }
1327
+ } catch (error) {
1328
+ console.error("Failed to parse _discounts_function_env:", error);
1329
+ }
1330
+ }
1331
+ }
1332
+ if (removeScriptGifts) {
1333
+ const scriptGiftAttr = item.customAttributes?.find(
1334
+ (attr) => attr.key === "_giveaway_gradient_gifts"
1335
+ );
1336
+ if (scriptGiftAttr) {
1337
+ return true;
1338
+ }
1339
+ }
1340
+ if (isGiftLineItem && isGiftLineItem(item)) {
1341
+ return true;
1342
+ }
1343
+ return false;
1344
+ });
1345
+ }, [cart, removeFunctionGifts, removeScriptGifts, isGiftLineItem]);
1346
+ react.useEffect(() => {
1347
+ if (isRemoving || giftsToRemove.length === 0) {
1348
+ return;
1349
+ }
1350
+ const performRemoval = async () => {
1351
+ setIsRemoving(true);
1352
+ try {
1353
+ await removeCartLines2({
1354
+ lineIds: giftsToRemove.map((item) => item.id)
1355
+ });
1356
+ } catch (error) {
1357
+ console.error("Failed to remove free gifts:", error);
1358
+ } finally {
1359
+ setIsRemoving(false);
1360
+ }
1361
+ };
1362
+ performRemoval();
1363
+ }, [
1364
+ isRemoving,
1365
+ giftsToRemove,
1366
+ removeCartLines2
1367
+ ]);
1368
+ return {
1369
+ isRemoving
1370
+ };
1371
+ }
1372
+ function isFunctionGift(line) {
1373
+ const functionAttr = line.customAttributes?.find(
1374
+ (attr) => attr.key === "_discounts_function_env"
1375
+ )?.value;
1376
+ if (!functionAttr) {
1377
+ return false;
1378
+ }
1379
+ try {
1380
+ const functionAttrObj = JSON.parse(functionAttr);
1381
+ return Boolean(
1382
+ functionAttrObj.is_gift && functionAttrObj.rule_id && functionAttrObj.spend_sum_money
1383
+ );
1384
+ } catch {
1385
+ return false;
1386
+ }
1387
+ }
1388
+ function isScriptGift(line) {
1389
+ return line.customAttributes?.some(
1390
+ (attr) => attr.key === "_giveaway_gradient_gifts"
1391
+ ) ?? false;
1392
+ }
1393
+ function isBuyGetGift(line) {
1394
+ return line.customAttributes?.some(
1395
+ (attr) => attr.key === "_freegift_related_handlesku"
1396
+ ) ?? false;
1397
+ }
1398
+ function isAnyGift(line) {
1399
+ return isFunctionGift(line) || isScriptGift(line) || isBuyGetGift(line);
1400
+ }
1154
1401
  function useCalcGiftsFromLines({
1155
1402
  lines,
1156
1403
  customer,
1157
1404
  scriptGiveawayKey = CUSTOMER_SCRIPT_GIFT_KEY
1158
1405
  }) {
1159
1406
  const { locale } = useShopify();
1160
- const { cart, autoFreeGiftConfig, gradientGiftsConfig } = useCartContext();
1161
- const functionGift = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer, lines);
1407
+ const { cart, functionAutoFreeGiftConfig, scriptAutoFreeGiftConfig } = useCartContext();
1408
+ const functionGift = useCalcAutoFreeGift(cart, functionAutoFreeGiftConfig || [], customer, lines);
1162
1409
  const scriptGift = useScriptAutoFreeGift({
1163
- campaign: gradientGiftsConfig || null,
1410
+ campaign: scriptAutoFreeGiftConfig,
1164
1411
  _giveaway: scriptGiveawayKey,
1165
1412
  cart,
1166
1413
  locale,
@@ -1195,7 +1442,9 @@ function useCalcGiftsFromLines({
1195
1442
  const variants = product?.variants;
1196
1443
  const variant = Array.isArray(variants) ? variants.find((v) => v.sku === item.sku) : void 0;
1197
1444
  if (!variant) {
1198
- console.warn(`Script gift: Variant not found for handle=${item.handle}, sku=${item.sku}`);
1445
+ console.warn(
1446
+ `Script gift: Variant not found for handle=${item.handle}, sku=${item.sku}`
1447
+ );
1199
1448
  return null;
1200
1449
  }
1201
1450
  return {
@@ -1338,6 +1587,19 @@ var getReferralAttributes = () => {
1338
1587
  }
1339
1588
  return [];
1340
1589
  };
1590
+ var getOperatingSystem = () => {
1591
+ if (typeof window === "undefined" || typeof navigator === "undefined") {
1592
+ return "Unknown";
1593
+ }
1594
+ const userAgent = navigator.userAgent || navigator.vendor || window.opera;
1595
+ if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
1596
+ return "IOS";
1597
+ }
1598
+ if (/android/i.test(userAgent)) {
1599
+ return "Android";
1600
+ }
1601
+ return "Unknown";
1602
+ };
1341
1603
  var getUserType = (customer) => {
1342
1604
  let userInfo = Cookies5__default.default.get("userInfo");
1343
1605
  if (userInfo) {
@@ -1359,12 +1621,42 @@ var getUserType = (customer) => {
1359
1621
  }
1360
1622
  return "new_user_login";
1361
1623
  };
1362
- function getCartAttributes({
1624
+ function getGA4Attributes(ga4Data) {
1625
+ if (!ga4Data?.clientId && !ga4Data?.sessionId) {
1626
+ return [];
1627
+ }
1628
+ const attributes = [];
1629
+ if (ga4Data.clientId) {
1630
+ attributes.push({
1631
+ key: "_ga4_client_id",
1632
+ value: ga4Data.clientId
1633
+ });
1634
+ }
1635
+ if (ga4Data.sessionId) {
1636
+ attributes.push({
1637
+ key: "_ga4_session_id",
1638
+ value: ga4Data.sessionId
1639
+ });
1640
+ }
1641
+ return attributes;
1642
+ }
1643
+ async function getGA4AttributesAsync() {
1644
+ try {
1645
+ const ga4Data = await getGA4Data();
1646
+ return getGA4Attributes(ga4Data);
1647
+ } catch (error) {
1648
+ console.error("Failed to get GA4 attributes:", error);
1649
+ return [];
1650
+ }
1651
+ }
1652
+ function getCartBasicAttributes({
1363
1653
  profile,
1364
1654
  customer,
1365
1655
  cart,
1366
1656
  memberType,
1367
- currentUrl = ""
1657
+ currentUrl = "",
1658
+ appContext,
1659
+ buyPath
1368
1660
  }) {
1369
1661
  const userType = getUserType(customer);
1370
1662
  const memberAttributes = [
@@ -1391,12 +1683,10 @@ function getCartAttributes({
1391
1683
  value: "1"
1392
1684
  });
1393
1685
  }
1394
- const discountCodes = cart?.discountCodes.map((item) => item.code).filter((code) => code) || [];
1395
1686
  const functionAttributes = [
1396
1687
  {
1397
1688
  key: CUSTOMER_ATTRIBUTE_KEY,
1398
1689
  value: JSON.stringify({
1399
- discount_code: discountCodes,
1400
1690
  user_tags: customer?.tags || []
1401
1691
  })
1402
1692
  }
@@ -1404,26 +1694,38 @@ function getCartAttributes({
1404
1694
  const presellAttributes = [
1405
1695
  {
1406
1696
  key: "_presale",
1407
- value: cart?.lineItems.some((item) => item?.variant?.metafields?.presell === "presell")
1697
+ value: cart?.lineItems?.some((item) => item?.variant?.metafields?.presell === "presell")
1408
1698
  }
1409
1699
  ];
1410
1700
  const weightAttributes = [
1411
1701
  {
1412
1702
  key: "_weight",
1413
- value: cart?.lineItems.reduce((acc, item) => {
1703
+ value: cart?.lineItems?.reduce((acc, item) => {
1414
1704
  const itemWeight = new Decimal2__default.default(item.variant.weight ?? 0).times(item.quantity);
1415
1705
  return new Decimal2__default.default(acc).plus(itemWeight).toNumber();
1416
1706
  }, 0).toString()
1417
- },
1418
- {
1419
- key: "_app_source_name",
1420
- value: "dtc"
1421
1707
  }
1422
1708
  ];
1423
1709
  const trackingAttributes = [
1424
1710
  {
1425
1711
  key: "utm_params",
1426
1712
  value: currentUrl
1713
+ },
1714
+ {
1715
+ key: "_app_source_name",
1716
+ value: appContext?.isInApp && appContext?.appName ? appContext.appName : "dtc"
1717
+ },
1718
+ {
1719
+ key: "_operating_system",
1720
+ value: getOperatingSystem()
1721
+ },
1722
+ {
1723
+ key: "_cart_id",
1724
+ value: cart?.id
1725
+ },
1726
+ {
1727
+ key: "_buy_path",
1728
+ value: buyPath
1427
1729
  }
1428
1730
  ];
1429
1731
  const commonAttributes = [
@@ -1443,21 +1745,41 @@ var useCartAttributes = ({
1443
1745
  profile,
1444
1746
  customer,
1445
1747
  cart,
1446
- memberType
1748
+ memberType,
1749
+ appContext,
1750
+ buyPath
1447
1751
  }) => {
1448
1752
  const [currentUrl, setCurrentUrl] = react.useState("");
1753
+ const [ga4Data, setGa4Data] = react.useState(null);
1449
1754
  react.useEffect(() => {
1450
1755
  setCurrentUrl(window.location.href);
1451
1756
  }, []);
1757
+ react.useEffect(() => {
1758
+ let isMounted = true;
1759
+ getGA4Data().then((data) => {
1760
+ if (isMounted) {
1761
+ setGa4Data(data);
1762
+ }
1763
+ }).catch((error) => {
1764
+ console.error("Failed to get GA4 data in useCartAttributes:", error);
1765
+ });
1766
+ return () => {
1767
+ isMounted = false;
1768
+ };
1769
+ }, []);
1452
1770
  const attributes = react.useMemo(() => {
1453
- return getCartAttributes({
1771
+ const basicAttributes = getCartBasicAttributes({
1454
1772
  profile,
1455
1773
  customer,
1456
1774
  cart,
1457
1775
  memberType,
1458
- currentUrl
1776
+ currentUrl,
1777
+ appContext,
1778
+ buyPath
1459
1779
  });
1460
- }, [profile, customer, cart, memberType, currentUrl]);
1780
+ const ga4Attributes = getGA4Attributes(ga4Data);
1781
+ return [...basicAttributes, ...ga4Attributes];
1782
+ }, [profile, customer, cart, memberType, currentUrl, appContext, buyPath, ga4Data]);
1461
1783
  return react.useMemo(
1462
1784
  () => ({
1463
1785
  attributes
@@ -1520,12 +1842,9 @@ var useUpdateLineCodeAmountAttributes = ({
1520
1842
  const codeDiscount = line.discountAllocations?.find(
1521
1843
  (allocation) => mainProductDiscountCodes?.includes(allocation.code)
1522
1844
  );
1523
- const hasFunctionEnvAttribute = line.customAttributes?.find(
1524
- (attr) => attr.key === CUSTOMER_ATTRIBUTE_KEY
1525
- );
1526
1845
  const functionEnvValue = getDiscountEnvAttributeValue(line.customAttributes);
1527
1846
  const hasSameFunctionEnvAttribute = Number(functionEnvValue.discounted_amount) === Number(line.totalAmount);
1528
- if (!hasSameFunctionEnvAttribute && hasFunctionEnvAttribute && !functionEnvValue.is_gift) {
1847
+ if (!hasSameFunctionEnvAttribute && !functionEnvValue.is_gift) {
1529
1848
  attrNeedUpdate.push({
1530
1849
  key: CUSTOMER_ATTRIBUTE_KEY,
1531
1850
  value: JSON.stringify({
@@ -1946,47 +2265,6 @@ var usePlusMemberCheckoutCustomAttributes = ({
1946
2265
  return checkoutCustomAttributes;
1947
2266
  }, [profile, selectedShippingMethod, selectedPlusMemberMode, isPresaleContains]);
1948
2267
  };
1949
- function useRemoveCartLines(options) {
1950
- const { client, locale, cartCookieAdapter } = useShopify();
1951
- const { mutateCart, metafieldIdentifiers } = useCartContext();
1952
- const removeLines = react.useCallback(
1953
- async (_key, { arg }) => {
1954
- const { autoRemoveInvalidCodes = true, onCodesRemoved, cartId, lineIds } = arg;
1955
- let updatedCart = await shopifySdk.removeCartLines(client, {
1956
- cartId,
1957
- lineIds,
1958
- metafieldIdentifiers,
1959
- cookieAdapter: cartCookieAdapter
1960
- });
1961
- if (updatedCart && autoRemoveInvalidCodes) {
1962
- const unApplicableCodes = updatedCart.discountCodes.filter((item) => !item.applicable).map((item) => item.code);
1963
- if (unApplicableCodes.length > 0) {
1964
- if (onCodesRemoved) {
1965
- const handledCart = await onCodesRemoved(updatedCart, unApplicableCodes);
1966
- if (handledCart) {
1967
- updatedCart = handledCart;
1968
- }
1969
- } else {
1970
- updatedCart = await shopifySdk.updateCartCodes(client, {
1971
- cartId: updatedCart.id,
1972
- discountCodes: updatedCart.discountCodes.filter((item) => item.applicable).map((item) => item.code),
1973
- metafieldIdentifiers,
1974
- cookieAdapter: cartCookieAdapter
1975
- }) || updatedCart;
1976
- }
1977
- }
1978
- }
1979
- if (updatedCart) {
1980
- mutateCart(updatedCart);
1981
- }
1982
- return updatedCart;
1983
- },
1984
- [client, locale, cartCookieAdapter, mutateCart, metafieldIdentifiers]
1985
- );
1986
- return useSWRMutation__default.default("remove-cart-lines", removeLines, options);
1987
- }
1988
-
1989
- // src/hooks/member/plus/use-auto-remove-plus-member-in-cart.ts
1990
2268
  function useAutoRemovePlusMemberInCart({
1991
2269
  cart,
1992
2270
  profile,
@@ -2201,7 +2479,8 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
2201
2479
  profile,
2202
2480
  customer,
2203
2481
  cart,
2204
- memberType: hasPlusMember ? "2" : String(profile?.memberType ?? 0)
2482
+ memberType: hasPlusMember ? "2" : String(profile?.memberType ?? 0),
2483
+ buyPath: "hasCart"
2205
2484
  });
2206
2485
  const addToCart = react.useCallback(
2207
2486
  async (_key, { arg }) => {
@@ -2294,7 +2573,8 @@ function useAddToCart({ withTrack = true } = {}, swrOptions) {
2294
2573
  applyCartCodes,
2295
2574
  removeInvalidCodes,
2296
2575
  addCustomAttributes,
2297
- config
2576
+ config,
2577
+ cartAttributes
2298
2578
  ]
2299
2579
  );
2300
2580
  return useSWRMutation__default.default("add-to-cart", addToCart, swrOptions);
@@ -2373,7 +2653,7 @@ function useUpdateBuyerIdentity({
2373
2653
  }
2374
2654
  function useBuyNow({ withTrack = true } = {}, swrOptions) {
2375
2655
  const { client, config, locale, cartCookieAdapter, userAdapter } = useShopify();
2376
- const { profile, customer, memberSetting } = useCartContext();
2656
+ const { profile, customer, memberSetting, appContext } = useCartContext();
2377
2657
  const isLoggedIn = userAdapter?.isLoggedIn || false;
2378
2658
  const buyNow = react.useCallback(
2379
2659
  async (_key, { arg }) => {
@@ -2395,12 +2675,6 @@ function useBuyNow({ withTrack = true } = {}, swrOptions) {
2395
2675
  lines: lineItems
2396
2676
  });
2397
2677
  const memberType = hasPlusMember ? "2" : String(profile?.memberType ?? 0);
2398
- const cartAttributes = getCartAttributes({
2399
- profile,
2400
- customer,
2401
- memberType,
2402
- currentUrl: window.location.href
2403
- });
2404
2678
  const linesWithFunctionAttributes = getLinesWithAttributes({
2405
2679
  lineItems
2406
2680
  });
@@ -2413,13 +2687,23 @@ function useBuyNow({ withTrack = true } = {}, swrOptions) {
2413
2687
  if (lines.length === 0) {
2414
2688
  return;
2415
2689
  }
2690
+ const basicCartAttributes = getCartBasicAttributes({
2691
+ profile,
2692
+ customer,
2693
+ memberType,
2694
+ cart: { lineItems },
2695
+ currentUrl: window.location.href,
2696
+ appContext,
2697
+ buyPath: "buyNow"
2698
+ });
2699
+ const ga4Attributes = await getGA4AttributesAsync();
2416
2700
  const resultCart = await shopifySdk.createCart(client, {
2417
2701
  lines,
2418
2702
  metafieldIdentifiers,
2419
2703
  cookieAdapter: cartCookieAdapter,
2420
2704
  buyerIdentity,
2421
2705
  discountCodes,
2422
- customAttributes: [...cartAttributes, ...customAttributes || []]
2706
+ customAttributes: [...basicCartAttributes, ...ga4Attributes, ...customAttributes || []]
2423
2707
  });
2424
2708
  if (!resultCart) {
2425
2709
  throw new Error("Failed to create cart for buy now");
@@ -2444,7 +2728,17 @@ function useBuyNow({ withTrack = true } = {}, swrOptions) {
2444
2728
  }
2445
2729
  return resultCart;
2446
2730
  },
2447
- [client, locale, isLoggedIn, cartCookieAdapter, withTrack, customer, profile, memberSetting]
2731
+ [
2732
+ client,
2733
+ locale,
2734
+ isLoggedIn,
2735
+ cartCookieAdapter,
2736
+ withTrack,
2737
+ customer,
2738
+ profile,
2739
+ memberSetting,
2740
+ appContext
2741
+ ]
2448
2742
  );
2449
2743
  return useSWRMutation__default.default("buy-now", buyNow, swrOptions);
2450
2744
  }
@@ -3240,13 +3534,14 @@ var CartContext = react.createContext(null);
3240
3534
  function CartProvider({
3241
3535
  children,
3242
3536
  // swrOptions,
3243
- autoFreeGiftConfig,
3244
- gradientGiftsConfig,
3537
+ functionAutoFreeGiftConfig,
3538
+ scriptAutoFreeGiftConfig,
3245
3539
  profile,
3246
3540
  customer,
3247
3541
  locale,
3248
3542
  metafieldIdentifiers,
3249
- memberSetting
3543
+ memberSetting,
3544
+ appContext
3250
3545
  }) {
3251
3546
  const { client, cartCookieAdapter } = useShopify();
3252
3547
  const [customAttributes, setCustomAttributes] = react.useState([]);
@@ -3291,7 +3586,8 @@ function CartProvider({
3291
3586
  profile,
3292
3587
  customer,
3293
3588
  cart,
3294
- memberType: hasPlusMember ? "2" : String(profile?.memberType ?? 0)
3589
+ memberType: hasPlusMember ? "2" : String(profile?.memberType ?? 0),
3590
+ appContext
3295
3591
  });
3296
3592
  ahooks.useRequest(
3297
3593
  () => {
@@ -3345,9 +3641,13 @@ function CartProvider({
3345
3641
  },
3346
3642
  [setCustomAttributes]
3347
3643
  );
3348
- const functionAutoFreeGiftResult = useCalcAutoFreeGift(cart, autoFreeGiftConfig || [], customer);
3644
+ const functionAutoFreeGiftResult = useCalcAutoFreeGift(
3645
+ cart,
3646
+ functionAutoFreeGiftConfig || [],
3647
+ customer
3648
+ );
3349
3649
  const scriptAutoFreeGiftResult = useScriptAutoFreeGift({
3350
- campaign: gradientGiftsConfig || null,
3650
+ campaign: scriptAutoFreeGiftConfig,
3351
3651
  _giveaway: CUSTOMER_SCRIPT_GIFT_KEY,
3352
3652
  cart,
3353
3653
  profile
@@ -3355,10 +3655,10 @@ function CartProvider({
3355
3655
  const formattedScriptGifts = react.useMemo(() => {
3356
3656
  return formatScriptAutoFreeGift({
3357
3657
  scriptAutoFreeGiftResult,
3358
- gradient_gifts: gradientGiftsConfig,
3658
+ gradient_gifts: scriptAutoFreeGiftConfig,
3359
3659
  locale
3360
3660
  });
3361
- }, [scriptAutoFreeGiftResult, gradientGiftsConfig, locale]);
3661
+ }, [scriptAutoFreeGiftResult, scriptAutoFreeGiftConfig, locale]);
3362
3662
  const formattedFunctionGifts = react.useMemo(() => {
3363
3663
  return formatFunctionAutoFreeGift({
3364
3664
  qualifyingGift: functionAutoFreeGiftResult?.qualifyingGift || null,
@@ -3406,6 +3706,12 @@ function CartProvider({
3406
3706
  const giftLinesCount = giftNeedAddToCartLines?.reduce((acc, item) => acc + (item.quantity || 1), 0) || 0;
3407
3707
  return cartLinesCount + giftLinesCount;
3408
3708
  }, [cart?.lineItems, giftNeedAddToCartLines]);
3709
+ const autoRemoveFreeGiftsOptions = react.useMemo(() => {
3710
+ return {
3711
+ removeFunctionGifts: !!functionAutoFreeGiftConfig,
3712
+ removeScriptGifts: !!scriptAutoFreeGiftConfig
3713
+ };
3714
+ }, [functionAutoFreeGiftConfig, scriptAutoFreeGiftConfig]);
3409
3715
  const value = react.useMemo(
3410
3716
  () => ({
3411
3717
  totalQuantity,
@@ -3420,8 +3726,8 @@ function CartProvider({
3420
3726
  customer,
3421
3727
  isCodeChanging,
3422
3728
  setIsCodeChanging,
3423
- autoFreeGiftConfig,
3424
- gradientGiftsConfig,
3729
+ functionAutoFreeGiftConfig,
3730
+ scriptAutoFreeGiftConfig,
3425
3731
  setLoadingState,
3426
3732
  loadingState,
3427
3733
  // function满赠
@@ -3434,7 +3740,9 @@ function CartProvider({
3434
3740
  setScriptAutoFreeGift,
3435
3741
  giftNeedAddToCartLines,
3436
3742
  metafieldIdentifiers,
3437
- memberSetting
3743
+ memberSetting,
3744
+ appContext,
3745
+ autoRemoveFreeGiftsOptions
3438
3746
  }),
3439
3747
  [
3440
3748
  cart,
@@ -3446,8 +3754,8 @@ function CartProvider({
3446
3754
  removeCustomAttributes,
3447
3755
  locale,
3448
3756
  isCodeChanging,
3449
- autoFreeGiftConfig,
3450
- gradientGiftsConfig,
3757
+ functionAutoFreeGiftConfig,
3758
+ scriptAutoFreeGiftConfig,
3451
3759
  loadingState,
3452
3760
  // function满赠
3453
3761
  functionAutoFreeGift,
@@ -3461,7 +3769,9 @@ function CartProvider({
3461
3769
  metafieldIdentifiers,
3462
3770
  customer,
3463
3771
  profile,
3464
- memberSetting
3772
+ memberSetting,
3773
+ appContext,
3774
+ autoRemoveFreeGiftsOptions
3465
3775
  ]
3466
3776
  );
3467
3777
  return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
@@ -3507,14 +3817,24 @@ exports.formatFunctionAutoFreeGift = formatFunctionAutoFreeGift;
3507
3817
  exports.formatScriptAutoFreeGift = formatScriptAutoFreeGift;
3508
3818
  exports.gaTrack = gaTrack;
3509
3819
  exports.getCachedGeoLocation = getCachedGeoLocation;
3510
- exports.getCartAttributes = getCartAttributes;
3820
+ exports.getCartBasicAttributes = getCartBasicAttributes;
3511
3821
  exports.getDiscountEnvAttributeValue = getDiscountEnvAttributeValue;
3822
+ exports.getGA4Attributes = getGA4Attributes;
3823
+ exports.getGA4AttributesAsync = getGA4AttributesAsync;
3824
+ exports.getGA4ClientId = getGA4ClientId;
3825
+ exports.getGA4Data = getGA4Data;
3826
+ exports.getGA4SessionId = getGA4SessionId;
3512
3827
  exports.getMatchedMainProductSubTotal = getMatchedMainProductSubTotal;
3828
+ exports.getOperatingSystem = getOperatingSystem;
3513
3829
  exports.getQuery = getQuery;
3514
3830
  exports.getReferralAttributes = getReferralAttributes;
3515
3831
  exports.getUserType = getUserType;
3516
3832
  exports.hasPlusMemberInCart = hasPlusMemberInCart;
3517
3833
  exports.hasPlusMemberInLines = hasPlusMemberInLines;
3834
+ exports.isAnyGift = isAnyGift;
3835
+ exports.isBuyGetGift = isBuyGetGift;
3836
+ exports.isFunctionGift = isFunctionGift;
3837
+ exports.isScriptGift = isScriptGift;
3518
3838
  exports.normalizeAddToCartLines = normalizeAddToCartLines;
3519
3839
  exports.preCheck = preCheck;
3520
3840
  exports.safeParse = safeParse;
@@ -3532,6 +3852,7 @@ exports.useApplyCartCodes = useApplyCartCodes;
3532
3852
  exports.useArticle = useArticle;
3533
3853
  exports.useArticles = useArticles;
3534
3854
  exports.useArticlesInBlog = useArticlesInBlog;
3855
+ exports.useAutoRemoveFreeGifts = useAutoRemoveFreeGifts;
3535
3856
  exports.useAutoRemovePlusMemberInCart = useAutoRemovePlusMemberInCart;
3536
3857
  exports.useAvailableDeliveryCoupon = useAvailableDeliveryCoupon;
3537
3858
  exports.useBlog = useBlog;
@@ -3574,6 +3895,7 @@ exports.useUpdateLineCodeAmountAttributes = useUpdateLineCodeAmountAttributes;
3574
3895
  exports.useUpdateVariantQuery = useUpdateVariantQuery;
3575
3896
  exports.useVariant = useVariant;
3576
3897
  exports.useVariantMedia = useVariantMedia;
3898
+ exports.waitForGtagReady = waitForGtagReady;
3577
3899
  Object.keys(shopifySdk).forEach(function (k) {
3578
3900
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
3579
3901
  enumerable: true,