mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-30 21:01:54 +08:00
## Summary Two related payments/dashboard changes: 1. **Customer page rework** (`/projects/<id>/payments/customers`) — replaces the old single-customer selector page with **one unified table** of users, teams, and custom customers, with filtering and search. Clicking a row opens a customer view that renders the **same data as the payments tab** on the user/team detail pages, plus a button to return to the list. 2. **"Create checkout" everywhere** — the existing checkout dialog is now reachable from every relevant surface (user table, team table, user/team detail payments tabs, product detail page, product-lines cards, and the customer detail view), all driven by **one shared dialog**. > ℹ️ Screenshots are from a local dev environment (test-mode banner + dev-tools rail are dev-only chrome). --- ## 1. Customers page rework A single `DataGrid` lists users + teams + custom customers (custom ones are derived from transactions, since they aren't otherwise enumerable). It uses the existing table/filter components: a **Type** filter (All / Users / Teams / Custom) and quick-search.  Filtering by type — e.g. **Custom** customers surfaced from transaction history:  Clicking a row opens a **read-only customer view** that is identical to the payments tab on the user/team detail pages (metrics, products & subscriptions, transaction history, item balances), with a **"Back to customers"** button and a **Create checkout** button:  To guarantee the view is identical, the user/team payments tabs and this page now share one generic `CustomerPaymentsSection` component keyed by `(customerType, customerId)`. --- ## 2. Create checkout everywhere (one shared dialog) The single `CreateCheckoutDialog` now supports: - **Customer pre-selected** → just choose a product (tables, detail tabs, customer detail view):  - **Locked product + customer selector** → launched from a product, the product is fixed and you pick the customer:  The customer selector reuses the existing searchable user/team tables (nested dialog):  Resulting checkout URL:  ### Entry points **Product detail page** — in the ellipsis menu:  **Product-lines** product-card menu:  **User table** row action (team table is analogous):  **User detail payments tab** (and **team detail payments tab**) get a Create-checkout button in the header:   --- ## Implementation notes - **New SDK method**: `adminApp.createCheckoutUrl({ userId | teamId | customCustomerId, productId, returnUrl? })` added to the `@hexclave/template` **server** app (interface + impl). This is what enables checkout for **custom** customers, which previously had no checkout path (the old dialog only called `customer.createCheckoutUrl(...)` on a `ServerUser`/`Team` object). Regenerate SDKs after pulling (`pnpm -w run generate-sdks`). - It lives on the server app (not client) deliberately: it targets an *arbitrary* customer, which is a server/admin capability. The backend route enforces this — for `client` auth it calls `ensureClientCanAccessCustomer(...)` ("clients can only create purchase URLs for their own user or teams they admin"). The client's safe, scoped path is the existing customer-object method `user.createCheckoutUrl()` / `team.createCheckoutUrl()`. The new method sits alongside `grantProduct`/`createItemQuantityChange`/`getItem`, which take the same `{ userId | teamId | customCustomerId }` shape. - **New shared components** under `apps/dashboard/src/components/payments/`: - `customer-selector.tsx` — `CustomerSelector`, `CustomerTypeSelect`, `SelectedCustomer`, `customerToMutationOptions` (extracted from the old customers page). - `customer-payments-section.tsx` — generic payments view; `user-payments.tsx` / `team-payments.tsx` are now thin wrappers over it. - `CreateCheckoutDialog` reworked to take a unified `customer` descriptor and the new selector / locked-product props. ## Testing - `pnpm typecheck` and `pnpm lint` pass. - Manually verified end-to-end against a seeded local project (test mode): generated real checkout URLs for a **custom** customer and a **team**, exercised every entry point above, the type filter (All/Users/Teams/Custom), search, row → detail → back, and the error states (e.g. "product already granted", "no products for this customer type"). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a unified Customers browser for payments with filter, quick search, infinite scrolling, and a customer detail view. * Enabled “Create checkout” directly from product and customer-related screens (including list/dropdown actions). * Added streamlined “customer payments” views (metrics, transactions, product/subscription info, and item balances where available). * Introduced a flexible customer picker to support user, team, and custom customers in checkout flows. * **Bug Fixes** * Improved checkout validation, dialog open/close behavior, and empty-state handling when no customer or products are available. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|---|---|---|
| .. | ||
| public | ||
| scripts | ||
| src | ||
| .env | ||
| .env.development | ||
| .eslintrc.cjs | ||
| .gitignore | ||
| .npmrc | ||
| components.json | ||
| DESIGN-GUIDE.md | ||
| instrumentation-client.ts | ||
| LICENSE | ||
| next.config.mjs | ||
| package.json | ||
| postcss.config.js | ||
| tailwind.config.ts | ||
| tsconfig.json | ||
| vitest.config.ts | ||