diff --git a/web-ui/src/components/cases/documents-panel.tsx b/web-ui/src/components/cases/documents-panel.tsx index 3c53f57..6bda427 100644 --- a/web-ui/src/components/cases/documents-panel.tsx +++ b/web-ui/src/components/cases/documents-panel.tsx @@ -107,8 +107,10 @@ function DocumentPreviewDialog({ useEffect(() => { if (!open) { + /* eslint-disable react-hooks/set-state-in-effect -- reset on close */ setText(null); setError(null); + /* eslint-enable react-hooks/set-state-in-effect */ return; } let cancelled = false; diff --git a/web-ui/src/components/cases/legal-arguments-panel.tsx b/web-ui/src/components/cases/legal-arguments-panel.tsx index bb591a9..5783d76 100644 --- a/web-ui/src/components/cases/legal-arguments-panel.tsx +++ b/web-ui/src/components/cases/legal-arguments-panel.tsx @@ -203,7 +203,7 @@ export function LegalArgumentsPanel({ caseNumber }: LegalArgumentsPanelProps) {

) : !data?.total ? (

- אין טיעונים מאוגדים עדיין. לחץ "חשב טיעונים" כדי להריץ את ה-aggregator. + אין טיעונים מאוגדים עדיין. לחץ “חשב טיעונים” כדי להריץ את ה-aggregator.

) : (
diff --git a/web-ui/src/components/compose/chair-editor.tsx b/web-ui/src/components/compose/chair-editor.tsx index c122796..61cc86d 100644 --- a/web-ui/src/components/compose/chair-editor.tsx +++ b/web-ui/src/components/compose/chair-editor.tsx @@ -34,6 +34,7 @@ export function ChairEditor({ /* Reset when the upstream analysis refetches (e.g. after initial load) */ useEffect(() => { + // eslint-disable-next-line react-hooks/set-state-in-effect -- sync from server setValue(initialValue); lastSaved.current = initialValue; }, [initialValue]); diff --git a/web-ui/src/components/methodology/content-checklists-panel.tsx b/web-ui/src/components/methodology/content-checklists-panel.tsx index 6e3970e..bbd945d 100644 --- a/web-ui/src/components/methodology/content-checklists-panel.tsx +++ b/web-ui/src/components/methodology/content-checklists-panel.tsx @@ -49,6 +49,7 @@ export function ContentChecklistsPanel() { useEffect(() => { if (!data?.items) return; + // eslint-disable-next-line react-hooks/set-state-in-effect -- sync from server setItems( CHECKLIST_ORDER .filter((k) => k in data.items) diff --git a/web-ui/src/components/methodology/discussion-rules-panel.tsx b/web-ui/src/components/methodology/discussion-rules-panel.tsx index e736837..e1daf76 100644 --- a/web-ui/src/components/methodology/discussion-rules-panel.tsx +++ b/web-ui/src/components/methodology/discussion-rules-panel.tsx @@ -40,6 +40,7 @@ export function DiscussionRulesPanel() { useEffect(() => { if (!data?.items) return; const order = ["universal", "rejection", "partial_acceptance", "full_acceptance", "betterment_levy"]; + // eslint-disable-next-line react-hooks/set-state-in-effect -- sync from server setSections( order .filter((k) => k in data.items) diff --git a/web-ui/src/components/methodology/golden-ratios-panel.tsx b/web-ui/src/components/methodology/golden-ratios-panel.tsx index af1f214..767dd43 100644 --- a/web-ui/src/components/methodology/golden-ratios-panel.tsx +++ b/web-ui/src/components/methodology/golden-ratios-panel.tsx @@ -46,6 +46,7 @@ export function GoldenRatiosPanel() { // Sync from server useEffect(() => { if (!data?.items) return; + // eslint-disable-next-line react-hooks/set-state-in-effect -- sync from server setCards( Object.entries(data.items).map(([key, item]) => ({ key, diff --git a/web-ui/src/components/precedents/halacha-review-panel.tsx b/web-ui/src/components/precedents/halacha-review-panel.tsx index 302b27b..fcd6b3e 100644 --- a/web-ui/src/components/precedents/halacha-review-panel.tsx +++ b/web-ui/src/components/precedents/halacha-review-panel.tsx @@ -474,7 +474,6 @@ function PendingPanel() { useEffect(() => { if (focusedId === null) return; if (visibleItems.some((h) => h.id === focusedId)) return; - // eslint-disable-next-line react-hooks/set-state-in-effect setFocusedId(visibleItems[0]?.id ?? null); }, [focusedId, visibleItems]); diff --git a/web-ui/src/components/precedents/precedent-edit-sheet.tsx b/web-ui/src/components/precedents/precedent-edit-sheet.tsx index 440e1e5..8460850 100644 --- a/web-ui/src/components/precedents/precedent-edit-sheet.tsx +++ b/web-ui/src/components/precedents/precedent-edit-sheet.tsx @@ -239,7 +239,7 @@ export function PrecedentEditSheet({ caseLawId, onOpenChange }: Props) {
- + setForm({ ...form, chair_name: e.target.value })} placeholder="" /> diff --git a/web-ui/src/components/precedents/precedent-upload-sheet.tsx b/web-ui/src/components/precedents/precedent-upload-sheet.tsx index 1b35191..3329767 100644 --- a/web-ui/src/components/precedents/precedent-upload-sheet.tsx +++ b/web-ui/src/components/precedents/precedent-upload-sheet.tsx @@ -75,15 +75,11 @@ export function PrecedentUploadSheet({ open, onOpenChange }: Props) { useEffect(() => { if (open) return; - // eslint-disable-next-line react-hooks/set-state-in-effect + // eslint-disable-next-line react-hooks/set-state-in-effect -- reset form on close setFile(null); setCitation(""); setCaseName(""); setCourt(""); - // eslint-disable-next-line react-hooks/set-state-in-effect setDecisionDate(""); setSourceType(""); setPrecedentLevel(""); - // eslint-disable-next-line react-hooks/set-state-in-effect setPracticeArea(""); setAppealSubtype(""); setSubjectTags(""); - // eslint-disable-next-line react-hooks/set-state-in-effect setHeadnote(""); setIsBinding(true); setTaskId(null); setConflict(null); - // eslint-disable-next-line react-hooks/set-state-in-effect setChairName(""); setDistrict(""); setCaseNumber(""); }, [open]); diff --git a/web-ui/src/components/training/subject-donut.tsx b/web-ui/src/components/training/subject-donut.tsx index 48f961c..4ec4d44 100644 --- a/web-ui/src/components/training/subject-donut.tsx +++ b/web-ui/src/components/training/subject-donut.tsx @@ -25,11 +25,12 @@ export function SubjectDonut({ segments: Array<{ label: string; count: number }>; total: number; }) { - let pct = 0; + // Prefix sums without a mutable outer accumulator (React Compiler rejects + // reassigning a let after render). segments is tiny, so O(n²) is fine. const parts = segments.map((s, i) => { - const start = total === 0 ? 0 : (pct / total) * 360; - pct += s.count; - const end = total === 0 ? 360 : (pct / total) * 360; + const before = segments.slice(0, i).reduce((acc, x) => acc + x.count, 0); + const start = total === 0 ? 0 : (before / total) * 360; + const end = total === 0 ? 360 : ((before + s.count) / total) * 360; return { ...s, start, end, color: DONUT_COLORS[i % DONUT_COLORS.length] }; }); diff --git a/web-ui/src/lib/api/documents.ts b/web-ui/src/lib/api/documents.ts index c76264f..a734433 100644 --- a/web-ui/src/lib/api/documents.ts +++ b/web-ui/src/lib/api/documents.ts @@ -217,6 +217,7 @@ export function useProgress(taskId: string | null, caseNumber?: string) { useEffect(() => { if (!taskId) return; + // eslint-disable-next-line react-hooks/set-state-in-effect -- reset on taskId change setEvent(null); /* Self-heal fallback: if no SSE message arrives within 10s — usually