import { useCallback, useLayoutEffect, useState } from "react"; export interface FlowRefs { items: Map; termsheets: Map; } export interface FlowDiagramProps { flowEl: HTMLDivElement | null; refs: FlowRefs; redrawKey?: string; // وقتی داده‌ی quote عوض شد (پذیرش/رسید/ویرایش) خطوط دوباره رسم شوند } interface PathSpec { d: string; accepted: boolean; } // خطوط اتصال SVG بین جعبه‌های اقلام و ترم‌شیت‌ها — موقعیت جعبه‌ها با // getBoundingClientRect خوانده می‌شود و با ResizeObserver در جریان می‌ماند. // خاکستری = باز، آبی = جفت پذیرفته‌شده‌ی دقیق. export function FlowDiagram({ flowEl, refs, redrawKey = "" }: FlowDiagramProps) { const [paths, setPaths] = useState([]); const draw = useCallback(() => { if (!flowEl) return; const crect = flowEl.getBoundingClientRect(); if (!crect.width) return; const out: PathSpec[] = []; refs.items.forEach((item) => { const ir = item.getBoundingClientRect(); const x1 = ir.left - crect.left; // لبه‌ی چپ جعبه‌ی قلم (رو به فاصله) const y1 = ir.top + ir.height / 2 - crect.top; const isRejected = item.classList.contains("rejected"); const acceptedTsId = item.dataset.acceptedTs || ""; const tsIds = (item.dataset.tsIds || "").split(",").filter(Boolean); tsIds.forEach((tsId) => { const t = refs.termsheets.get(tsId); if (!t) return; const tr = t.getBoundingClientRect(); const x2 = tr.right - crect.left; // لبه‌ی راست جعبه‌ی termsheet const y2 = tr.top + tr.height / 2 - crect.top; const cx = (x1 + x2) / 2; // آبی فقط برای جفت دقیقی که قلم پذیرفته — بقیه خاکستری const accepted = !isRejected && acceptedTsId === tsId; out.push({ d: `M ${x1} ${y1} C ${cx} ${y1}, ${cx} ${y2}, ${x2} ${y2}`, accepted, }); }); }); setPaths(out); }, [flowEl, refs, redrawKey]); useLayoutEffect(() => { draw(); if (!flowEl) return; const ro = new ResizeObserver(draw); ro.observe(flowEl); window.addEventListener("resize", draw); if (typeof document !== "undefined" && document.fonts && document.fonts.ready) { void document.fonts.ready.then(draw); } return () => { ro.disconnect(); window.removeEventListener("resize", draw); }; }, [draw, flowEl]); return ( ); }