@zuplo/zudoku-plugin-monetization 0.0.33 → 0.0.35

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.
Files changed (2) hide show
  1. package/dist/index.mjs +47 -26
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -811,14 +811,14 @@ const PricingCard = ({ plan, isPopular = false, isSubscribed = false }) => {
811
811
  })
812
812
  }),
813
813
  isSubscribed ? /* @__PURE__ */ jsx(Button, {
814
- variant: isPopular ? "default" : "secondary",
814
+ variant: isPopular ? "default" : "outline",
815
815
  asChild: true,
816
816
  children: /* @__PURE__ */ jsx(Link$1, {
817
817
  to: `/subscriptions#manage`,
818
818
  children: "Manage Subscriptions"
819
819
  })
820
820
  }) : /* @__PURE__ */ jsx(Button, {
821
- variant: isPopular ? "default" : "secondary",
821
+ variant: isPopular ? "default" : "outline",
822
822
  asChild: true,
823
823
  children: /* @__PURE__ */ jsx(Link$1, {
824
824
  to: `/checkout?planId=${encodeURIComponent(plan.id)}`,
@@ -836,7 +836,8 @@ const PricingPage = () => {
836
836
  const deploymentName = useDeploymentName();
837
837
  const auth = useAuth();
838
838
  const { data: pricingTable } = usePlans();
839
- const taxLegendSentence = taxBehaviorLegendSentence(collectDefaultTaxBehaviors(pricingTable.items[0]));
839
+ const firstPlan = pricingTable.items[0];
840
+ const taxLegendSentence = firstPlan ? taxBehaviorLegendSentence(collectDefaultTaxBehaviors(firstPlan)) : void 0;
840
841
  const { data: subscriptions = { items: [] } } = useQuery({
841
842
  meta: { context: zudoku },
842
843
  queryKey: [`/v3/zudoku-metering/${deploymentName}/subscriptions`],
@@ -1094,6 +1095,17 @@ const useSubscriptions = (environmentName) => {
1094
1095
  });
1095
1096
  };
1096
1097
  //#endregion
1098
+ //#region src/utils/billables.ts
1099
+ const getActivePhase = (sub) => {
1100
+ const now = Date.now();
1101
+ return sub.phases.filter((p) => new Date(p.activeFrom).getTime() <= now && (!p.activeTo || new Date(p.activeTo).getTime() >= now)).sort((a, b) => new Date(b.activeFrom).getTime() - new Date(a.activeFrom).getTime())[0];
1102
+ };
1103
+ const activePhaseHasBillables = (sub) => getActivePhase(sub)?.items.some((i) => i.price != null) ?? false;
1104
+ const hasFutureBillables = (sub) => {
1105
+ const now = Date.now();
1106
+ return sub.phases.filter((p) => new Date(p.activeFrom).getTime() > now).some((p) => p.items.some((i) => i.price != null));
1107
+ };
1108
+ //#endregion
1097
1109
  //#region src/pages/subscriptions/ConfirmDeleteKeyAlert.tsx
1098
1110
  const ConfirmDeleteKeyAlert = ({ children, onDelete }) => {
1099
1111
  return /* @__PURE__ */ jsxs(AlertDialog, { children: [/* @__PURE__ */ jsx(AlertDialogTrigger, {
@@ -1386,19 +1398,22 @@ const ApiKeysList = ({ isPendingFirstPayment, apiKeys, deploymentName, consumerI
1386
1398
  };
1387
1399
  //#endregion
1388
1400
  //#region src/pages/subscriptions/CancelSubscriptionDialog.tsx
1389
- const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId, billingPeriodEnd }) => {
1401
+ const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId, billingPeriodEnd, hasCurrentBillables, hasFutureBillables }) => {
1390
1402
  const [confirmationText, setConfirmationText] = useState("");
1391
1403
  const isConfirmed = planName.startsWith(confirmationText);
1392
1404
  const deploymentName = useDeploymentName();
1393
1405
  const context = useZudoku();
1394
1406
  const queryClient = useQueryClient();
1407
+ const cancelTiming = hasCurrentBillables ? "next_billing_cycle" : "immediate";
1408
+ const isImmediateCancel = !hasCurrentBillables;
1409
+ const isTrialCancel = isImmediateCancel && hasFutureBillables;
1395
1410
  const cancelSubscriptionMutation = useMutation({
1396
1411
  mutationKey: [`/v3/zudoku-metering/${deploymentName}/subscriptions/${subscriptionId}/cancel`],
1397
1412
  meta: {
1398
1413
  context,
1399
1414
  request: {
1400
1415
  method: "POST",
1401
- body: JSON.stringify({ timing: "next_billing_cycle" })
1416
+ body: JSON.stringify({ timing: cancelTiming })
1402
1417
  }
1403
1418
  },
1404
1419
  onSuccess: async () => {
@@ -1418,28 +1433,32 @@ const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId
1418
1433
  children: [
1419
1434
  /* @__PURE__ */ jsxs(Alert, {
1420
1435
  variant: "warning",
1421
- children: [
1422
- /* @__PURE__ */ jsx(CalendarIcon, { className: "size-4" }),
1423
- /* @__PURE__ */ jsx(AlertTitle, { children: "Your plan will be canceled at the end of your billing cycle." }),
1424
- /* @__PURE__ */ jsxs(AlertDescription, { children: [
1425
- "You'll retain access until ",
1426
- formatDate$2(billingPeriodEnd),
1427
- ". After your billing period ends, this plan will not renew and you would need to subscribe again to continue."
1428
- ] })
1429
- ]
1436
+ children: [/* @__PURE__ */ jsx(CalendarIcon, { className: "size-4" }), isTrialCancel ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(AlertTitle, { children: [
1437
+ "Cancel your trial of ",
1438
+ planName,
1439
+ "?"
1440
+ ] }), /* @__PURE__ */ jsxs(AlertDescription, { children: [
1441
+ "Your subscription will end now and you won't be charged when the trial would have converted to ",
1442
+ planName,
1443
+ "."
1444
+ ] })] }) : isImmediateCancel ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(AlertTitle, { children: [
1445
+ "Cancel your ",
1446
+ planName,
1447
+ " subscription?"
1448
+ ] }), /* @__PURE__ */ jsx(AlertDescription, { children: "Your subscription will end immediately. You'll lose access to its entitlements right away." })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AlertTitle, { children: "Your plan will be canceled at the end of your billing cycle." }), /* @__PURE__ */ jsxs(AlertDescription, { children: [
1449
+ "You'll retain access until ",
1450
+ formatDate$2(billingPeriodEnd),
1451
+ ". After your billing period ends, this plan will not renew and you would need to subscribe again to continue."
1452
+ ] })] })]
1430
1453
  }),
1431
1454
  /* @__PURE__ */ jsxs(Alert, {
1432
1455
  variant: "info",
1433
- children: [
1434
- /* @__PURE__ */ jsx(InfoIcon, { className: "size-4" }),
1435
- /* @__PURE__ */ jsx(AlertTitle, { children: "You can still resume before then" }),
1436
- /* @__PURE__ */ jsxs(AlertDescription, { children: [
1437
- "If you change your mind you have until",
1438
- " ",
1439
- formatDate$2(billingPeriodEnd),
1440
- " to remove this cancellation from Manage subscription."
1441
- ] })
1442
- ]
1456
+ children: [/* @__PURE__ */ jsx(InfoIcon, { className: "size-4" }), isImmediateCancel ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AlertTitle, { children: "You can subscribe again at any time" }), /* @__PURE__ */ jsx(AlertDescription, { children: "After canceling, you can return to the pricing page and start a new subscription whenever you're ready." })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AlertTitle, { children: "You can still resume before then" }), /* @__PURE__ */ jsxs(AlertDescription, { children: [
1457
+ "If you change your mind you have until",
1458
+ " ",
1459
+ formatDate$2(billingPeriodEnd),
1460
+ " to remove this cancellation from Manage subscription."
1461
+ ] })] })]
1443
1462
  }),
1444
1463
  /* @__PURE__ */ jsxs("div", {
1445
1464
  className: "space-y-2",
@@ -2074,7 +2093,9 @@ const ManageSubscription = ({ subscription, planName }) => {
2074
2093
  onOpenChange: setCancelDialogOpen,
2075
2094
  planName,
2076
2095
  subscriptionId: subscription.id,
2077
- billingPeriodEnd
2096
+ billingPeriodEnd,
2097
+ hasCurrentBillables: activePhaseHasBillables(subscription),
2098
+ hasFutureBillables: hasFutureBillables(subscription)
2078
2099
  }),
2079
2100
  /* @__PURE__ */ jsx(RestoreSubscriptionDialog, {
2080
2101
  open: restoreDialogOpen,
@@ -2579,7 +2600,7 @@ const ActiveSubscription = ({ subscription, deploymentName }) => {
2579
2600
  meta: { context: zudoku }
2580
2601
  });
2581
2602
  const isPendingFirstPayment = usageQuery.data.paymentStatus.isFirstPayment === true && usageQuery.data.paymentStatus.status !== "paid" && usageQuery.data.paymentStatus.status !== "not_required";
2582
- const activePhase = subscription?.phases.find((p) => new Date(p.activeFrom) <= /* @__PURE__ */ new Date() && (!p.activeTo || new Date(p.activeTo) >= /* @__PURE__ */ new Date()));
2603
+ const activePhase = getActivePhase(subscription);
2583
2604
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2584
2605
  planSwitched && /* @__PURE__ */ jsxs(DismissibleAlert, {
2585
2606
  variant: "info",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zuplo/zudoku-plugin-monetization",
3
- "version": "0.0.33",
3
+ "version": "0.0.35",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/zuplo/zudoku",
@@ -30,8 +30,8 @@
30
30
  "happy-dom": "20.9.0",
31
31
  "react": "19.2.5",
32
32
  "react-dom": "19.2.5",
33
- "tsdown": "0.21.9",
34
- "zudoku": "0.76.0"
33
+ "tsdown": "0.21.10",
34
+ "zudoku": "0.77.0"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "react": ">=19.2.0",