0797f8f99c
Closes out the design pass with the missing piece: a real client-side
mock-API pipeline so the write-path CTAs the design shows (invite a
teammate, run a scan, kick off a workflow test, request reactivation)
actually do something visible without a backend.
* `public/mockServiceWorker.js` — generated by `pnpm exec msw init`.
* `src/mocks/handlers.ts` — POST handlers for `/api/team/invites`,
`/api/scans`, `/api/workflows/:id/test`, `/api/billing/reactivate`.
Each returns the design's mono status-code header
(`201 · invite.created`, `202 · scan.queued`, etc.) so the toast
surface reads identical to the handoff. A `x-bp-tenant-status` hint
header lets the same handler respond 402 (frozen) or 410 (archived)
without needing a real session.
* `src/mocks/browser.ts` — thin `setupWorker(...handlers)` wrapper,
imported lazily so prod bundles don't pull MSW.
* `src/components/portal/MockWorker.tsx` — client component that boots
the worker only when `window.__BP_MOCK_API__` is true (set by
`[slug]/layout` when `BP_DEV_FIXTURE` is on the server). Real Auth.js
builds skip the worker entirely.
* `src/components/portal/ToastHost.tsx` — global bottom-right toast
queue, mounted in `[slug]/layout`. Emits via a custom event so any
client component can call `toast({ msg, code })` without prop-drilling.
* `src/components/portal/InviteButton.tsx` — first live write affordance.
Modal with email + role-segmented buttons, POSTs to `/api/team/invites`
with the tenant-status hint header, surfaces 201/402/410 differently.
Wired into the Team page.
* `src/middleware.ts` — added `mockServiceWorker.js` to the matcher
exclusion list so the host-rewrite doesn't 404 the worker script.
Verified end-to-end via Playwright: SW registers at the root scope,
click Invite member → fill email → Send invitation → MSW intercepts →
toast "Invitation sent · 201 · invite.created" → modal closes.
This closes the last open M10.2 task. Branch is ready to review/merge.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
52 lines
1.3 KiB
JSON
52 lines
1.3 KiB
JSON
{
|
|
"name": "@breakpilot/portal",
|
|
"version": "0.0.0",
|
|
"private": true,
|
|
"description": "Customer-facing portal + platform-staff backstage. Next.js + Auth.js v5.",
|
|
"license": "UNLICENSED",
|
|
"engines": {
|
|
"node": ">=20",
|
|
"pnpm": ">=9"
|
|
},
|
|
"scripts": {
|
|
"dev": "next dev --port 3000",
|
|
"build": "next build",
|
|
"start": "next start --port 3000",
|
|
"lint": "eslint . --max-warnings 0",
|
|
"typecheck": "tsc --noEmit",
|
|
"test": "vitest run --coverage",
|
|
"e2e": "playwright test",
|
|
"e2e:install": "playwright install --with-deps chromium"
|
|
},
|
|
"dependencies": {
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"geist": "^1.7.2",
|
|
"lucide-react": "^1.17.0",
|
|
"next": "16.2.6",
|
|
"next-auth": "5.0.0-beta.25",
|
|
"react": "19.0.0",
|
|
"react-dom": "19.0.0",
|
|
"tailwind-merge": "^3.6.0"
|
|
},
|
|
"devDependencies": {
|
|
"@playwright/test": "^1.60.0",
|
|
"@tailwindcss/postcss": "^4.3.0",
|
|
"@types/node": "20.16.10",
|
|
"@types/react": "19.0.1",
|
|
"@types/react-dom": "19.0.1",
|
|
"@vitest/coverage-v8": "2.1.8",
|
|
"eslint": "9.15.0",
|
|
"eslint-config-next": "16.2.6",
|
|
"msw": "^2.14.6",
|
|
"postcss": "^8.5.15",
|
|
"tailwindcss": "^4.3.0",
|
|
"typescript": "5.7.2",
|
|
"vitest": "2.1.8"
|
|
},
|
|
"msw": {
|
|
"workerDirectory": [
|
|
"public"
|
|
]
|
|
}
|
|
} |