Skip to content

feat(billing): Add seats info to payment attempts page#8527

Draft
aeliox wants to merge 1 commit into
mainfrom
keiran/BILL-1752
Draft

feat(billing): Add seats info to payment attempts page#8527
aeliox wants to merge 1 commit into
mainfrom
keiran/BILL-1752

Conversation

@aeliox
Copy link
Copy Markdown
Contributor

@aeliox aeliox commented May 12, 2026

Adds seat info to payment attempts page

@vercel
Copy link
Copy Markdown

vercel Bot commented May 12, 2026

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment May 12, 2026 4:28am

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 12, 2026

🦋 Changeset detected

Latest commit: 454faa6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@clerk/shared Minor
@clerk/clerk-js Minor
@clerk/ui Minor
@clerk/astro Patch
@clerk/backend Patch
@clerk/chrome-extension Patch
@clerk/expo-passkeys Patch
@clerk/expo Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/hono Patch
@clerk/localizations Patch
@clerk/msw Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/react Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/vue Patch

Not sure what this means? Click here to learn what changesets are.

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

@aeliox aeliox marked this pull request as draft May 12, 2026 04:28
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces seat-based billing totals to payment attempts across the stack. It starts by defining the BillingPaymentTotals contract (subtotal, grand total, tax, optional base fee and per-unit tiers), then implements JSON deserialization to convert API responses to typed objects. The BillingPayment resource class is extended with the new totals field. Seat-specific helper functions extract and summarize per-seat pricing. Finally, the payment attempt detail UI is refactored to render a new "Seats" line item when seat billing is present, displaying usage, included seat counts, and tier pricing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 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
Title check ✅ Passed The title accurately summarizes the main change: adding seat information to the payment attempts page, which is reflected across multiple files and components.
Description check ✅ Passed The description is concise but directly related to the changeset, confirming that seat info is being added to the payment attempts page.
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.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx`:
- Around line 232-243: The seats description currently always renders a
quantity×rate string; update the JSX in the PaymentAttemptPage component so that
when seatSummary.paidTier.quantity === null (an unlimited paid tier) you do not
render the "× {feePerBlock}" piece and instead only show the tier total,
otherwise keep the existing "{used} × {feePerBlock}" behavior; specifically
adjust the LineItems.Title description expression (using seatSummary,
seatSummary.paidTier.quantity, seatSummary.paidTier.feePerBlock and
seatSummary.paidTier.total) to branch on paidTier.quantity and produce the
appropriate string for unlimited vs. limited tiers.
🪄 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: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cd96259-918b-49c3-9ce0-6aa6a4195339

📥 Commits

Reviewing files that changed from the base of the PR and between c5fd14c and 454faa6.

📒 Files selected for processing (9)
  • .changeset/billing-seat-tier-rows-payment-attempt.md
  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/utils/__tests__/billing.test.ts
  • packages/clerk-js/src/utils/billing.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
  • packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/ui/src/utils/__tests__/billingPlanSeats.test.ts
  • packages/ui/src/utils/billingPlanSeats.ts

Comment on lines +232 to +243
{seatSummary && (
<LineItems.Group variant='tertiary'>
<LineItems.Title
title={localizationKeys('billing.seats')}
description={`${seatSummary.used} ${seatSummary.used === 1 ? 'seat' : 'seats'}${
seatSummary.included > 0 ? ` (${seatSummary.included} included)` : ''
} × ${seatSummary.paidTier.feePerBlock.currencySymbol}${seatSummary.paidTier.feePerBlock.amountFormatted}`}
/>
<LineItems.Description
text={`${seatSummary.paidTier.total.currencySymbol}${seatSummary.paidTier.total.amountFormatted}`}
/>
</LineItems.Group>
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 | ⚡ Quick win

Handle unlimited paid tiers without quantity×rate text

The seats description always renders "{used} × {feePerBlock}". For unlimited paid tiers (paidTier.quantity === null), this is incorrect/misleading and conflicts with the intended “show tier total for unlimited tiers” behavior.

Proposed fix
         {seatSummary && (
           <LineItems.Group variant='tertiary'>
             <LineItems.Title
               title={localizationKeys('billing.seats')}
-              description={`${seatSummary.used} ${seatSummary.used === 1 ? 'seat' : 'seats'}${
-                seatSummary.included > 0 ? ` (${seatSummary.included} included)` : ''
-              } × ${seatSummary.paidTier.feePerBlock.currencySymbol}${seatSummary.paidTier.feePerBlock.amountFormatted}`}
+              description={
+                seatSummary.paidTier.quantity === null
+                  ? undefined
+                  : `${seatSummary.used} ${seatSummary.used === 1 ? 'seat' : 'seats'}${
+                      seatSummary.included > 0 ? ` (${seatSummary.included} included)` : ''
+                    } × ${seatSummary.paidTier.feePerBlock.currencySymbol}${seatSummary.paidTier.feePerBlock.amountFormatted}`
+              }
             />
             <LineItems.Description
               text={`${seatSummary.paidTier.total.currencySymbol}${seatSummary.paidTier.total.amountFormatted}`}
             />
           </LineItems.Group>
         )}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx` around
lines 232 - 243, The seats description currently always renders a quantity×rate
string; update the JSX in the PaymentAttemptPage component so that when
seatSummary.paidTier.quantity === null (an unlimited paid tier) you do not
render the "× {feePerBlock}" piece and instead only show the tier total,
otherwise keep the existing "{used} × {feePerBlock}" behavior; specifically
adjust the LineItems.Title description expression (using seatSummary,
seatSummary.paidTier.quantity, seatSummary.paidTier.feePerBlock and
seatSummary.paidTier.total) to branch on paidTier.quantity and produce the
appropriate string for unlimited vs. limited tiers.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 12, 2026

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8527

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8527

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8527

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8527

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@8527

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8527

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8527

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8527

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8527

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8527

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8527

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8527

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8527

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8527

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8527

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8527

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8527

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8527

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8527

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8527

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8527

commit: 454faa6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant