Files
twenty/packages/twenty-front/src
Félix Malfait 179ab2f066 feat(billing): clarify subscription, credits, and add-credits sections (#22126)
## What & why

Redesigns the **content** of the workspace billing settings page so the
numbers that matter are surfaced clearly. Strictly reuses existing
design-system components — no new UI primitives, no color/font changes,
same section structure. All pricing values are pulled from the pricing
config (nothing hardcoded).

## Changes

**Subscription card** (`SettingsBillingSubscriptionInfo.tsx`)
- **Seats** row shows per-seat pricing inline, e.g. `16 × $25 / seat /
mo` (interval-aware unit).
- **"Credits by period" → "Monthly credits"** (interval-aware: "Yearly
credits" on yearly plans).
- New **"Total per month"** row (→ "Total per year" on yearly) with a
helper line via the existing `Label`: `$400 seats + $2,000 credits ·
next charge <date>`. The total is computed at the billing interval, so
it equals the actual next charge.
- **"Switch to Yearly · save 20%"** — discount computed from real
monthly vs. yearly config prices (only appended when > 0).

**Credit usage card** (`SettingsBillingCreditsSection.tsx`)
- Denominator stays total available (allocation + rollover); figures
shown in full (`3,856`, not `3.86k`).
- "Base Credits" → **"This month's credits"** + a **"Rolled over"** row
rendered as `+1,856`.
- Adds a blue `Info` note stating the rollover rule: *"Unused credits
roll over, up to 2× your plan's credits (max 4,000)."* — verified
against the backend cap (`billing-credit-rollover.service.ts`:
`rolloverAmount = min(unused, tierQuantity)`).

**Add-credits section** (`ResourceCreditPriceSelector.tsx`)
- "Resource credits" → **"Add monthly credits"** with a description
clarifying it stacks on the plan and adjusts the bill.
- On selection, shows the resulting **new total** and **new rollover
cap** (2× the new allocation).

**Shared logic**
- New `useBillingSubscriptionCost` hook centralizes the
seats/credits/total math so the subscription card and the add-credits
selector stay consistent.
- Yearly-discount calculation lives in `useBillingWording`
(`getYearlyDiscountPercent`) next to the existing price logic.

All new figures degrade gracefully — the Total row and the add-credits
summary only render when fully computable, so trial/edge states never
show partial numbers.

## Testing

⚠️ `nx typecheck` / `lint` could **not** be run in the authoring
environment (dependency install couldn't complete due to flaky network).
The changes were reviewed manually against the generated GraphQL types
(`BillingPlanKey` = `{ENTERPRISE, PRO}`, `unitAmount: number`,
`creditAmount: Maybe<number>`, nullable
`interval`/`currentPeriodEnd`/`quantity` — all guarded) and a 4-angle
cleanup pass (reuse/simplify/efficiency/altitude). **Please let CI run
typecheck + lint to confirm.**

https://claude.ai/code/session_01GNhCHPfD1SRzAiBACXGCf7

---
_Generated by [Claude
Code](https://claude.ai/code/session_01GNhCHPfD1SRzAiBACXGCf7)_

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22126?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-25 04:13:06 +02:00
..