feat(auth): disable write affordances for viewer role

Re-apply f91d7b3 manually against current Upload.tsx / Inbox.tsx /
Reconciliation.tsx since main's UI text diverged from the original
cherry-pick (Release to 'parse' span, mono uppercase tracking, etc.).
The write affordances are now wrapped in <RoleGate allow={admin,user}>:

  - Upload.tsx: dropzone + Parse/Clear buttons
  - Inbox.tsx: rejected / payer_rejected / candidates BulkBars
  - Reconciliation.tsx: 'Match selected' button

Test fixtures stub useAuth to return an admin user so RoleGate lets
the BulkBars / Match button render synchronously on first paint —
the tests don't need a full AuthProvider + /api/auth/me probe.
This commit is contained in:
Nora
2026-06-22 15:54:38 -06:00
parent a25504bd3a
commit 35e0f5a422
5 changed files with 237 additions and 150 deletions
+21
View File
@@ -8,6 +8,27 @@ import Inbox from "./Inbox";
import * as inboxApi from "@/lib/inbox-api";
import * as downloadModule from "@/lib/download";
// The Inbox's write-affordance BulkBars (resubmit / acknowledge /
// dismiss) are wrapped in RoleGate, which reads the auth context to
// decide whether the current user has write permission. We don't want
// the tests to spin up the full AuthProvider + /api/auth/me probe —
// instead we stub useAuth to return an admin user so RoleGate renders
// the BulkBars synchronously on first render.
vi.mock("@/auth/useAuth", () => ({
useAuth: () => ({
status: "authenticated" as const,
user: {
id: "test-admin",
username: "test-admin",
role: "admin" as const,
created_at: "2026-01-01T00:00:00Z",
},
login: vi.fn(),
logout: vi.fn(),
refresh: vi.fn(),
}),
}));
// SP21 Phase 4 Task 4.4: Inbox now uses `useNavigate` (for unmatched
// claim drilldown to /claims?claim=ID), so the render harness needs
// a Router context. We use a fresh QueryClient per test so the