Skip to content

chore: remove trials#3988

Merged
chronark merged 5 commits intomainfrom
09-17-chore_remove_trials
Sep 19, 2025
Merged

chore: remove trials#3988
chronark merged 5 commits intomainfrom
09-17-chore_remove_trials

Conversation

@chronark
Copy link
Collaborator

@chronark chronark commented Sep 17, 2025

What does this PR do?

Remove trial functionality from subscription system

This PR removes the 14-day trial period from our subscription system, simplifying the upgrade flow. Users now directly upgrade to paid plans without a trial period. The changes include:

  • Removed trial-related UI elements and logic from the billing page
  • Updated subscription creation to no longer include trial periods
  • Removed trial status checks and display components
  • Updated documentation to reflect the new direct upgrade process
  • Deleted the trial_ended email template
  • Removed the sendTrialEnded method from the Resend client

Fixes #0000

Type of change

  • Enhancement (small improvements)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Test the upgrade flow to ensure users can directly upgrade without a trial period
  • Verify that the billing page correctly shows subscription status without trial information
  • Check that the documentation accurately reflects the new upgrade process
  • Verify that Stripe webhook handling works correctly with the updated subscription flow

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

Summary by CodeRabbit

  • Refactor
    • Removed trial flows across billing UI and simplified subscription states (only active/canceled and free-tier messaging).
    • Subscription creation no longer sets a built-in trial period; Stripe defaults apply.
  • Documentation
    • Replaced trial-based onboarding with an upgrade-based flow and added usage/quota monitoring guidance.
  • Chores
    • Removed trial-ended email support and updated notifications to reference sign-ups/subscriptions.
    • Changed "Contact Support" actions to open the user's email client (support@unkey.dev).

I have not tested this yet, I'm going to bed
@vercel
Copy link

vercel bot commented Sep 17, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
dashboard Ready Ready Preview Comment Sep 19, 2025 0:50am
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
engineering Ignored Ignored Preview Sep 19, 2025 0:50am

@changeset-bot
Copy link

changeset-bot bot commented Sep 17, 2025

⚠️ No Changeset found

Latest commit: 061e36b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

📝 Walkthrough

Walkthrough

Removes trial-related logic across billing UI, subscription creation, Stripe webhooks, docs, and internal emails. Trial fields and trial-specific UI/notifications are deleted; subscription creation no longer sets trial_period_days; trial-ended email and its send API are removed; support links in several error toasts switched to mailto.

Changes

