diff --git a/web-ui/src/components/cases/legal-arguments-panel.tsx b/web-ui/src/components/cases/legal-arguments-panel.tsx index a8aad2b..7297333 100644 --- a/web-ui/src/components/cases/legal-arguments-panel.tsx +++ b/web-ui/src/components/cases/legal-arguments-panel.tsx @@ -1,6 +1,6 @@ "use client"; -import { useMemo } from "react"; +import { useMemo, type ReactNode } from "react"; import { Accordion, AccordionContent, @@ -9,7 +9,6 @@ import { } from "@/components/ui/accordion"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; import { Popover, PopoverContent, @@ -22,6 +21,7 @@ import { PRIORITY_ORDER, useAggregateArguments, useLegalArguments, + type AggregateArgumentsResult, type LegalArgument, type LegalArgumentParty, type LegalArgumentPriority, @@ -189,97 +189,167 @@ export function LegalArgumentsPanel({ caseNumber }: LegalArgumentsPanelProps) { }, [data]); const handleAggregate = (force: boolean) => { + // Status feedback is rendered inline as a banner from `aggregate.data`; + // only hard transport/HTTP errors fall through to a toast. aggregate.mutate(force, { - onSuccess: (result) => { - switch (result.status) { - case "queued": - toast.success( - force - ? "נשלח לאנליטיקאי לחישוב מחדש. התוצאה תופיע תוך כמה דקות — רענן את הדף." - : "נשלח לאנליטיקאי. החישוב רץ ברקע; התוצאה תופיע תוך כמה דקות — רענן את הדף.", - ); - break; - case "no_claims": - case "exists": - toast.info(result.message); - break; - case "skipped": - toast.warning( - `לא ניתן להפעיל אוטומטית (${result.reason}). הרץ ידנית מ-Claude Code: mcp__legal-ai__aggregate_claims_to_arguments`, - ); - break; - default: - toast.success("הבקשה נשלחה."); - } - }, onError: (e) => toast.error(`שגיאה: ${(e as Error).message}`), }); }; return ( - - -
-
-

- טיעונים משפטיים -

-

- טיעונים מאוגדים מתוך הפרופוזיציות הגולמיות, מקובצים לפי צד וקדימות. -

-
-
- - -
+
+
+
+

טיעונים משפטיים

+

+ טיעונים מאוגדים מתוך הטענות הגולמיות, מקובצים לפי צד וקדימות. החישוב + רץ אצל המנתח המשפטי ומדווח בחזרה. +

+
+ + +
+
- {isPending ? ( -
- - - -
- ) : isError ? ( -

- שגיאה בטעינת טיעונים: {(error as Error).message} -

- ) : !data?.total ? ( -

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

- ) : ( -
- {parties.map((party) => ( - - ))} -
- )} - - + + + {isPending ? ( +
+ + + +
+ ) : isError ? ( +

+ שגיאה בטעינת טיעונים: {(error as Error).message} +

+ ) : !data?.total ? ( +

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

+ ) : ( +
+ {parties.map((party) => ( + + ))} +
+ )} +
+ ); +} + +const BANNER_TONE = { + info: "border-info/30 bg-info-bg", + gold: "border-gold/40 bg-gold-wash", + muted: "border-rule bg-rule-soft", + warn: "border-warn/40 bg-warn-bg", +} as const; + +const DOT_TONE = { + info: "bg-info", + gold: "bg-gold-deep", + muted: "bg-ink-light", + warn: "bg-warn", +} as const; + +const TITLE_TONE = { + info: "text-info", + gold: "text-gold-deep", + muted: "text-ink-soft", + warn: "text-warn", +} as const; + +/** + * Inline status feedback for the aggregation trigger — mirrors the approved + * Claude Design mockup (25-legal-arguments-panel). Shown only after a click; + * the four states map to the endpoint's discriminated-union result. + */ +function AggregateStatusBanner({ + result, + force, +}: { + result: AggregateArgumentsResult | undefined; + force: boolean; +}) { + if (!result) return null; + + let tone: keyof typeof BANNER_TONE; + let title: string; + let body: ReactNode; + + switch (result.status) { + case "queued": + tone = "info"; + title = "נשלח לאנליטיקאי."; + body = `${force ? "החישוב-מחדש" : "החישוב"} רץ ברקע אצל המנתח המשפטי; התוצאה תופיע תוך כמה דקות — רענן את הדף.`; + break; + case "exists": + tone = "gold"; + title = "כבר חושב."; + body = result.message; + break; + case "no_claims": + tone = "muted"; + title = "אין טענות גולמיות."; + body = result.message; + break; + case "skipped": + tone = "warn"; + title = "לא ניתן להפעיל אוטומטית"; + body = ( + <> + {` (${result.reason}). הרץ ידנית מ-Claude Code: `} + + mcp__legal-ai__aggregate_claims_to_arguments + + + ); + break; + default: + return null; + } + + return ( +
+ +

+ {title}{" "} + {body} +

+
); }