From 2b1fb18dfda9410a9086b11b3f0136de89c20a39 Mon Sep 17 00:00:00 2001 From: Chaim Date: Wed, 17 Jun 2026 11:32:32 +0000 Subject: [PATCH] =?UTF-8?q?feat(plans):=20=D7=9B=D7=A4=D7=AA=D7=95=D7=A8?= =?UTF-8?q?=20"=D7=9E=D7=A9=D7=95=D7=9A=20=D7=9E-=D7=9E=D7=A0=D7=94=D7=9C-?= =?UTF-8?q?=D7=94=D7=AA=D7=9B=D7=A0=D7=95=D7=9F"=20=D7=91=D7=98=D7=95?= =?UTF-8?q?=D7=A4=D7=A1-=D7=94=D7=AA=D7=9B=D7=A0=D7=99=D7=AA=20(Phase=20C?= =?UTF-8?q?=20=D7=98=D7=A8=D7=99=D7=92=D7=A8=201)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit טריגר 1 הידני: בטופס PlanForm, כפתור "משוך מ-מנהל-התכנון" — היו"ר מקליד מספר-תכנית, לוחץ, והשדות (שם/תאריך-רשומות/י"פ/סוג/ייעוד) מתמלאים מ-mavat דרך POST /api/plans/fetch (#292). היו"ר בודק ושומר — שער-היו"ר נשמר (שום שמירה אוטומטית). - plans.ts: useFetchPlan + PlanFetchResult. - PlanForm: כפתור עם spinner (~דקה, דפדפן חי), מילוי-שדות (מחליף בערך-mavat היכן שקיים, שומר ערך-יו"ר היכן ש-mavat ריק), קישור-מקור "מקור: מנהל-התכנון" בתצוגה-המקדימה (פרובננס INV-AH). עבר שער-עיצוב (מוקאפ 22-plans-review מאושר). ההוק ידני (לא תלוי types שנוצרים). tsc ✅ lint ✅ (0 errors). INV-AH: source_url מוצג; שדה-חסר ריק לא מומצא. G10: מילוי-טופס בלבד, שמירה דרך plan_upsert הקיים. G2: צורך את /api/plans/fetch (#292). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../precedents/plans-review-panel.tsx | 66 ++++++++++++++++++- web-ui/src/lib/api/plans.ts | 26 ++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) 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 && ( + + מקור: מנהל-התכנון + + )}