Skip to content

Move billing flows to web dashboard#956

Merged
senamakel merged 2 commits intotinyhumansai:mainfrom
senamakel:fix/redirect-billing
Apr 27, 2026
Merged

Move billing flows to web dashboard#956
senamakel merged 2 commits intotinyhumansai:mainfrom
senamakel:fix/redirect-billing

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented Apr 27, 2026

Summary

  • route all desktop billing CTAs to https://tinyhumans.ai/dashboard instead of the in-app billing settings page
  • remove the Billing & Usage entry from Settings so the old embedded billing surface is no longer exposed in the UI
  • replace the old billing panel with a lightweight redirect/fallback screen so stale /settings/billing links still land safely
  • centralize the billing dashboard URL in app/src/utils/links.ts

Problem

  • Billing management has moved to the web, but the desktop app still exposed subscription, top-up, payment-method, and billing-history panels.
  • Several billing-related entry points still navigated users into the old in-app settings route, which no longer matches the current product flow.
  • Stale deep links and existing internal links to /settings/billing still needed a safe fallback instead of a dead-end or broken panel.

Solution

  • Replaced in-app billing navigations with openUrl(BILLING_DASHBOARD_URL) across the usage pill, upsell surfaces, conversation limit banners, and deep-link payment completion handling.
  • Removed the Billing & Usage menu item from Settings home so the deprecated billing panels are no longer a first-class settings destination.
  • Simplified BillingPanel into a redirect-oriented fallback view that auto-opens the dashboard and provides a manual retry button if the browser does not open.
  • Kept the existing /settings/billing route in place as a compatibility shim rather than removing the route entirely.

Submission Checklist

  • Unit tests — Vitest (app/) and/or cargo test (core) for logic you add or change
  • E2E / integration — Where behavior is user-visible or crosses UI → Tauri → sidecar → JSON-RPC; use existing harnesses (app/test/e2e, mock backend, tests/json_rpc_e2e.rs as appropriate)
  • N/A — E2E not added because this change only reroutes existing billing entry points to an external URL and keeps the legacy route as a compatibility shim
  • Doc comments/// / //! (Rust), JSDoc or brief file/module headers (TS) on public APIs and non-obvious modules
  • Inline comments — Where logic, invariants, or edge cases aren’t clear from names alone (keep them grep-friendly; avoid restating the code)

(Any feature related checklist can go in here)

Impact

  • Desktop UI only; no Rust core or JSON-RPC behavior changed.
  • Billing management now consistently leaves the app and opens the TinyHumans web dashboard.
  • Existing billing deep links and stale internal billing links remain compatible through the redirect fallback.

Related

  • Closes:
  • Follow-up PR(s)/TODOs:

Summary by CodeRabbit

  • New Features

    • Integrated external billing dashboard for billing and subscription management
  • Refactor

    • Removed in-app billing panel; users now directed to the external dashboard via “Open dashboard” control
    • Unified billing navigation across the app (settings, banners, modals, conversations) to open the external dashboard
    • Post-checkout flows now open the external dashboard and return users to Home afterward

@senamakel senamakel requested a review from a team April 27, 2026 02:08
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e2c8a238-15c8-4f89-8577-ecf7d06b292a

📥 Commits

Reviewing files that changed from the base of the PR and between d866db6 and f6317d4.

📒 Files selected for processing (1)
  • app/src/components/settings/SettingsHome.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/components/settings/SettingsHome.tsx

📝 Walkthrough

Walkthrough

Replaces in-app billing navigation and UI with an external dashboard flow: a new BILLING_DASHBOARD_URL constant is added, multiple components now call openUrl(BILLING_DASHBOARD_URL) instead of navigating to /settings/billing, and BillingPanel is simplified to open the external dashboard on mount.

Changes

Cohort / File(s) Summary
New Billing URL Constant
app/src/utils/links.ts
Adds exported BILLING_DASHBOARD_URL pointing to external dashboard.
Import updates (replace local/hardcoded URL)
app/src/components/OpenhumanLinkModal.tsx, app/src/components/home/HomeBanners.tsx
Switch to importing shared BILLING_DASHBOARD_URL instead of local hardcoded values.
UI → External URL: chat/upsell/pages
app/src/components/chat/TokenUsagePill.tsx, app/src/components/upsell/GlobalUpsellBanner.tsx, app/src/components/upsell/UsageLimitModal.tsx, app/src/pages/Conversations.tsx
Remove client-side route navigation (useNavigate / navigate('/settings/billing')) and replace CTA handlers with void openUrl(BILLING_DASHBOARD_URL).
Settings: Billing entry
app/src/components/settings/SettingsHome.tsx
Change billing settings item to open external dashboard via openUrl(BILLING_DASHBOARD_URL); adjust description text.
BillingPanel refactor
app/src/components/settings/panels/BillingPanel.tsx
Remove internal billing fetches, multi-tab UI and payment handlers; mount triggers openUrl(BILLING_DASHBOARD_URL) with simple status state and “Open dashboard” / “Back to settings” controls.
Deep link/payment listener
app/src/utils/desktopDeepLinkListener.ts
On payment success/cancel, open external dashboard with openUrl(BILLING_DASHBOARD_URL) then set in-app route hash to /home (replacing direct navigation to billing).

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant UI as App Component
  participant Utils as openUrl helper
  participant Browser as External Dashboard

  rect rgba(200,200,255,0.5)
  User->>UI: Click billing CTA
  UI->>Utils: openUrl(BILLING_DASHBOARD_URL)
  Utils->>Browser: Open external URL
  Browser-->>User: Dashboard opens
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 I hopped through code with nimble feet,
Billing links now point to lands more sweet,
One constant guides where dashboards bloom,
Click — and your billing hops out of the room! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Move billing flows to web dashboard' clearly and concisely summarizes the main change: routing billing interactions from the desktop app to an external web dashboard.
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 unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
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

