Skip to content

feat(billing): add top up credits button - #1169

Merged
steebchen merged 1 commit into
mainfrom
claude/add-topup-credits-button-0186nQarxUeA94fuXKCduTrn
Nov 18, 2025
Merged

steebchen merged 1 commit into
mainfrom
claude/add-topup-credits-button-0186nQarxUeA94fuXKCduTrn

Conversation

@steebchen

@steebchen steebchen commented Nov 18, 2025 •

Copy link
Copy Markdown
Member
image
  • Add Credits card showing current balance with status
  • Add Top Up Credits button for easy access
  • Create CreditsBalance component with visual indicators
  • Add "use client" directive to top-up dialog
  • Display warnings for low/no credits

Summary by CodeRabbit

  • New Features
    • Added a credits balance card to the billing page displaying current account credits.
    • Integrated visual status indicators showing credit level states (no credits, low credits, or healthy balance).
    • Added Top Up button directly on the billing overview for easy credit purchases.

- Add Credits card showing current balance with status
- Add Top Up Credits button for easy access
- Create CreditsBalance component with visual indicators
- Add "use client" directive to top-up dialog
- Display warnings for low/no credits
@github-actions github-actions Bot changed the title Add top up credits button to billing page feat(billing): add top up credits button Nov 18, 2025
@coderabbitai

coderabbitai Bot commented Nov 18, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Introduces a new CreditsBalance component for displaying organization credits with status-based styling (no credits, low credits, healthy balance). Integrates this component into the Billing page alongside the TopUpCreditsButton. Adds the "use client" directive to an existing dialog component.

Changes

Cohort / File(s) Change Summary
Credits balance UI component
apps/ui/src/app/dashboard/[orgId]/org/billing/credits-balance.tsx
New React client component that reads selected organization from dashboard state and renders a credits balance card with dynamic styling based on credit status (no credits, low credits, or healthy balance)
Billing page integration
apps/ui/src/app/dashboard/[orgId]/org/billing/page.tsx
Adds new Credits card section to billing page with TopUpCreditsButton and CreditsBalance component; imports two new components
Client directive
apps/ui/src/components/credits/top-up-credits-dialog.tsx
Adds "use client" directive to establish module as client-side component

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • The CreditsBalance component introduces straightforward conditional rendering logic based on credit amounts with no complex state management or error handling
  • Billing page integration is a simple UI addition with standard component composition
  • All changes are localized to UI layer without affecting business logic or data flow

Possibly related PRs

Suggested reviewers

  • smakosh

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(billing): add top up credits button' accurately reflects the main change: adding a top-up credits button to the billing page.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/add-topup-credits-button-0186nQarxUeA94fuXKCduTrn

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/ui/src/app/dashboard/[orgId]/org/billing/credits-balance.tsx (1)

24-25: Consider extracting hardcoded thresholds to constants.

The low credits threshold (< 1) is hardcoded. Consider defining it as a named constant for easier maintenance and potential future configuration.

+const LOW_CREDITS_THRESHOLD = 1;
+const NO_CREDITS_THRESHOLD = 0;
+
 export function CreditsBalance() {
 	const { selectedOrganization } = useDashboardState();
 	
 	// ...
 	
-	const isLowCredits = creditsBalance < 1;
-	const hasNoCredits = creditsBalance <= 0;
+	const isLowCredits = creditsBalance < LOW_CREDITS_THRESHOLD;
+	const hasNoCredits = creditsBalance <= NO_CREDITS_THRESHOLD;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b9004b and 8b927a1.

📒 Files selected for processing (3)
  • apps/ui/src/app/dashboard/[orgId]/org/billing/credits-balance.tsx (1 hunks)
  • apps/ui/src/app/dashboard/[orgId]/org/billing/page.tsx (3 hunks)
  • apps/ui/src/components/credits/top-up-credits-dialog.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/ui/src/app/dashboard/[orgId]/org/billing/page.tsx (2)
apps/ui/src/components/credits/top-up-credits-dialog.tsx (1)
  • TopUpCreditsButton (33-42)
apps/ui/src/app/dashboard/[orgId]/org/billing/credits-balance.tsx (1)
  • CreditsBalance (7-98)
🪛 ESLint
apps/ui/src/app/dashboard/[orgId]/org/billing/credits-balance.tsx

[error] 1-1: Resolve error: EACCES: permission denied, open '/hdGZOpoqrH'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import@2.32.0_eslint@9.34.0_jiti@2.6.1_/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/.pnpm/eslint-module-utils@2.12.1_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1__t_eb0afb446ca3f59399f5d681f0059e64/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/.pnpm/eslint-module-utils@2.12.1_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1__t_eb0afb446ca3f59399f5d681f0059e64/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/.pnpm/eslint-module-utils@2.12.1_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1__t_eb0afb446ca3f59399f5d681f0059e64/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/.pnpm/eslint-module-utils@2.12.1_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1__t_eb0afb446ca3f59399f5d681f0059e64/node_modules/eslint-module-utils/resolve.js:233:12)
at resolveImportType (/home/jailuser/git/node_modules/.pnpm/eslint-plugin-import@2.32.0_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1___986ec7d736a20dae59d4d473ff8a6f0d/node_modules/eslint-plugin-import/lib/core/importType.js:126:2822)
at computeRank (/home/jailuser/git/node_modules/.pnpm/eslint-plugin-import@2.32.0_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1___986ec7d736a20dae59d4d473ff8a6f0d/node_modules/eslint-plugin-import/lib/rules/order.js:529:43)

