@abra-promotions/webhooks-for-tapcart 2.0.0-beta.1 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -211,9 +211,7 @@ const getDiscountForTierDiscount = ({
211
211
 
212
212
  if (targetDiscount.entitled.variants) {
213
213
  if (
214
- targetDiscount.entitled.variants?.includes(
215
- item.variantId.toString(),
216
- )
214
+ targetDiscount.entitled.variants?.includes(item.variantId.toString())
217
215
  ) {
218
216
  return isItemEligibleWithSelectedPurchaseType(item, targetDiscount);
219
217
  }
@@ -330,8 +328,7 @@ const getDiscountForVolumeDiscount = ({
330
328
  const selectedHasSellingPlan = Boolean(
331
329
  selectedVariant?.sellingPlanAllocation,
332
330
  );
333
- if (getsPurchaseType === "SUBSCRIPTION" && !selectedHasSellingPlan)
334
- return 0;
331
+ if (getsPurchaseType === "SUBSCRIPTION" && !selectedHasSellingPlan) return 0;
335
332
  if (getsPurchaseType === "ONE_TIME" && selectedHasSellingPlan) return 0;
336
333
 
337
334
  const currentCollectionHandle = product.sourceCollection?.handle;
@@ -358,10 +355,7 @@ const getDiscountForVolumeDiscount = ({
358
355
  }
359
356
 
360
357
  if (targetDiscount?.entitled?.variants) {
361
- if (
362
- variantId &&
363
- targetDiscount?.entitled?.variants.includes(variantId)
364
- ) {
358
+ if (variantId && targetDiscount?.entitled?.variants.includes(variantId)) {
365
359
  return true;
366
360
  }
367
361
  }
@@ -397,9 +391,7 @@ const getDiscountForVolumeDiscount = ({
397
391
 
398
392
  if (targetDiscount.entitled.variants) {
399
393
  if (
400
- targetDiscount.entitled.variants?.includes(
401
- item.variantId.toString(),
402
- )
394
+ targetDiscount.entitled.variants?.includes(item.variantId.toString())
403
395
  ) {
404
396
  return isItemEligibleWithSelectedPurchaseType(item, targetDiscount);
405
397
  }
@@ -558,9 +550,7 @@ const getDiscountForMultiEffectTiers = ({
558
550
 
559
551
  if (targetDiscount.entitled.variants) {
560
552
  if (
561
- targetDiscount.entitled.variants?.includes(
562
- item.variantId.toString(),
563
- )
553
+ targetDiscount.entitled.variants?.includes(item.variantId.toString())
564
554
  ) {
565
555
  return isItemEligibleWithSelectedPurchaseType(item, targetDiscount);
566
556
  }
@@ -654,15 +644,12 @@ const getDiscountForMultiEffectTiers = ({
654
644
  targetDiscount.discountValue.tiers
655
645
  .slice(0, biggestEligibleTierIndex + 1)
656
646
  ?.filter((tier) =>
657
- tier.discounts.some(
658
- (discount) => discount.type === "ProductDiscount",
659
- ),
647
+ tier.discounts.some((discount) => discount.type === "ProductDiscount"),
660
648
  )
661
649
  ?.flatMap(
662
650
  (tier) =>
663
- tier.discounts.find(
664
- (discount) => discount.type === "ProductDiscount",
665
- )?.value ?? [],
651
+ tier.discounts.find((discount) => discount.type === "ProductDiscount")
652
+ ?.value ?? [],
666
653
  ) ?? [];
667
654
 
668
655
  // Per-entry purchaseType replaces the promotion-level flags: an entry only
@@ -680,20 +667,17 @@ const getDiscountForMultiEffectTiers = ({
680
667
  },
681
668
  );
682
669
 
683
- const maxDiscountAmount = eligibleProductDiscounts.reduce(
684
- (max, discount) => {
685
- let discountAmount = 0;
686
- if (discount.value.type === "DiscountAmount") {
687
- discountAmount = parseFloat(discount.value.discountAmount.amount);
688
- } else if (discount.value.type === "DiscountPercentage") {
689
- discountAmount =
690
- parseFloat(selectedVariant.price.amount) *
691
- (discount.value.percentage / 100);
692
- }
693
- return Math.max(max, discountAmount);
694
- },
695
- 0,
696
- );
670
+ const maxDiscountAmount = eligibleProductDiscounts.reduce((max, discount) => {
671
+ let discountAmount = 0;
672
+ if (discount.value.type === "DiscountAmount") {
673
+ discountAmount = parseFloat(discount.value.discountAmount.amount);
674
+ } else if (discount.value.type === "DiscountPercentage") {
675
+ discountAmount =
676
+ parseFloat(selectedVariant.price.amount) *
677
+ (discount.value.percentage / 100);
678
+ }
679
+ return Math.max(max, discountAmount);
680
+ }, 0);
697
681
  return maxDiscountAmount;
698
682
  };
699
683
 
@@ -844,9 +828,13 @@ const getDiscountForBxgyDiscount = ({
844
828
  // Check if this product matches a productCard with purchase type requirement
845
829
  // Look up the actual cart item to check if it has a subscription selected
846
830
  const matchingCartItem = (cart?.items || []).find(
847
- (item) => item.variantId?.toString() === variantId?.toString() || item.handle === handle
831
+ (item) =>
832
+ item.variantId?.toString() === variantId?.toString() ||
833
+ item.handle === handle,
834
+ );
835
+ const cartItemHasSellingPlan = Boolean(
836
+ matchingCartItem?.sellingPlanAllocation,
848
837
  );
849
- const cartItemHasSellingPlan = Boolean(matchingCartItem?.sellingPlanAllocation);
850
838
 
851
839
  for (const card of bxgy.productCards) {
852
840
  if (isProductMatchingBxgyCardItems(handle, variantId, card.items)) {
@@ -858,7 +846,6 @@ const getDiscountForBxgyDiscount = ({
858
846
  }
859
847
  }
860
848
 
861
-
862
849
  if (!areAllBxgyProductCardsMet(cart, bxgy)) return 0;
863
850
 
864
851
  const originalPrice = parseFloat(selectedVariant?.price?.amount || 0);
@@ -1051,9 +1038,12 @@ const getBiggestDiscount = ({
1051
1038
 
1052
1039
  if (appliesOnSubscription && !appliesOnOneTimePurchase) {
1053
1040
  if (!hasSellingPlan) {
1054
- log("Skipping subscription-only discount (no subscription selected)", {
1055
- discountType: discount.discountValue?.type,
1056
- });
1041
+ log(
1042
+ "Skipping subscription-only discount (no subscription selected)",
1043
+ {
1044
+ discountType: discount.discountValue?.type,
1045
+ },
1046
+ );
1057
1047
  return max;
1058
1048
  }
1059
1049
  }
@@ -1098,7 +1088,8 @@ const parsePromotionIfActive = (promotionObject, now = new Date()) => {
1098
1088
  ? JSON.parse(promotionObject ?? "{}")
1099
1089
  : promotionObject;
1100
1090
 
1101
- if (!promotion.startsAt || !promotion.status || !promotion.title)
1091
+ // no stored promotion is the normal state, not an error
1092
+ if (!promotion?.startsAt || !promotion.status || !promotion.title)
1102
1093
  return undefined;
1103
1094
  const startsAt = new Date(promotion.startsAt);
1104
1095
  const endsAt = promotion.endsAt ? new Date(promotion.endsAt) : null;
@@ -1118,8 +1109,44 @@ const parsePromotionIfActive = (promotionObject, now = new Date()) => {
1118
1109
  }
1119
1110
  };
1120
1111
 
1121
- function useAbra({ React, useTapcart, tapcartData }) {
1112
+ // Prints log() lines (including the discount math's) to the console, read over WebView remote
1113
+ // debugging, only on the devices in debugDeviceIds (the template's ABRA_CONFIG, set by setup/update
1114
+ // --debug <device-id>). Consecutive identical lines are dropped: some fire on every render.
1115
+ let lastConsoleLine = "";
1116
+ const consoleLog = (debugDeviceIds, deviceId, message, data) => {
1117
+ const device = String(deviceId ?? "").toLowerCase();
1118
+ if (
1119
+ !device ||
1120
+ !(debugDeviceIds || []).some((id) => String(id).toLowerCase() === device)
1121
+ )
1122
+ return;
1123
+ let json = "";
1124
+ if (data != null) {
1125
+ try {
1126
+ json = ` ${JSON.stringify(data)}`;
1127
+ } catch {
1128
+ json = ` ${String(data)}`;
1129
+ }
1130
+ }
1131
+ const line = `[Abra useAbra] ${message}${json}`;
1132
+ if (line === lastConsoleLine) return;
1133
+ lastConsoleLine = line;
1134
+ console.log(line);
1135
+ };
1136
+
1137
+ function useAbra({
1138
+ React,
1139
+ useTapcart,
1140
+ tapcartData,
1141
+ debugDeviceIds,
1142
+ }) {
1122
1143
  const Tapcart = useTapcart();
1144
+ // log() is memoized once; it reads these through a ref
1145
+ const consoleRef = React.useRef({});
1146
+ consoleRef.current = {
1147
+ debugDeviceIds,
1148
+ deviceId: Tapcart?.variables?.device?.id,
1149
+ };
1123
1150
  const [activePromotion, setActivePromotion] = React.useState(undefined);
1124
1151
  const renderCountRef = React.useRef(0);
1125
1152
  const logRef = React.useRef([]);
@@ -1308,6 +1335,12 @@ function useAbra({ React, useTapcart, tapcartData }) {
1308
1335
 
1309
1336
  // Stable logging function that doesn't cause re-renders
1310
1337
  const log = React.useCallback((message, data = null) => {
1338
+ consoleLog(
1339
+ consoleRef.current.debugDeviceIds,
1340
+ consoleRef.current.deviceId,
1341
+ message,
1342
+ data,
1343
+ );
1311
1344
  const timestamp = new Date().toISOString();
1312
1345
  const logEntry = {
1313
1346
  timestamp,