AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters.
feat(frontend): split switch-to-yearly dialog copy into lines + surface charged-today amount (#13099)
### Why / What / How **Why:** [SECRT-2348](https://linear.app/autogpt/issue/SECRT-2348) — the Settings → Subscription cycle-switch confirmation popup is too wordy and packs four different numbers into a single run-on sentence, so users can't quickly tell what they're being asked to pay. The ticket also asks us to show the exact prorated amount the user will be charged today when switching from monthly to yearly on Pro/Max. **What:** Rewrites the body of `SwitchCycleDialog` (monthly→yearly *and* yearly→monthly) so each fact lives on its own line, and surfaces the real charged-today number computed from the backend's `proration_credit_cents`. Before (one paragraph): > Save 15% with yearly billing. Pro is $42.50/month when billed yearly, charged as $510.00/year instead of $600.00/year monthly. You'll be charged the prorated difference immediately. After this period, your plan renews yearly at $510.00. <img width="662" height="342" alt="Screenshot 2026-05-13 at 12 58 15 PM" src="https://github.com/user-attachments/assets/b0924746-eded-4420-a828-d2642d9e72c8" /> <img width="724" height="364" alt="Screenshot 2026-05-13 at 1 00 23 PM" src="https://github.com/user-attachments/assets/bd3ff846-6741-4f1b-ab3b-078586ddff3b" /> After (four scannable lines): > Save 15% with yearly billing. > Pro yearly: $510.00/year ($42.50/month). > Charged today: $485.00 (prorated from your monthly plan). > Renews $510.00/year on May 14, 2030. **How:** - `useYourPlanCard.ts` — `getDialogBody()` now returns `string[]`. For monthly→yearly with both prices available, it builds four lines: savings %, consolidated yearly + monthly-equivalent price, exact charged-today amount, renewal line with the period-end date. For yearly→monthly it returns three lines (date of switch, new monthly price, "No charge today"). Falls back to a shorter two-line variant when prices are missing (e.g. BUSINESS tier). - Charged-today math reuses what the backend already returns: `max(0, currentYearlyCents - proration_credit_cents)`. `proration_credit_cents` is already computed server-side via `get_proration_credit_cents` and matches what Stripe credits under `proration_behavior="always_invoice"`. When the backend returns `0` (admin-granted plans / no Stripe customer), we fall back to the generic "prorated difference today" line instead of showing `$0`. - Renewal-date line uses `current_period_end` (already on `SubscriptionStatusResponse`) — no new backend fields. - `SwitchCycleDialog.tsx` — `body` prop is now `string[]`; renders each line as its own `<Text>` row with `gap-2` spacing. - Tier-upgrade and tier-downgrade dialogs are intentionally left alone — out of scope for this ticket. ### Changes 🏗️ - `useYourPlanCard.ts`: `getDialogBody()` returns `string[]`; reads `proration_credit_cents` and `current_period_end` from the subscription status response; computes savings %, monthly equivalent, net charge today, and renewal date. - `SwitchCycleDialog.tsx`: `body: string` → `body: string[]`; iterates and renders each line as a stacked `<Text>` row. - `billing-cards.test.tsx`: per-line anchored regex assertions for both directions; added `proration_credit_cents: 2500` + `current_period_end` to the Pro monthly→yearly fixture so the exact-amount path is exercised; the Max test keeps the fallback path covered. ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Pro monthly user clicks Yearly toggle → dialog title reads "Switch Pro to yearly billing?" and body shows four separate lines including "Charged today: $X.XX (prorated from your monthly plan)." - [x] Max monthly user clicks Yearly toggle → dialog title reads "Switch Max to yearly billing?" with Max pricing on its own line. - [x] Pro yearly user clicks Monthly toggle → dialog shows three lines including "No charge today." on the last line. - [x] BUSINESS user (no tier_costs) → dialog falls back to two-line generic copy (no $0 leak). - [x] Confirm flow still POSTs `billing_cycle` correctly in both directions (existing tests cover this). - [x] `pnpm test:unit` passes for `billing-cards.test.tsx`. #### For configuration changes: - [x] `.env.default` is updated or already compatible with my changes - [x] `docker-compose.yml` is updated or already compatible with my changes - [x] I have included a list of my configuration changes in the PR description (under **Changes**)
A
Abhimanyu Yadav committed
16f94ed90f1dbe910e36163bc8e76034f758d0c7
Parent: 71e582d
Committed by GitHub <noreply@github.com>
on 5/13/2026, 7:52:55 AM