(import/order)

apps/ui/src/components/credits/top-up-credits-dialog.tsx

[error] 1-1: Resolve error: EACCES: permission denied, open '/NKwIdkHICO'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import@2.32.0_eslint@9.34.0_jiti@2.6.1_/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/.pnpm/eslint-module-utils@2.12.1_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1__t_eb0afb446ca3f59399f5d681f0059e64/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/.pnpm/eslint-module-utils@2.12.1_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1__t_eb0afb446ca3f59399f5d681f0059e64/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/.pnpm/eslint-module-utils@2.12.1_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1__t_eb0afb446ca3f59399f5d681f0059e64/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/.pnpm/eslint-module-utils@2.12.1_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1__t_eb0afb446ca3f59399f5d681f0059e64/node_modules/eslint-module-utils/resolve.js:233:12)
at resolveImportType (/home/jailuser/git/node_modules/.pnpm/eslint-plugin-import@2.32.0_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1___986ec7d736a20dae59d4d473ff8a6f0d/node_modules/eslint-plugin-import/lib/core/importType.js:126:2822)
at computeRank (/home/jailuser/git/node_modules/.pnpm/eslint-plugin-import@2.32.0_@typescript-eslint+parser@8.39.1_eslint@9.34.0_jiti@2.6.1___986ec7d736a20dae59d4d473ff8a6f0d/node_modules/eslint-plugin-import/lib/rules/order.js:529:43)

(import/order)

⏰ 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 / run
  • GitHub Check: build / run
  • GitHub Check: lint / run
  • GitHub Check: autofix
🔇 Additional comments (6)
apps/ui/src/components/credits/top-up-credits-dialog.tsx (1)

1-1: LGTM! Correct addition of "use client" directive.

This directive is appropriate for this component given its use of React hooks (useState, useEffect), Stripe client-side elements, and interactive form handling.

apps/ui/src/app/dashboard/[orgId]/org/billing/credits-balance.tsx (3)

10-19: LGTM! Clean loading state handling.

The loading state provides clear feedback while organization data is being fetched.


27-97: LGTM! Well-structured status display with clear visual hierarchy.

The conditional rendering logic correctly prioritizes status messages (no credits → low credits → healthy), and the color-coded UI provides clear visual feedback to users.


21-25: Verify credits field type from external "@llmgateway/db" package before dismissing null safety concerns.

The original review flags a real risk: if selectedOrganization.credits is undefined, null, or an invalid string, Number() returns NaN, which displays as "$NaN" and incorrectly shows "Healthy balance" status (since NaN < 1 and NaN <= 0 both evaluate to false).

While the code has an early guard checking if (!selectedOrganization), this only validates the object exists—not that the credits field is a valid value. With "strict": true enabled in tsconfig.json, TypeScript should catch optional fields, but the type definition for SerializedOrganization is in the external package @llmgateway/db and is not accessible.

Developer action: Check whether the credits field in SerializedOrganization (from @llmgateway/db) is guaranteed to be a non-null, valid number string. If the field can be undefined or non-numeric, implement the defensive handling suggested in the original review.

apps/ui/src/app/dashboard/[orgId]/org/billing/page.tsx (2)

4-4: LGTM! Clean imports for new credit management components.

Import paths are correct and the components are properly utilized in the billing page.

Also applies to: 13-13


39-52: LGTM! Well-integrated Credits card with appropriate placement.

The Credits card is positioned prominently at the top of the billing page, providing immediate visibility of the credit balance and easy access to the top-up action. The structure is consistent with other cards on the page.

@steebchen
steebchen added this pull request to the merge queue Nov 18, 2025
Merged via the queue into main with commit 5d9e652 Nov 18, 2025
9 checks passed
@steebchen
steebchen deleted the claude/add-topup-credits-button-0186nQarxUeA94fuXKCduTrn branch November 18, 2025 14:18
@coderabbitai coderabbitai Bot mentioned this pull request Apr 13, 2026
12 tasks
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.

3 participants