Cohort / File(s) Summary
Billing UI (remove trial fields/flows)
apps/dashboard/app/(app)/settings/billing/client.tsx, apps/dashboard/app/(app)/settings/billing/page.tsx
Removed trialUntil from subscription props and UI; SusbcriptionStatus no longer accepts/handles trialing; allowUpdate/allowCancel/isFreeTier logic tightened; UI trial cards/text removed.
Stripe webhook (no trial gating / slack text)
apps/dashboard/app/api/webhooks/stripe/route.ts
Dropped trial_end gating for customer.subscription.created; updated Slack messages from trial-specific wording to generic signup/subscription notices.
Subscription creation (no trial period)
apps/dashboard/lib/trpc/routers/stripe/createSubscription.ts
Removed previous-subscription check and trial_period_days when creating subscriptions; eliminated extra Stripe list call; rely on Stripe defaults.
Documentation (remove trial flow, add usage tracking)
apps/engineering/content/docs/infrastructure/stripe/subscriptions.mdx
Replaced trial-based onboarding with upgrade flow; removed trial section and 14-day specifics; added usage-tracking and quota metadata updates; minor formatting/terminology edits.
Email template removal (trial-ended)
internal/resend/emails/trial_ended.tsx
Deleted TrialEnded email component, its Props type, preview props, and default export.
Email client API (remove sender)
internal/resend/src/client.tsx
Removed Resend.sendTrialEnded method and its import/usage.
Support actions → mailto (error toasts)
apps/dashboard/app/(app)/apis/.../create-key/.../key-created-success-dialog.tsx, apps/dashboard/app/(app)/apis/.../create-key/hooks/use-create-key.tsx, apps/dashboard/app/(app)/apis/.../create-key/index.tsx, apps/dashboard/app/(app)/apis/.../edit-credits/.../index.tsx, apps/dashboard/app/(app)/apis/.../use-delete-key.ts, apps/dashboard/app/(app)/apis/.../use-edit-credits.ts, apps/dashboard/app/(app)/apis/.../use-edit-key.tsx, apps/dashboard/app/(app)/apis/.../use-edit-ratelimits.ts, apps/dashboard/app/(app)/apis/.../use-update-key-status.tsx
Replaced support website navigation (https://support.unkey.dev) with opening mail client via mailto:support@unkey.dev for "Contact Support" actions in various error toasts.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as Dashboard UI
  participant Srv as Server (trpc)
  participant Stripe as Stripe API

  UI->>Srv: Create subscription (workspace, priceId)
  Note right of Srv: removed previous-subscription check\nno trial_period_days set
  Srv->>Stripe: subscriptions.create({ customer, items:[{price}] })
  Stripe-->>Srv: Subscription (status)
  Srv-->>UI: Subscription result
  Note over UI,Srv: UI no longer receives or handles trialUntil/trialing state
Loading
sequenceDiagram
  autonumber
  participant Stripe as Stripe Webhooks
  participant API as Webhook Handler
  participant Slack as Slack

  Stripe->>API: customer.subscription.created
  Note right of API: no trial_end gating — process when price.id & customer present
  API->>Slack: Post generic signup/new-subscription message
  Slack-->>API: OK
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Dashboard

Suggested reviewers

  • mcstepp
  • perkinsjr
  • MichaelUnkey

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "chore: remove trials" is concise and accurately summarizes the primary change of the PR — removal of trial-related functionality across billing, subscription creation, webhooks, docs, and email templates. It is short, focused, and immediately signals the main intent to reviewers.
Description Check ✅ Passed The PR description follows the repository template: it includes a clear summary of changes, the type-of-change checkboxes, testing instructions, and a completed checklist, making it largely complete and actionable for reviewers. However, the "Fixes #0000" line appears to be a placeholder and should be replaced with a real issue reference or removed.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 09-17-chore_remove_trials

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/dashboard/app/(app)/settings/billing/client.tsx (1)

93-110: Free-tier banner shows for unpaid/past_due users — tighten the condition.

Current isFreeTier treats any non‑active status as free, so users with payment issues will see both “Payment Required” and “Free tier” banners.

Apply:

-  const isFreeTier = !props.subscription || props.subscription.status !== "active";
+  // Only show free-tier when there is no subscription or it is canceled.
+  const isFreeTier =
+    !props.subscription || props.subscription.status === "canceled";
apps/engineering/content/docs/infrastructure/stripe/subscriptions.mdx (1)

27-28: Docs still claim “trials” — remove to reflect new flow.

Inconsistent with this PR’s removal of trials.

-Unkey's Stripe billing integration manages user subscriptions through a tiered pricing model, with support for legacy usage-based pricing. The system handles payment methods, trials, subscription management, and customer portals.
+Unkey's Stripe billing integration manages user subscriptions through a tiered pricing model, with support for legacy usage-based pricing. The system handles payment methods, subscription management, and customer portals.
🧹 Nitpick comments (6)
apps/dashboard/app/api/webhooks/stripe/route.ts (2)

112-116: Use the price’s currency instead of hardcoding USD.

Prevents wrong formatting if we ever list non‑USD prices.

Apply:

-        const formattedPrice = new Intl.NumberFormat("en-US", {
-          style: "currency",
-          currency: "USD",
-        }).format(price.unit_amount / 100);
+        const currency = (price.currency ?? "usd").toUpperCase();
+        const formattedPrice = new Intl.NumberFormat("en-US", {
+          style: "currency",
+          currency,
+        }).format((price.unit_amount ?? 0) / 100);

154-162: PII in Slack: consider masking email and/or add a unique reference.

Posting raw emails to Slack can be sensitive; mask it (e.g., a…@domain.com) or ensure the channel is restricted. Optionally include the subscription.id to aid dedup/debug.

Suggested masking inside alertSlack:

-            text: `A new subscription for the ${product} tier has started at a price of ${price} by ${email} :moneybag: `,
+            text: `A new subscription for the ${product} tier has started at ${price} by ${email.replace(/(^.).*(@.*$)/, "$1…$2")} :moneybag: `,
apps/dashboard/app/(app)/settings/billing/client.tsx (3)

90-93: Coerce flags to boolean for clearer types.

Avoids truthy object leakage into flags.

-  const allowUpdate = props.subscription && props.subscription.status === "active";
+  const allowUpdate = !!(props.subscription && props.subscription.status === "active");
-  const allowCancel =
-    props.subscription && props.subscription.status === "active" && !props.subscription.cancelAt;
+  const allowCancel = !!(
+    props.subscription &&
+    props.subscription.status === "active" &&
+    !props.subscription.cancelAt
+  );

105-105: Typo: Rename SusbcriptionStatus → SubscriptionStatus.

Small polish; improves readability and searchability.

-        {props.subscription ? <SusbcriptionStatus status={props.subscription.status} /> : null}
+        {props.subscription ? <SubscriptionStatus status={props.subscription.status} /> : null}
@@
-const SusbcriptionStatus: React.FC<{
+const SubscriptionStatus: React.FC<{

Also applies to: 305-335


185-189: Copy: avoid using “trial” in UI; use support link.

Keeps UI consistent with “no trials” policy and provides a clickable URL.

-                        fineprint="Do you need a trial? Contact support.unkey.dev"
+                        fineprint="Need an evaluation period? Contact us at https://support.unkey.dev"
apps/engineering/content/docs/infrastructure/stripe/subscriptions.mdx (1)

20-24: Optional: Call out “No Trials” explicitly in objectives.

Clarifies the policy right up front.

  3. **Frictionless Upgrades**
     - Seamless transition from free to paid
-    - Transparent upgrade process with payment method collection upfront
+    - Transparent upgrade process with payment method collection upfront
+4. **No Trials**
+   - Paid plans start immediately; evaluation access available by request via support
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfe590b and 68d9201.

📒 Files selected for processing (7)
  • apps/dashboard/app/(app)/settings/billing/client.tsx (4 hunks)
  • apps/dashboard/app/(app)/settings/billing/page.tsx (0 hunks)
  • apps/dashboard/app/api/webhooks/stripe/route.ts (2 hunks)
  • apps/dashboard/lib/trpc/routers/stripe/createSubscription.ts (0 hunks)
  • apps/engineering/content/docs/infrastructure/stripe/subscriptions.mdx (6 hunks)
  • internal/resend/emails/trial_ended.tsx (0 hunks)
  • internal/resend/src/client.tsx (0 hunks)
💤 Files with no reviewable changes (4)
  • apps/dashboard/lib/trpc/routers/stripe/createSubscription.ts
  • internal/resend/src/client.tsx
  • apps/dashboard/app/(app)/settings/billing/page.tsx
  • internal/resend/emails/trial_ended.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-10-04T20:44:38.489Z
Learnt from: chronark
PR: unkeyed/unkey#2180
File: apps/dashboard/lib/constants/workspace-navigations.tsx:56-118
Timestamp: 2024-10-04T20:44:38.489Z
Learning: When typing the `workspace` parameter in functions like `createWorkspaceNavigation`, prefer importing the `Workspace` type from the database module and picking the necessary keys (e.g., `features`) instead of redefining the interface.

Applied to files:

  • apps/engineering/content/docs/infrastructure/stripe/subscriptions.mdx
📚 Learning: 2025-04-08T09:34:24.576Z
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use `ctx.workspace.id` directly instead of fetching the workspace separately for better performance and security.

Applied to files:

  • apps/engineering/content/docs/infrastructure/stripe/subscriptions.mdx
🔇 Additional comments (3)
apps/dashboard/app/(app)/settings/billing/client.tsx (1)

2-2: Nice: Workspace type import matches our past guidance.

This aligns with the retrieved learning to use the DB Workspace type instead of redefining it.

apps/dashboard/app/api/webhooks/stripe/route.ts (1)

89-92: Resolved — workspace linking confirmed on subscription creation

createSubscription calls stripe.subscriptions.create and then updates the workspace with stripeSubscriptionId = sub.id (db.update(...).set({ stripeSubscriptionId: sub.id }) in apps/dashboard), so the "created" webhook will find the workspace.

apps/engineering/content/docs/infrastructure/stripe/subscriptions.mdx (1)

10-13: Resolved — calendar-month billing and proration are implemented

createSubscription.ts sets billing_cycle_anchor_config.day_of_month = 1 and proration_behavior = "always_invoice" (around lines 74–78).

@chronark chronark marked this pull request as ready for review September 18, 2025 06:52
@chronark chronark enabled auto-merge September 18, 2025 09:43
@github-actions
Copy link
Contributor

github-actions bot commented Sep 18, 2025

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
Member

@perkinsjr perkinsjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM couple of quick things.

Copy link
Member

@perkinsjr perkinsjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM works perfectly

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-delete-key.ts (1)

47-50: Standardize support contact to support@unkey.dev in user-facing strings

Toasts currently show "support.unkey.dev" while UI actions open mailto:support@unkey.dev — replace the plain-text domain with the email (or a mailto link) for consistency.

-          description: `We encountered an issue while deleting your ${keyText}. Please try again later or contact support at support.unkey.dev`,
+          description: `We encountered an issue while deleting your ${keyText}. Please try again later or contact support@unkey.dev`,

Also apply the same replacement in these files found by the search:

  • apps/dashboard/lib/trpc/routers/key/create.ts:63
  • apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/hooks/use-create-key.tsx:26
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/.../use-edit-credits.ts:29
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/.../use-edit-ratelimits.ts:47
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/.../use-update-key-status.tsx:15
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/.../use-edit-key.tsx:37
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/.../use-delete-key.ts:49
🧹 Nitpick comments (15)
apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-delete-key.ts (1)

62-63: Prefer location.href over window.open for mailto

window.open with "_blank" is superfluous for mailto and can trigger pop-up blockers. Use location.href for higher reliability.

-            onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+            onClick: () => (window.location.href = "mailto:support@unkey.dev"),
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/index.tsx (1)

121-122: Use location.href for mailto

Consistent with other places and avoids pop-up issues.

-          onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+          onClick: () => (window.location.href = "mailto:support@unkey.dev"),
apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-edit-ratelimits.ts (2)

54-55: Use location.href for mailto

-            onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+            onClick: () => (window.location.href = "mailto:support@unkey.dev"),

45-48: Make support contact consistent with mailto

Description still points to support.unkey.dev while action uses email.

-            "We encountered an issue while updating your key. Please try again later or contact support at support.unkey.dev",
+            "We encountered an issue while updating your key. Please try again later or contact support at support@unkey.dev",

Also applies to: 54-55

apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/hooks/use-create-key.tsx (2)

37-38: Use location.href for mailto

-            onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+            onClick: () => (window.location.href = "mailto:support@unkey.dev"),

24-27: Unify support reference to email

Keep the description consistent with the action.

-            "We encountered an issue while creating your key. Please try again later or contact support at support.unkey.dev",
+            "We encountered an issue while creating your key. Please try again later or contact support at support@unkey.dev",

Also applies to: 37-38

apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-edit-key.tsx (2)

48-49: Use location.href for mailto

-            onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+            onClick: () => (window.location.href = "mailto:support@unkey.dev"),

35-38: Replace support URL in description with email

Matches the new contact method used in the action.

-            "We encountered an issue while updating your key. Please try again later or contact support at support.unkey.dev",
+            "We encountered an issue while updating your key. Please try again later or contact support at support@unkey.dev",

Also applies to: 48-49

apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/components/key-created-success-dialog.tsx (1)

88-89: Use location.href for mailto

-                onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+                onClick: () => (window.location.href = "mailto:support@unkey.dev"),
apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-update-key-status.tsx (2)

22-23: Use location.href for mailto

-        onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+        onClick: () => (window.location.href = "mailto:support@unkey.dev"),

13-16: Align description with email contact

Description references support.unkey.dev; switch to email to match the action.

-        "We encountered an issue while updating your key(s). Please try again later or contact support at support.unkey.dev",
+        "We encountered an issue while updating your key(s). Please try again later or contact support at support@unkey.dev",

Also applies to: 22-23

apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-edit-credits.ts (2)

36-37: Use location.href for mailto

-            onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+            onClick: () => (window.location.href = "mailto:support@unkey.dev"),

27-30: Switch remaining support URL in description to email

Keep messaging consistent across toasts.

-            "We encountered an issue while updating your key. Please try again later or contact support at support.unkey.dev",
+            "We encountered an issue while updating your key. Please try again later or contact support at support@unkey.dev",

Also applies to: 36-37

apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/edit-credits/index.tsx (1)

76-79: Prefer location.href for mailto; prefill a subject for faster triage

Using window.open for mailto can spawn a blank tab in some browsers. Use location.href and add a helpful subject.

-                onClick: () => window.open("mailto:support@unkey.dev", "_blank"),
+                onClick: () => {
+                  window.location.href =
+                    "mailto:support@unkey.dev?subject=Failed%20to%20Update%20Key%20Limits";
+                },

Optional: centralize the support address (e.g., NEXT_PUBLIC_SUPPORT_EMAIL) to avoid future drifts across files.

apps/dashboard/app/(app)/settings/billing/client.tsx (1)

105-105: Typo: SusbcriptionStatus → SubscriptionStatus

Rename the component and its usages when convenient to avoid lingering misspellings in the codebase.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68d9201 and 061e36b.

⛔ Files ignored due to path filters (1)
  • deployment/data/metald/metald.db is excluded by !**/*.db
📒 Files selected for processing (10)
  • apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/components/key-created-success-dialog.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/hooks/use-create-key.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/edit-credits/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-delete-key.ts (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-edit-credits.ts (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-edit-key.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-edit-ratelimits.ts (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/components/hooks/use-update-key-status.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/billing/client.tsx (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test Packages / Test
  • GitHub Check: Build / Build
  • GitHub Check: Test API / API Test Local
🔇 Additional comments (2)
apps/dashboard/app/(app)/settings/billing/client.tsx (2)

187-188: Copy change to “Upgrade” looks good

Matches the no-trial flow and keeps intent clear.


201-201: Copy update LGTM

Clearer guidance now that trials are removed.

Comment on lines +90 to 94
const allowUpdate = props.subscription && props.subscription.status === "active";
const allowCancel =
props.subscription &&
["active", "trialing"].includes(props.subscription.status) &&
!props.subscription.cancelAt;
const isFreeTier =
!props.subscription || !["active", "trialing"].includes(props.subscription.status);
props.subscription && props.subscription.status === "active" && !props.subscription.cancelAt;
const isFreeTier = !props.subscription || props.subscription.status !== "active";
const selectedProductIndex = allowUpdate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Don’t show “Free tier” for delinquent/non-active paid statuses; align “Change vs Upgrade” behavior

Current isFreeTier = status !== "active" shows the Free tier alert alongside “Payment Required” for statuses like past_due/unpaid/incomplete. Also, the product list uses “updateSubscription” whenever subscription exists, which is wrong for canceled/paused; it should create a new subscription instead.

Apply:

  • Only treat as free tier when there’s no subscription or status is canceled/paused/incomplete_expired.
  • Drive the “update vs create” branch off allowUpdate, not truthiness of subscription.
@@
-  const mutations = Mutations();
-  const allowUpdate = props.subscription && props.subscription.status === "active";
-  const allowCancel =
-    props.subscription && props.subscription.status === "active" && !props.subscription.cancelAt;
-  const isFreeTier = !props.subscription || props.subscription.status !== "active";
+  const mutations = Mutations();
+  const status = props.subscription?.status;
+  const allowUpdate = status === "active";
+  const allowCancel = status === "active" && !props.subscription?.cancelAt;
+  const isFreeTier =
+    !status || status === "canceled" || status === "paused" || status === "incomplete_expired";
@@
-                    {props.subscription ? (
+                    {allowUpdate ? (
                       <Confirm
                         title={`${i > selectedProductIndex ? "Upgrade" : "Downgrade"} to ${p.name}`}
@@
-                    ) : (
+                    ) : (
                       <Confirm
                         title={`Upgrade to ${p.name}`}

Result: no contradictory banners; canceled/paused users get a clean “Upgrade” create flow instead of a failing “Change” update flow.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/dashboard/app/(app)/settings/billing/client.tsx around lines 90 to 94,
the isFreeTier boolean and selectedProductIndex logic are incorrect: change
isFreeTier to be true only when there is no subscription OR the
subscription.status is explicitly one of "canceled", "paused", or
"incomplete_expired" (so delinquent statuses like
"past_due"/"unpaid"/"incomplete" are not treated as free tier), and change the
branch that decides whether to call update vs create to be driven by allowUpdate
(i.e., set selectedProductIndex/use updateSubscription only when allowUpdate is
true) rather than by the mere existence/truthiness of props.subscription; leave
allowUpdate/allowCancel logic as-is.

@chronark chronark disabled auto-merge September 19, 2025 13:02
@chronark chronark merged commit 659afa5 into main Sep 19, 2025
19 checks passed
@chronark chronark deleted the 09-17-chore_remove_trials branch September 19, 2025 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants