Skip to content

feat(desktop): show Pro badge in account dropdown#3878

Merged
Kitenite merged 3 commits into
mainfrom
pro-indicator-dropdown
Apr 29, 2026
Merged

feat(desktop): show Pro badge in account dropdown#3878
Kitenite merged 3 commits into
mainfrom
pro-indicator-dropdown

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Apr 29, 2026

Summary

  • Adds a billing.activePlan tRPC query that returns the active org's plan tier and subscription status (defaults to free when there's no active subscription).
  • Renders a Pro / Enterprise badge next to the user's name in the AgentsHeader desktop dropdown and mobile drawer when the org is on a paid plan.
  • Skipped the legacy (dashboard-legacy)/Header.tsx since the v1 dashboard is being sunset.

Test plan

  • Sign in as a user whose active org is on the free plan — no badge shows.
  • Switch to an org on proPro badge renders next to the name in both the desktop dropdown and the mobile drawer.
  • Switch to an org on enterprise — badge label reads Enterprise.
  • Subscription with non-active status (e.g. canceled) does not show a badge.

Summary by cubic

Show a Pro/Enterprise badge when the active org has a paid plan in the web account menu (dropdown + mobile drawer) and the desktop Organization dropdown. Adds a billing.activePlan tRPC query to expose the active org’s plan and subscription status.

  • New Features

    • billing.activePlan returns { plan, status } for the active org; defaults to free/null and filters to active statuses via @superset/shared/billing.
    • Web (AgentsHeader): render a Badge next to the user’s name in the desktop dropdown and mobile drawer; label shows "Pro" or "Enterprise"; hidden for free or non-active subscriptions.
    • Desktop (OrganizationDropdown): render a Badge next to the org name in both trigger variants using useCurrentPlan.
  • Bug Fixes

    • Avoid stale plan text by computing the label only when on a paid tier.
    • Remove a redundant status check in billing.activePlan.

Written for commit 3c17e8e. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features
    • Your active billing plan is now shown with a compact badge next to your account name and organization name in both mobile and desktop menus.
    • A human-readable plan label and status are consistently displayed across account and organization dropdowns, with the badge shown only for non-free (paid) plans.
    • The app reliably falls back to a free plan label when no active subscription is found.

Adds a `billing.activePlan` tRPC query and renders a Pro/Enterprise
badge next to the user's name in the AgentsHeader dropdown and mobile
drawer when the active org has a paid subscription.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 09856416-2622-439c-88f7-efa62a11ff26

📥 Commits

Reviewing files that changed from the base of the PR and between 4d931ba and 3c17e8e.

📒 Files selected for processing (2)
  • apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx
  • packages/trpc/src/router/billing/billing.ts

📝 Walkthrough

Walkthrough

Added a protected backend query billing.activePlan to return an org's current plan (fallback to free) and updated UI components to fetch it, compute paid status/label, and conditionally render a compact plan Badge next to user/org display names.

Changes

Cohort / File(s) Summary
Billing Router
packages/trpc/src/router/billing/billing.ts
New billing.activePlan protected query: finds latest subscription for the active org filtered by active statuses, returns { plan, status } with fallback { plan: "free", status: null }.
Web Agents Header UI
apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx
Calls trpc.billing.activePlan, computes isPaidPlan and planLabel, and conditionally renders a compact Badge beside the user's name in mobile drawer and desktop account dropdown when paid.
Desktop Organization Dropdown
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/OrganizationDropdown/OrganizationDropdown.tsx
Uses useCurrentPlan()/activePlan to derive planLabel and conditionally shows a Badge in both expanded and compact organization trigger variants when plan ≠ free.

Sequence Diagram(s)

sequenceDiagram
  participant UI as Client UI
  participant TRPC as TRPC Client
  participant Router as billingRouter
  participant DB as Database

  UI->>TRPC: request activePlan
  TRPC->>Router: invoke protected billing.activePlan
  Router->>DB: query subscriptions for org (filter ACTIVE_SUBSCRIPTION_STATUSES, order by createdAt desc)
  DB-->>Router: subscription or empty
  Router-->>TRPC: { plan, status } (or fallback { plan: "free", status: null })
  TRPC-->>UI: activePlan response
  UI->>UI: compute isPaidPlan & planLabel
  UI-->>UI: render Badge if paid
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through rows of plans and strings,
I sniffed the latest subscription wings.
From DB to UI I pranced with glee,
A tiny badge now sits by thee,
Carrot-chip cheer for pro and free! 🥕✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description provides a clear summary, test plan, and rationale; however, it does not follow the required template structure with labeled sections like Description, Related Issues, Type of Change, Testing, and Screenshots. Reorganize the description to match the template format: add a 'Description' section, explicit 'Type of Change' checkboxes (mark 'New feature'), and a formal 'Testing' section with the test plan items.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change—displaying a Pro badge in the account dropdown—which is a primary objective of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pro-indicator-dropdown

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
Review rate limit: 3/8 reviews remaining, refill in 35 minutes and 46 seconds.

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 29, 2026

Greptile Summary

This PR introduces a billing.activePlan tRPC endpoint that queries the active org's subscription from the database and returns the plan tier, then uses that data to render a Pro / Enterprise badge next to the user's name in the AgentsHeader desktop dropdown and mobile drawer. The implementation is straightforward and the gating logic (using the shared isPaidPlan / isActiveSubscriptionStatus helpers) is applied consistently.

Confidence Score: 5/5

Safe to merge — all findings are minor style/robustness suggestions with no blocking issues.

Both changed files are straightforward. The only issues found are a redundant double-check of the subscription status (P2 style) and a slightly brittle planLabel fallback that is currently unreachable in practice (P2). No P0/P1 defects identified.

