/** * Chair feedback hooks — recording and managing Dafna's feedback on drafts. */ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "./client"; export type FeedbackCategory = | "missing_content" | "wrong_tone" | "wrong_structure" | "factual_error" | "style" | "other"; export type ChairFeedback = { id: string; case_id: string | null; case_number: string; block_id: string; category: FeedbackCategory; feedback_text: string; lesson_extracted: string; resolved: boolean; applied_to: string[]; created_at: string | null; }; export type CreateFeedbackInput = { case_number?: string; block_id?: string; feedback_text: string; category?: FeedbackCategory; lesson_extracted?: string; }; const feedbackKeys = { all: ["feedback"] as const, list: (filters: { category?: string; unresolved_only?: boolean }) => [...feedbackKeys.all, "list", filters] as const, }; export function useFeedbackList(filters: { category?: string; unresolved_only?: boolean; } = {}) { const params = new URLSearchParams(); if (filters.category) params.set("category", filters.category); if (filters.unresolved_only) params.set("unresolved_only", "true"); const qs = params.toString(); return useQuery({ queryKey: feedbackKeys.list(filters), queryFn: ({ signal }) => apiRequest(`/api/feedback${qs ? `?${qs}` : ""}`, { signal }), }); } /** Feedback filtered by case number */ export function useCaseFeedback(caseNumber: string | undefined) { const params = caseNumber ? `?case_number=${caseNumber}` : ""; return useQuery({ queryKey: [...feedbackKeys.all, "case", caseNumber ?? ""] as const, queryFn: ({ signal }) => apiRequest(`/api/feedback${params}`, { signal }), enabled: Boolean(caseNumber), staleTime: 5_000, refetchInterval: 5_000, }); } export function useCreateFeedback() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreateFeedbackInput) => apiRequest<{ id: string; status: string }>("/api/feedback/json", { method: "POST", body: data, }), onSuccess: () => { qc.invalidateQueries({ queryKey: feedbackKeys.all }); }, }); } export function useResolveFeedback() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ feedbackId, applied_to, }: { feedbackId: string; applied_to: string[]; }) => apiRequest<{ status: string }>( `/api/feedback/${feedbackId}/resolve`, { method: "PATCH", body: { applied_to } }, ), onSuccess: () => { qc.invalidateQueries({ queryKey: feedbackKeys.all }); }, }); } /** Hebrew labels for feedback categories */ export const CATEGORY_LABELS: Record = { missing_content: "תוכן חסר", wrong_tone: "טון שגוי", wrong_structure: "מבנה שגוי", factual_error: "שגיאה עובדתית", style: "סגנון", other: "אחר", }; /** Tailwind color classes per category */ export const CATEGORY_COLORS: Record = { missing_content: "bg-amber-100 text-amber-800 border-amber-200", wrong_tone: "bg-purple-100 text-purple-800 border-purple-200", wrong_structure: "bg-blue-100 text-blue-800 border-blue-200", factual_error: "bg-red-100 text-red-800 border-red-200", style: "bg-emerald-100 text-emerald-800 border-emerald-200", other: "bg-gray-100 text-gray-800 border-gray-200", }; /** Block ID labels */ export const BLOCK_LABELS: Record = { "block-he": "ה — פתיחה", "block-vav": "ו — רקע עובדתי", "block-zayin": "ז — טענות הצדדים", "block-chet": "ח — הליכים", "block-tet": "ט — תכניות חלות", "block-yod": "י — דיון והכרעה", "block-yod-alef": "יא — סיכום", };