Phase 2: API client, typed hooks, live probe
- Add api:types script (openapi-typescript against live FastAPI) - Generate src/lib/api/types.ts (2972 lines, 55 paths, 16 schemas) - lib/api/client.ts: typed apiRequest + ApiError + makeQueryClient (staleTime 5s, no refetchOnWindowFocus to preserve editor state) - lib/providers.tsx: QueryClientProvider client component, useState singleton so App Router re-renders don't dump the cache - lib/api/cases.ts: Case type + casesKeys + useCases hook (pragmatic hand-typed Case pending backend response-model annotations) - layout.tsx: wrap children with <Providers> - Smoke test: CasesLiveProbe component on home page hitting live FastAPI via /api/cases rewrite proxy Phase 2 deliverable check: useCases() returns typed Case[] from the production FastAPI through the Next.js proxy. End-to-end wiring proven. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
54
web-ui/src/lib/api/cases.ts
Normal file
54
web-ui/src/lib/api/cases.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Cases domain hooks.
|
||||
*
|
||||
* Note on types: the FastAPI `/api/cases` endpoint doesn't declare a response
|
||||
* model, so openapi-typescript emits `unknown` for its payload. Until the
|
||||
* backend is annotated (see out-of-scope in the rewrite plan), we maintain a
|
||||
* small local type that matches what the running API returns today. Any drift
|
||||
* surfaces as a runtime TypeScript error the first time a property is touched.
|
||||
*/
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { apiRequest } from "./client";
|
||||
|
||||
export type CaseStatus =
|
||||
| "new"
|
||||
| "uploading"
|
||||
| "processing"
|
||||
| "documents_ready"
|
||||
| "outcome_set"
|
||||
| "brainstorming"
|
||||
| "direction_approved"
|
||||
| "drafting"
|
||||
| "qa_review"
|
||||
| "drafted"
|
||||
| "exported"
|
||||
| "reviewed"
|
||||
| "final";
|
||||
|
||||
export type Case = {
|
||||
case_number: string;
|
||||
title: string;
|
||||
status: CaseStatus;
|
||||
subject?: string | null;
|
||||
expected_outcome?: string | null;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
};
|
||||
|
||||
export const casesKeys = {
|
||||
all: ["cases"] as const,
|
||||
list: (detail: boolean) => [...casesKeys.all, "list", { detail }] as const,
|
||||
detail: (caseNumber: string) =>
|
||||
[...casesKeys.all, "detail", caseNumber] as const,
|
||||
};
|
||||
|
||||
export function useCases(detail = false) {
|
||||
return useQuery({
|
||||
queryKey: casesKeys.list(detail),
|
||||
queryFn: ({ signal }) =>
|
||||
apiRequest<Case[]>(`/api/cases${detail ? "?detail=true" : ""}`, {
|
||||
signal,
|
||||
}),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user