diff --git a/web-ui/src/components/precedents/plans-review-panel.tsx b/web-ui/src/components/precedents/plans-review-panel.tsx index a668f8b..e111cdd 100644 --- a/web-ui/src/components/precedents/plans-review-panel.tsx +++ b/web-ui/src/components/precedents/plans-review-panel.tsx @@ -3,6 +3,7 @@ import { useMemo, useState } from "react"; import { Check, X, Edit2, AlertTriangle, Plus, GitMerge, Save, Search, Undo2, BadgeCheck, + DownloadCloud, Loader2, ExternalLink, } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -13,7 +14,7 @@ import { Skeleton } from "@/components/ui/skeleton"; import { cn } from "@/lib/utils"; import { usePlansAll, usePlanDuplicates, useUpsertPlan, useUpdatePlan, - useReviewPlan, useMergePlans, type Plan, type PlanEdit, + useReviewPlan, useMergePlans, useFetchPlan, type Plan, type PlanEdit, } from "@/lib/api/plans"; /* Strip bidi marks (mirror of the halacha panel's cleanCitation). */ @@ -401,14 +402,47 @@ function PlanForm({ onClose: () => void; }) { const [f, setF] = useState(initial); + const [sourceUrl, setSourceUrl] = useState(""); const upsert = useUpsertPlan(); const update = useUpdatePlan(); + const fetchMavat = useFetchPlan(); const busy = upsert.isPending || update.isPending; function set(k: K, v: string) { setF((prev) => ({ ...prev, [k]: v })); } + // Pull identity + validity from the official source (mavat) into the fields. + // Fills each field mavat returns (keeps a chair value only where mavat is + // empty); the chair still reviews + saves. Slow — a real browser on the host. + async function pullFromMavat() { + const num = f.plan_number.trim(); + if (!num) { + toast.error("הקלד מספר-תכנית למשיכה"); + return; + } + try { + const r = await fetchMavat.mutateAsync(num); + setF((prev) => ({ + plan_number: r.plan_number || prev.plan_number, + display_name: r.display_name || prev.display_name, + plan_type: r.plan_type || prev.plan_type, + gazette_date: r.gazette_date || prev.gazette_date, + yalkut_number: r.yalkut_number || prev.yalkut_number, + purpose: r.purpose || prev.purpose, + })); + setSourceUrl(r.source_url || ""); + toast.success( + r.yalkut_number || r.gazette_date + ? "נמשך ממנהל-התכנון — בדוק ואשר" + : "נמצא במנהל-התכנון אך ללא תוקף מפורסם — השלם ידנית", + ); + } catch (e) { + const msg = (e as { body?: { detail?: string } })?.body?.detail; + toast.error(msg || "שגיאה במשיכה ממנהל-התכנון"); + } + } + async function save() { if (!f.plan_number.trim()) { toast.error("חובה מספר-תכנית"); @@ -455,6 +489,28 @@ function PlanForm({

{title}

{subtitle}

+ + {/* pull validity from the official source (mavat) into the fields below */} +
+ + + {fetchMavat.isPending + ? "מושך ממנהל-התכנון — עד כדקה (דפדפן חי)…" + : 'הקלד מספר-תכנית ולחץ — שם, תאריך-רשומות, מס\' ילקוט (י"פ), סוג וייעוד יימשכו מהמקור הרשמי. שדה שהמקור אינו חושף יישאר ריק — לא מומצא.'} + +
+
{field("plan_number", "מספר תכנית", 'מזהה בלבד (ללא המילה "תכנית")')} {field("display_name", "שם תצוגה")} @@ -468,6 +524,14 @@ function PlanForm({ תצוגה מקדימה — כך ייכתב בבלוק ט: {previewCitation(f)} + {sourceUrl && ( + + מקור: מנהל-התכנון + + )}