import { FormEvent, MouseEvent, useState } from "react"; import { API_BASE_URL } from "../api"; import type { Language } from "../copy"; type Feedback = { reason: string; comment?: string | null; }; type ReviewRow = { id: string; source_text: string; translation: string; corrected_text: string | null; risk_tier: string; status: string; feedback: Feedback[]; }; type ReviewResponse = { items: ReviewRow[]; total: number; }; type Filters = { risk: string; flagged: boolean; low_confidence: boolean; escalated: boolean; }; const initialFilters: Filters = { risk: "", flagged: false, low_confidence: false, escalated: false, }; function reviewUrl(filters: Filters, format = "json") { const params = new URLSearchParams({ format }); if (filters.risk) { params.set("risk", filters.risk); } if (filters.flagged) { params.set("flagged", "1"); } if (filters.low_confidence) { params.set("low_confidence", "1"); } if (filters.escalated) { params.set("escalated", "1"); } return `${API_BASE_URL}/api/admin/review?${params.toString()}`; } export function AdminReview({ language = "vi" }: { language?: Language }) { const [token, setToken] = useState(""); const [filters, setFilters] = useState(initialFilters); const [rows, setRows] = useState([]); const [total, setTotal] = useState(0); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); async function loadReview(event?: FormEvent) { event?.preventDefault(); setLoading(true); setError(null); try { const response = await fetch(reviewUrl(filters), { headers: { "X-Admin-Token": token }, }); if (!response.ok) { throw new Error(`review request failed: ${response.status}`); } const payload = (await response.json()) as ReviewResponse; setRows(payload.items); setTotal(payload.total); } catch (caught) { setError(caught instanceof Error ? caught.message : "review request failed"); } finally { setLoading(false); } } async function downloadCsv(event: MouseEvent) { event.preventDefault(); setError(null); try { const response = await fetch(reviewUrl(filters, "csv"), { headers: { "X-Admin-Token": token }, }); if (!response.ok) { throw new Error(`CSV request failed: ${response.status}`); } const blob = await response.blob(); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = "carepath-review.csv"; link.click(); URL.revokeObjectURL(url); } catch (caught) { setError(caught instanceof Error ? caught.message : "CSV request failed"); } } return (
void downloadCsv(event)}> Download CSV
void loadReview(event)}>
{error ? (

{error}

) : null}

{total} turns

{rows.map((row) => ( ))}
Source Translation Correction Risk tier Status Feedback
{row.source_text} {row.translation} {row.corrected_text || ""} {row.risk_tier} {row.status} {row.feedback.map((item) => item.reason).join(", ")}
); }