🧹 Nitpick comments (1)
app/src/pages/Conversations.tsx (1)

1295-1297: Optional: extract a shared openBillingDashboard handler.

The same click body is duplicated across billing CTAs, which makes future telemetry/error-handling tweaks easier to miss.

♻️ Suggested cleanup
+  const openBillingDashboard = () => {
+    void openUrl(BILLING_DASHBOARD_URL);
+  };
...
-                      onCtaClick={() => {
-                        void openUrl(BILLING_DASHBOARD_URL);
-                      }}
+                      onCtaClick={openBillingDashboard}
...
-                      onClick={() => {
-                        void openUrl(BILLING_DASHBOARD_URL);
-                      }}
+                      onClick={openBillingDashboard}

Also applies to: 1328-1330

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/pages/Conversations.tsx` around lines 1295 - 1297, Duplicate inline
handlers calling openUrl(BILLING_DASHBOARD_URL) should be extracted into a
single named handler (e.g., openBillingDashboard) so telemetry, error handling,
or URL changes are centralized; create a function openBillingDashboard that
calls openUrl(BILLING_DASHBOARD_URL) (and wraps try/catch/telemetry as needed),
then replace the inline onCtaClick={() => { void openUrl(BILLING_DASHBOARD_URL);
}} usages with onCtaClick={openBillingDashboard} (apply to the occurrences
currently using openUrl(BILLING_DASHBOARD_URL), including the handler used for
billing CTAs referenced in this diff and the other occurrence you noted).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/utils/desktopDeepLinkListener.ts`:
- Around line 106-107: The current flow awaits openUrl(BILLING_DASHBOARD_URL) so
if that promise rejects the subsequent navigation (window.location.hash =
'/home') is skipped; modify the handler in desktopDeepLinkListener so
post-payment navigation is unconditional: either call openUrl without awaiting
it or wrap the await openUrl(...) in a try/catch and always execute
window.location.hash = '/home' in a finally (or after the try/catch). Ensure you
update both places where openUrl(...) and window.location.hash are used (the
checkout/confirm and cancel handlers) so failures opening the external URL
cannot block client-side navigation.

---

Nitpick comments:
In `@app/src/pages/Conversations.tsx`:
- Around line 1295-1297: Duplicate inline handlers calling
openUrl(BILLING_DASHBOARD_URL) should be extracted into a single named handler
(e.g., openBillingDashboard) so telemetry, error handling, or URL changes are
centralized; create a function openBillingDashboard that calls
openUrl(BILLING_DASHBOARD_URL) (and wraps try/catch/telemetry as needed), then
replace the inline onCtaClick={() => { void openUrl(BILLING_DASHBOARD_URL); }}
usages with onCtaClick={openBillingDashboard} (apply to the occurrences
currently using openUrl(BILLING_DASHBOARD_URL), including the handler used for
billing CTAs referenced in this diff and the other occurrence you noted).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7baa10f1-95b2-4c67-992d-49bee8090fe0

📥 Commits

Reviewing files that changed from the base of the PR and between e3c46d1 and d866db6.

📒 Files selected for processing (10)
  • app/src/components/OpenhumanLinkModal.tsx
  • app/src/components/chat/TokenUsagePill.tsx
  • app/src/components/home/HomeBanners.tsx
  • app/src/components/settings/SettingsHome.tsx
  • app/src/components/settings/panels/BillingPanel.tsx
  • app/src/components/upsell/GlobalUpsellBanner.tsx
  • app/src/components/upsell/UsageLimitModal.tsx
  • app/src/pages/Conversations.tsx
  • app/src/utils/desktopDeepLinkListener.ts
  • app/src/utils/links.ts
💤 Files with no reviewable changes (1)
  • app/src/components/settings/SettingsHome.tsx

Comment on lines +106 to +107
await openUrl(BILLING_DASHBOARD_URL);
window.location.hash = '/home';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t gate post-payment navigation on external URL open success.

At Line 106 and Line 111, a failure from openUrl(...) can prevent window.location.hash = '/home', leaving users stuck in an unintended state after checkout/cancel handling.

🛠️ Suggested fix
+const openBillingDashboardAndReturnHome = async () => {
+  try {
+    await openUrl(BILLING_DASHBOARD_URL);
+  } catch (error) {
+    console.warn('[DeepLink] Could not open billing dashboard', error);
+  } finally {
+    window.location.hash = '/home';
+  }
+};
...
-    await openUrl(BILLING_DASHBOARD_URL);
-    window.location.hash = '/home';
+    await openBillingDashboardAndReturnHome();
...
-    await openUrl(BILLING_DASHBOARD_URL);
-    window.location.hash = '/home';
+    await openBillingDashboardAndReturnHome();

Also applies to: 111-112

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/utils/desktopDeepLinkListener.ts` around lines 106 - 107, The current
flow awaits openUrl(BILLING_DASHBOARD_URL) so if that promise rejects the
subsequent navigation (window.location.hash = '/home') is skipped; modify the
handler in desktopDeepLinkListener so post-payment navigation is unconditional:
either call openUrl without awaiting it or wrap the await openUrl(...) in a
try/catch and always execute window.location.hash = '/home' in a finally (or
after the try/catch). Ensure you update both places where openUrl(...) and
window.location.hash are used (the checkout/confirm and cancel handlers) so
failures opening the external URL cannot block client-side navigation.

@senamakel senamakel merged commit 74e532d into tinyhumansai:main Apr 27, 2026
9 checks passed
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