stack/apps/dashboard
BilalG1 0532a18c36
fix(dashboard): wrap "Block new purchases" toggle in a Card (#1364)
## Summary

The **Block new purchases** toggle on the Payments → Settings page was
visually out of place: it rendered as a bare `SettingSwitch` outside the
`max-w-3xl` settings column, while every neighboring setting (Stripe
Connection, Test Mode, Payment Methods, Platform-Managed Methods) was a
full-width `Card`.

This PR wraps it in a `Card` that matches the existing `TestModeToggle`
pattern so it inherits the same width constraint, border, padding,
title/description structure, and state-colored icon badge.

**File changed:**
[`apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/payments/settings/page-client.tsx`](https://github.com/stack-auth/stack-auth/blob/fix/payments-block-new-purchases-card/apps/dashboard/src/app/(main)/(protected)/projects/%5BprojectId%5D/payments/settings/page-client.tsx)

## What was wrong

Two concrete mismatches with the rest of the page:

1. **Wrong container.** The `SettingSwitch` was a direct child of
`<PageLayout>` rather than the `<div className="space-y-6 max-w-3xl">`
column that wraps the other settings — so it stretched to the full page
width instead of the 3xl column and broke the vertical rhythm (no
consistent `space-y-6` gap from the card above).
2. **Wrong style primitive.** It used the bare `SettingSwitch` row
component instead of a `Card` +
`CardHeader`/`CardTitle`/`CardDescription`/`CardContent` structure — so
there was no border, no heading hierarchy, and no state-colored icon
badge, which every other setting on the page has.

## Fix

- Moved the block inside the `space-y-6 max-w-3xl` column so it's
constrained and spaced like its siblings.
- Replaced the `SettingSwitch` with a `Card` mirroring `TestModeToggle`:
- `CardHeader` with `CardTitle` (\"Block New Purchases\") and
`CardDescription` (\"Stops new checkouts while keeping existing
subscriptions active.\").
- `CardContent` with an icon badge (`ProhibitIcon`) that turns red when
blocking is active, plus a short \"Block new purchases\" label and the
`Switch`.
- Copy is intentionally minimal: one title, one sentence of description,
one label next to the switch. No two-state narration.

## Visual comparison

### Pixel diff (changed pixels tinted red over the after image)
4.7% of pixels changed, all concentrated in the bottom of the settings
column — everything else is pixel-identical, confirming the fix is
scoped.

![pixel
diff](https://gist.githubusercontent.com/BilalG1/faacb21aea28bc6acae0f527f232c38c/raw/compare_pixel_diff.png)

### Cropped before/after toggle (zoomed to the changed region)
Full-viewport comparisons are noisy when the delta is a single component
at the bottom. This one is cropped to the changed bbox so the card fix
is the whole frame — 1s before, 1s after, looped.

![crop
toggle](https://gist.githubusercontent.com/BilalG1/faacb21aea28bc6acae0f527f232c38c/raw/compare_crop_toggle.gif)

### Wipe reveal (before on the left, after swept in from the left)
A vertical red sweeps across the full page, revealing the after state
over the before state. Useful for spotting any unintended drift
elsewhere on the page (there is none).


![wipe](https://gist.githubusercontent.com/BilalG1/faacb21aea28bc6acae0f527f232c38c/raw/compare_wipe.gif)

## Test plan

- [ ] Open `/projects/<id>/payments/settings` in the dashboard.
- [ ] Verify \"Block New Purchases\" renders as a `Card` with the same
width as Stripe Connection / Test Mode / Payment Methods.
- [ ] Toggle the switch on — icon badge turns red, config write fires
(`payments.blockNewPurchases = true`, `pushable: true`).
- [ ] Toggle off — icon returns to muted gray, config write fires with
`false`.
- [ ] Reload the page and confirm the persisted state matches the
toggle.
- [ ] `pnpm lint` and `pnpm typecheck` pass.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Redesigned the "Block New Purchases" toggle in payment settings with a
new card-based interface and visual prohibit indicator for improved
clarity and user experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-22 17:28:09 -07:00
..
public [Changelog] Updates to US date format, adds images. (#1143) 2026-02-02 11:21:21 -06:00
scripts Custom dashboards and unified ai no playground (#1243) 2026-03-13 20:24:40 +00:00
src fix(dashboard): wrap "Block new purchases" toggle in a Card (#1364) 2026-04-22 17:28:09 -07:00
.env Local emulator base (#1233) 2026-03-10 15:15:06 -07:00
.env.development Add Mintlify docs to pnpm run dev 2026-04-06 13:47:53 -07:00
.eslintrc.cjs Config sources (#1083) 2026-01-21 18:08:35 -08:00
.gitignore Custom dashboards and unified ai no playground (#1243) 2026-03-13 20:24:40 +00:00
.npmrc Split backend and dashboard (#83) 2024-06-18 15:49:31 +02:00
components.json Split backend and dashboard (#83) 2024-06-18 15:49:31 +02:00
DESIGN-GUIDE.md Overview revamp (#1238) 2026-04-15 09:36:00 -07:00
instrumentation-client.ts Upgrade PostHog 2026-01-30 23:38:06 -08:00
LICENSE Split backend and dashboard (#83) 2024-06-18 15:49:31 +02:00
next.config.mjs dev tool indicator (#1272) 2026-04-13 17:43:03 -07:00
package.json chore: update package versions 2026-04-20 19:06:56 -07:00
postcss.config.js Split backend and dashboard (#83) 2024-06-18 15:49:31 +02:00
tailwind.config.ts Overview revamp (#1238) 2026-04-15 09:36:00 -07:00
tsconfig.json fix flaky typecheck test (#1072) 2025-12-17 12:26:12 -08:00
vitest.config.ts In-source unit tests (#429) 2025-02-14 11:47:52 -08:00