No files require special attention.

Important Files Changed

Filename Overview
packages/trpc/src/router/billing/billing.ts Adds activePlan tRPC query that fetches the org's active subscription from the DB, filters by active statuses, and returns the plan tier; contains a redundant double-check of the subscription status (P2).
apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx Adds Pro/Enterprise badge rendering in both the desktop dropdown and mobile drawer; planLabel fallback defaults to "Pro" when data is loading, which is harmless today but slightly brittle (P2).

Sequence Diagram

sequenceDiagram
    participant UI as AgentsHeader (React)
    participant tRPC as tRPC billing.activePlan
    participant DB as Database (subscriptions)

    UI->>tRPC: useQuery(activePlan)
    tRPC->>tRPC: check ctx.activeOrganizationId
    alt no active org
        tRPC-->>UI: { plan: "free", status: null }
    else has active org
        tRPC->>DB: findFirst WHERE referenceId=orgId AND status IN ["active","trialing"] ORDER BY createdAt DESC
        DB-->>tRPC: subscription | undefined
        alt no active subscription
            tRPC-->>UI: { plan: "free", status: null }
        else active subscription found
            tRPC-->>UI: { plan: subscription.plan, status: subscription.status }
        end
    end
    UI->>UI: isPro = isPaidPlan(activePlan?.plan)
    alt isPro
        UI->>UI: Render Badge with capitalized plan name
    else not paid
        UI->>UI: No badge shown
    end
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: packages/trpc/src/router/billing/billing.ts
Line: 84-86

Comment:
**Redundant status guard after filtered query**

The `inArray(subscriptions.status, ACTIVE_SUBSCRIPTION_STATUSES)` WHERE clause already guarantees that any row returned has an active-subscription status, so the `!isActiveSubscriptionStatus(subscription.status)` branch on line 84 is always false when a subscription is found. The secondary check adds no safety; it only adds noise and the risk of the two lists drifting apart silently.

```suggestion
		if (!subscription) {
			return { plan: "free" as const, status: null };
		}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx
Line: 52-54

Comment:
**Stale `planLabel` when `activePlan` is loading**

When `activePlan` is still loading (`undefined`), `activePlan?.plan` is `undefined` (falsy), so `planLabel` is hardcoded to `"Pro"`. At the same moment, `isPro` evaluates to `false`, so the badge is not rendered — the wrong default is never visible today. But if the loading-state logic ever changes (e.g., `isPro` uses a previous cached value while a new org's plan is being fetched), the stale `"Pro"` label could flash incorrectly.

Consider deriving the label only when `activePlan?.plan` is a known paid tier:

```suggestion
	const planLabel =
		activePlan?.plan && activePlan.plan !== "free"
			? activePlan.plan.charAt(0).toUpperCase() + activePlan.plan.slice(1)
			: null;
```

Then render `{isPro && planLabel && <Badge ...>{planLabel}</Badge>}`.

```suggestion
	const planLabel =
		activePlan?.plan && activePlan.plan !== "free"
			? activePlan.plan.charAt(0).toUpperCase() + activePlan.plan.slice(1)
			: null;
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(web): show Pro badge in account dro..." | Re-trigger Greptile

Comment on lines +84 to +86
if (!subscription || !isActiveSubscriptionStatus(subscription.status)) {
return { plan: "free" as const, status: null };
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Redundant status guard after filtered query

The inArray(subscriptions.status, ACTIVE_SUBSCRIPTION_STATUSES) WHERE clause already guarantees that any row returned has an active-subscription status, so the !isActiveSubscriptionStatus(subscription.status) branch on line 84 is always false when a subscription is found. The secondary check adds no safety; it only adds noise and the risk of the two lists drifting apart silently.

Suggested change
if (!subscription || !isActiveSubscriptionStatus(subscription.status)) {
return { plan: "free" as const, status: null };
}
if (!subscription) {
return { plan: "free" as const, status: null };
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/trpc/src/router/billing/billing.ts
Line: 84-86

Comment:
**Redundant status guard after filtered query**

The `inArray(subscriptions.status, ACTIVE_SUBSCRIPTION_STATUSES)` WHERE clause already guarantees that any row returned has an active-subscription status, so the `!isActiveSubscriptionStatus(subscription.status)` branch on line 84 is always false when a subscription is found. The secondary check adds no safety; it only adds noise and the risk of the two lists drifting apart silently.

```suggestion
		if (!subscription) {
			return { plan: "free" as const, status: null };
		}
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) View Branch
Vercel API (Vercel) Open Preview
Vercel Web (Vercel) Open Preview
Vercel Marketing (Vercel) Open Preview
Vercel Admin (Vercel) Open Preview
Vercel Docs (Vercel) Open Preview

Preview updates automatically with new commits

Renders a Pro/Enterprise badge next to the org name in the desktop
OrganizationDropdown trigger (topbar and expanded sidebar variants),
using the existing useCurrentPlan hook.
- billing.activePlan: drop redundant status check; the WHERE clause
  already restricts to ACTIVE_SUBSCRIPTION_STATUSES.
- AgentsHeader: derive planLabel only when on a paid tier so a stale
  "Pro" string can't surface if loading-state logic changes.
@Kitenite Kitenite changed the title feat(web): show Pro badge in account dropdown feat(desktop): show Pro badge in account dropdown Apr 29, 2026
@Kitenite Kitenite merged commit 2e9494f into main Apr 29, 2026
12 of 13 checks passed
@Kitenite Kitenite deleted the pro-indicator-dropdown branch April 29, 2026 23:53
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.

1 participant