feat: update LangGraph flow diagram to reflect new reschedule flow
Replace the old ASAP/next-week/Mon-Tue-Wed/morning-afternoon subtree with the new direct datetime flow: - MSG 1: AI self-introduction (sent first via REST API) - MSG 2: "When would you like to reschedule?" (intent response) - Patient gives date → day-open check (office hours) with fail loop - AI asks time → hours check (within AM/PM session) with fail loop - AI confirms: "Just to confirm — [date at time]?" - Patient YES/NO → slot availability check with fail loop - DB: appointment moved, AI badge shown on schedule grid - Patient thanks → closing message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,219 +37,201 @@ function previewTemplate(text: string, officeName: string) {
|
||||
// ─── LangGraph flow diagram (SVG) ─────────────────────────────────────────────
|
||||
|
||||
function LangGraphFlow() {
|
||||
const W = 620;
|
||||
const cx = W / 2; // 310
|
||||
const nodeW = 200;
|
||||
const nx = cx - nodeW / 2; // 210
|
||||
const W = 640;
|
||||
const cx = 320; // top-section center
|
||||
const nW = 210;
|
||||
const nx = cx - nW / 2;
|
||||
|
||||
// sequential node y positions & heights
|
||||
const n1y = 16, n1h = 58;
|
||||
const n2y = 116, n2h = 58;
|
||||
const n3y = 216, n3h = 78;
|
||||
// ── Top sequence ──────────────────────────────────────────────────────────
|
||||
const n1y = 16, n1h = 52;
|
||||
const n2y = 84, n2h = 52;
|
||||
const n3y = 152, n3h = 76; // AI classifies + sends MSG 1
|
||||
|
||||
// fork geometry
|
||||
const forkHY = n3y + n3h + 22; // 316
|
||||
const lcx = 150, rcx = 470; // branch centers (balanced around 310)
|
||||
const forkHY = n3y + n3h + 22; // 250
|
||||
|
||||
// main branch nodes
|
||||
const branchY = forkHY + 58; // 374
|
||||
const branchW = 220;
|
||||
const branchH = 88;
|
||||
const branchBottom = branchY + branchH; // 462
|
||||
// Branch centers
|
||||
const lcx = 138; // YES (left)
|
||||
const rcx = 490; // NO (right)
|
||||
|
||||
// ── Rescheduling sub-tree (below NO/left branch at lcx=150) ──────────────
|
||||
const rsForkHY = branchBottom + 28; // 490 patient says YES/NO to reschedule
|
||||
const rsYesCx = 90;
|
||||
const rsNoCx = 215;
|
||||
const rsNodeY = rsForkHY + 32; // 522
|
||||
const rsNodeH = 54;
|
||||
// ── YES branch ────────────────────────────────────────────────────────────
|
||||
const yes1y = forkHY + 50; // 300
|
||||
const yes1h = 78;
|
||||
const yes2y = yes1y + yes1h + 14; // 392
|
||||
const yes2h = 52;
|
||||
|
||||
// ASAP-or-next-week fork (below rsYesCx=90)
|
||||
const prefForkHY = rsNodeY + rsNodeH + 22; // 598
|
||||
const asakCx = 48;
|
||||
const nwkCx = 138;
|
||||
const prefNodeY = prefForkHY + 32; // 630
|
||||
const prefNodeH = 62;
|
||||
// ── NO branch – step-by-step ──────────────────────────────────────────────
|
||||
const noW = 226;
|
||||
const no1y = forkHY + 50; // 300 — "When would you like to reschedule?"
|
||||
const no1h = 62;
|
||||
const no2y = no1y + no1h + 14; // 376 — patient gives date + day-open check
|
||||
const no2h = 80;
|
||||
const no3y = no2y + no2h + 14; // 470 — "What time on [date]?"
|
||||
const no3h = 62;
|
||||
const no4y = no3y + no3h + 14; // 546 — patient gives time + hours check
|
||||
const no4h = 80;
|
||||
const no5y = no4y + no4h + 14; // 640 — "Just to confirm — [date at time]?"
|
||||
const no5h = 62;
|
||||
const no6y = no5y + no5h + 14; // 716 — patient confirms YES / NO
|
||||
const no6h = 72;
|
||||
const no7y = no6y + no6h + 14; // 802 — slot availability check
|
||||
const no7h = 80;
|
||||
const no8y = no7y + no7h + 14; // 896 — DB move + AI badge
|
||||
const no8h = 78;
|
||||
const no9y = no8y + no8h + 14; // 988 — patient thanks / closing
|
||||
const no9h = 54;
|
||||
|
||||
const totalH = prefNodeY + prefNodeH + 54 + 20 + 54 + 22; // time node + DB node + padding
|
||||
const totalH = Math.max(yes2y + yes2h, no9y + no9h) + 24;
|
||||
|
||||
// Helper: failure annotation box to the right of a check node
|
||||
const failX = rcx + noW / 2 + 8;
|
||||
const failW = 122;
|
||||
|
||||
return (
|
||||
<svg
|
||||
viewBox={`0 0 ${W} ${totalH}`}
|
||||
className="w-full max-w-xl mx-auto"
|
||||
className="w-full max-w-2xl mx-auto"
|
||||
role="img"
|
||||
aria-label="LangGraph conversation flow diagram"
|
||||
aria-label="LangGraph appointment reminder conversation flow"
|
||||
>
|
||||
<defs>
|
||||
{/* Arrowhead marker */}
|
||||
<marker
|
||||
id="ah"
|
||||
markerWidth="10" markerHeight="7"
|
||||
refX="9" refY="3.5"
|
||||
orient="auto"
|
||||
markerUnits="userSpaceOnUse"
|
||||
>
|
||||
<polygon points="0 0, 10 3.5, 0 7" fill="#9CA3AF" />
|
||||
<marker id="rg2ah" markerWidth="10" markerHeight="7"
|
||||
refX="9" refY="3.5" orient="auto" markerUnits="userSpaceOnUse">
|
||||
<polygon points="0 0,10 3.5,0 7" fill="#9CA3AF" />
|
||||
</marker>
|
||||
<marker id="rg2fail" markerWidth="8" markerHeight="6"
|
||||
refX="7" refY="3" orient="auto" markerUnits="userSpaceOnUse">
|
||||
<polygon points="0 0,8 3,0 6" fill="#EF4444" />
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
{/* ── Node 1: Office sends reminder ─────────────────────────── */}
|
||||
<rect x={nx} y={n1y} width={nodeW} height={n1h} rx={8}
|
||||
fill="#EFF6FF" stroke="#3B82F6" strokeWidth={1.5} />
|
||||
<text x={cx} y={n1y + 24} textAnchor="middle" fontSize={13}
|
||||
fontWeight="600" fill="#1D4ED8">Office sends reminder</text>
|
||||
<text x={cx} y={n1y + 42} textAnchor="middle" fontSize={10}
|
||||
fill="#93C5FD">Staff triggers the SMS</text>
|
||||
{/* ══ TOP SEQUENCE ═══════════════════════════════════════════════ */}
|
||||
|
||||
{/* Arrow 1 → 2 */}
|
||||
<line x1={cx} y1={n1y + n1h} x2={cx} y2={n2y - 2}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
{/* N1: Office sends reminder */}
|
||||
<rect x={nx} y={n1y} width={nW} height={n1h} rx={8} fill="#EFF6FF" stroke="#3B82F6" strokeWidth={1.5} />
|
||||
<text x={cx} y={n1y+22} textAnchor="middle" fontSize={13} fontWeight="600" fill="#1D4ED8">Office sends reminder SMS</text>
|
||||
<text x={cx} y={n1y+40} textAnchor="middle" fontSize={10} fill="#93C5FD">Staff triggers the batch send</text>
|
||||
<line x1={cx} y1={n1y+n1h} x2={cx} y2={n2y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* ── Node 2: Patient replies ───────────────────────────────── */}
|
||||
<rect x={nx} y={n2y} width={nodeW} height={n2h} rx={8}
|
||||
fill="#F9FAFB" stroke="#D1D5DB" strokeWidth={1.5} />
|
||||
<text x={cx} y={n2y + 24} textAnchor="middle" fontSize={13}
|
||||
fontWeight="600" fill="#374151">Patient replies</text>
|
||||
<text x={cx} y={n2y + 42} textAnchor="middle" fontSize={10}
|
||||
fill="#9CA3AF">Any message triggers the AI</text>
|
||||
{/* N2: Patient replies */}
|
||||
<rect x={nx} y={n2y} width={nW} height={n2h} rx={8} fill="#F9FAFB" stroke="#D1D5DB" strokeWidth={1.5} />
|
||||
<text x={cx} y={n2y+22} textAnchor="middle" fontSize={13} fontWeight="600" fill="#374151">Patient replies</text>
|
||||
<text x={cx} y={n2y+40} textAnchor="middle" fontSize={10} fill="#9CA3AF">Any SMS triggers the AI</text>
|
||||
<line x1={cx} y1={n2y+n2h} x2={cx} y2={n3y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* Arrow 2 → 3 */}
|
||||
<line x1={cx} y1={n2y + n2h} x2={cx} y2={n3y - 2}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
{/* N3: AI classifies + sends MSG 1 */}
|
||||
<rect x={nx} y={n3y} width={nW} height={n3h} rx={8} fill="#ECFDF5" stroke="#10B981" strokeWidth={1.5} />
|
||||
<text x={cx} y={n3y+20} textAnchor="middle" fontSize={12} fontWeight="700" fill="#065F46">Google AI classifies YES / NO</text>
|
||||
<text x={cx} y={n3y+36} textAnchor="middle" fontSize={10} fontWeight="600" fill="#047857">MSG 1 → AI self-introduction sent</text>
|
||||
<text x={cx} y={n3y+52} textAnchor="middle" fontSize={9} fill="#6B7280" fontStyle="italic">"Hi! My name is Lisa at {"{officeName}"}…"</text>
|
||||
<text x={cx} y={n3y+66} textAnchor="middle" fontSize={9} fill="#6B7280" fontStyle="italic">MSG 2 → intent response (below)</text>
|
||||
|
||||
{/* ── Node 3: AI introduces itself ──────────────────────────── */}
|
||||
<rect x={nx} y={n3y} width={nodeW} height={n3h} rx={8}
|
||||
fill="#ECFDF5" stroke="#10B981" strokeWidth={1.5} />
|
||||
<text x={cx} y={n3y + 24} textAnchor="middle" fontSize={13}
|
||||
fontWeight="600" fill="#065F46">AI introduces itself</text>
|
||||
<text x={cx} y={n3y + 43} textAnchor="middle" fontSize={9}
|
||||
fill="#6B7280" fontStyle="italic">"Hi! My name is Lisa, the dedicated</text>
|
||||
<text x={cx} y={n3y + 57} textAnchor="middle" fontSize={9}
|
||||
fill="#6B7280" fontStyle="italic">AI assistant at {"{officeName}"}..."</text>
|
||||
|
||||
{/* ── Fork connectors ───────────────────────────────────────── */}
|
||||
{/* Vertical down from N3 */}
|
||||
<line x1={cx} y1={n3y + n3h} x2={cx} y2={forkHY}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
{/* Horizontal fork line */}
|
||||
<line x1={lcx} y1={forkHY} x2={rcx} y2={forkHY}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
{/* Left drop → NO branch */}
|
||||
<line x1={lcx} y1={forkHY} x2={lcx} y2={branchY - 2}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
{/* Right drop → YES branch */}
|
||||
<line x1={rcx} y1={forkHY} x2={rcx} y2={branchY - 2}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
|
||||
{/* ── YES / NO badges on the fork ───────────────────────────── */}
|
||||
{/* NO badge — left junction */}
|
||||
<rect x={lcx - 28} y={forkHY - 12} width={56} height={24} rx={12}
|
||||
fill="#FFF7ED" stroke="#F97316" strokeWidth={1.5} />
|
||||
<text x={lcx} y={forkHY + 5} textAnchor="middle" fontSize={11}
|
||||
fontWeight="700" fill="#EA580C">NO</text>
|
||||
|
||||
{/* YES badge — right junction */}
|
||||
<rect x={rcx - 24} y={forkHY - 12} width={48} height={24} rx={12}
|
||||
fill="#F0FDF4" stroke="#22C55E" strokeWidth={1.5} />
|
||||
<text x={rcx} y={forkHY + 5} textAnchor="middle" fontSize={11}
|
||||
fontWeight="700" fill="#15803D">YES</text>
|
||||
|
||||
{/* ── Left branch: NO → "Would you like to reschedule?" ───────── */}
|
||||
<rect x={lcx - branchW/2} y={branchY} width={branchW} height={branchH}
|
||||
rx={8} fill="#FFF7ED" stroke="#F97316" strokeWidth={1.5} />
|
||||
<text x={lcx} y={branchY+22} textAnchor="middle" fontSize={12} fontWeight="600" fill="#C2410C">It is understandable!</text>
|
||||
<text x={lcx} y={branchY+40} textAnchor="middle" fontSize={12} fontWeight="600" fill="#C2410C">Would you like to</text>
|
||||
<text x={lcx} y={branchY+58} textAnchor="middle" fontSize={12} fontWeight="600" fill="#C2410C">reschedule?</text>
|
||||
|
||||
{/* ── Right branch: YES → Confirm ───────────────────────────── */}
|
||||
<rect x={rcx - branchW/2} y={branchY} width={branchW} height={branchH}
|
||||
rx={8} fill="#F0FDF4" stroke="#22C55E" strokeWidth={1.5} />
|
||||
<text x={rcx} y={branchY+22} textAnchor="middle" fontSize={12} fontWeight="600" fill="#15803D">Thank you for</text>
|
||||
<text x={rcx} y={branchY+40} textAnchor="middle" fontSize={12} fontWeight="600" fill="#15803D">confirming!</text>
|
||||
<text x={rcx} y={branchY+60} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">"See you on [date & time]"</text>
|
||||
|
||||
{/* ══════════ RESCHEDULING SUB-TREE ══════════════════════════════ */}
|
||||
|
||||
{/* Vertical from NO node bottom */}
|
||||
<line x1={lcx} y1={branchBottom} x2={lcx} y2={rsForkHY} stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
{/* Horizontal YES/NO fork */}
|
||||
<line x1={rsYesCx} y1={rsForkHY} x2={rsNoCx} y2={rsForkHY} stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
<line x1={rsYesCx} y1={rsForkHY} x2={rsYesCx} y2={rsNodeY-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
<line x1={rsNoCx} y1={rsForkHY} x2={rsNoCx} y2={rsNodeY-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
{/* Fork lines */}
|
||||
<line x1={cx} y1={n3y+n3h} x2={cx} y2={forkHY} stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
<line x1={lcx} y1={forkHY} x2={rcx} y2={forkHY} stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
<line x1={lcx} y1={forkHY} x2={lcx} y2={yes1y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
<line x1={rcx} y1={forkHY} x2={rcx} y2={no1y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* YES / NO badges */}
|
||||
<rect x={rsYesCx-20} y={rsForkHY-11} width={40} height={22} rx={11} fill="#F0FDF4" stroke="#22C55E" strokeWidth={1.5} />
|
||||
<text x={rsYesCx} y={rsForkHY+4} textAnchor="middle" fontSize={10} fontWeight="700" fill="#15803D">YES</text>
|
||||
<rect x={rsNoCx-18} y={rsForkHY-11} width={36} height={22} rx={11} fill="#F9FAFB" stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
<text x={rsNoCx} y={rsForkHY+4} textAnchor="middle" fontSize={10} fontWeight="700" fill="#6B7280">NO</text>
|
||||
<rect x={lcx-26} y={forkHY-12} width={52} height={24} rx={12} fill="#F0FDF4" stroke="#22C55E" strokeWidth={1.5} />
|
||||
<text x={lcx} y={forkHY+5} textAnchor="middle" fontSize={11} fontWeight="700" fill="#15803D">YES</text>
|
||||
<rect x={rcx-24} y={forkHY-12} width={48} height={24} rx={12} fill="#FFF7ED" stroke="#F97316" strokeWidth={1.5} />
|
||||
<text x={rcx} y={forkHY+5} textAnchor="middle" fontSize={11} fontWeight="700" fill="#EA580C">NO</text>
|
||||
|
||||
{/* YES → "ASAP or next week?" node */}
|
||||
<rect x={rsYesCx-52} y={rsNodeY} width={104} height={rsNodeH} rx={8} fill="#EFF6FF" stroke="#3B82F6" strokeWidth={1.5} />
|
||||
<text x={rsYesCx} y={rsNodeY+18} textAnchor="middle" fontSize={10} fontWeight="600" fill="#1D4ED8">ASAP or</text>
|
||||
<text x={rsYesCx} y={rsNodeY+32} textAnchor="middle" fontSize={10} fontWeight="600" fill="#1D4ED8">next week?</text>
|
||||
<text x={rsYesCx} y={rsNodeY+46} textAnchor="middle" fontSize={9} fill="#6B7280" fontStyle="italic">(if Mon–Thu appt)</text>
|
||||
{/* ══ YES BRANCH ══════════════════════════════════════════════════ */}
|
||||
|
||||
{/* NO → polite close */}
|
||||
<rect x={rsNoCx-46} y={rsNodeY} width={92} height={rsNodeH} rx={8} fill="#F9FAFB" stroke="#D1D5DB" strokeWidth={1.5} />
|
||||
<text x={rsNoCx} y={rsNodeY+18} textAnchor="middle" fontSize={10} fontWeight="600" fill="#374151">No problem!</text>
|
||||
<text x={rsNoCx} y={rsNodeY+36} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">Conversation ends</text>
|
||||
{/* Yes1: Thank you */}
|
||||
<rect x={lcx-nW/2} y={yes1y} width={nW} height={yes1h} rx={8} fill="#F0FDF4" stroke="#22C55E" strokeWidth={1.5} />
|
||||
<text x={lcx} y={yes1y+20} textAnchor="middle" fontSize={11} fontWeight="600" fill="#15803D">MSG 2: Thank you for confirming!</text>
|
||||
<text x={lcx} y={yes1y+38} textAnchor="middle" fontSize={9} fill="#6B7280" fontStyle="italic">"See you on [date & time]"</text>
|
||||
<text x={lcx} y={yes1y+56} textAnchor="middle" fontSize={9} fill="#6B7280" fontStyle="italic">Appointment confirmed ✓</text>
|
||||
<line x1={lcx} y1={yes1y+yes1h} x2={lcx} y2={yes2y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* Vertical from "ASAP or next week?" down to preference fork */}
|
||||
<line x1={rsYesCx} y1={rsNodeY+rsNodeH} x2={rsYesCx} y2={prefForkHY} stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
{/* ASAP / Next week fork */}
|
||||
<line x1={asakCx} y1={prefForkHY} x2={nwkCx} y2={prefForkHY} stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
<line x1={asakCx} y1={prefForkHY} x2={asakCx} y2={prefNodeY-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
<line x1={nwkCx} y1={prefForkHY} x2={nwkCx} y2={prefNodeY-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
{/* Yes2: Patient thanks → closing */}
|
||||
<rect x={lcx-nW/2} y={yes2y} width={nW} height={yes2h} rx={8} fill="#F9FAFB" stroke="#D1D5DB" strokeWidth={1.5} />
|
||||
<text x={lcx} y={yes2y+20} textAnchor="middle" fontSize={11} fontWeight="600" fill="#374151">Patient: "Thank you / OK"</text>
|
||||
<text x={lcx} y={yes2y+38} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">AI: "Thank you for choosing us!</text>
|
||||
<text x={lcx} y={yes2y+50} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">See you on [date]"</text>
|
||||
|
||||
{/* ASAP badge */}
|
||||
<rect x={asakCx-22} y={prefForkHY-11} width={44} height={22} rx={11} fill="#EFF6FF" stroke="#3B82F6" strokeWidth={1.5} />
|
||||
<text x={asakCx} y={prefForkHY+4} textAnchor="middle" fontSize={9} fontWeight="700" fill="#1D4ED8">ASAP</text>
|
||||
{/* Next week badge */}
|
||||
<rect x={nwkCx-30} y={prefForkHY-11} width={60} height={22} rx={11} fill="#F5F3FF" stroke="#8B5CF6" strokeWidth={1.5} />
|
||||
<text x={nwkCx} y={prefForkHY+4} textAnchor="middle" fontSize={9} fontWeight="700" fill="#6D28D9">Next week</text>
|
||||
{/* ══ NO / RESCHEDULE BRANCH ══════════════════════════════════════ */}
|
||||
|
||||
{/* ASAP → "Can you come tomorrow?" */}
|
||||
<rect x={asakCx-44} y={prefNodeY} width={88} height={prefNodeH} rx={8} fill="#EFF6FF" stroke="#3B82F6" strokeWidth={1.5} />
|
||||
<text x={asakCx} y={prefNodeY+16} textAnchor="middle" fontSize={10} fontWeight="600" fill="#1D4ED8">Can you come</text>
|
||||
<text x={asakCx} y={prefNodeY+30} textAnchor="middle" fontSize={10} fontWeight="600" fill="#1D4ED8">tomorrow?</text>
|
||||
<text x={asakCx} y={prefNodeY+48} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">YES → ask time</text>
|
||||
{/* no1: When would you like to reschedule? */}
|
||||
<rect x={rcx-noW/2} y={no1y} width={noW} height={no1h} rx={8} fill="#FFF7ED" stroke="#F97316" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no1y+20} textAnchor="middle" fontSize={11} fontWeight="600" fill="#C2410C">MSG 2: It is understandable!</text>
|
||||
<text x={rcx} y={no1y+38} textAnchor="middle" fontSize={11} fontWeight="600" fill="#C2410C">When would you like to reschedule?</text>
|
||||
<text x={rcx} y={no1y+54} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">Patient replies with a preferred date</text>
|
||||
<line x1={rcx} y1={no1y+no1h} x2={rcx} y2={no2y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* Next week → "Mon, Tue, or Wed?" */}
|
||||
<rect x={nwkCx-46} y={prefNodeY} width={92} height={prefNodeH} rx={8} fill="#F5F3FF" stroke="#8B5CF6" strokeWidth={1.5} />
|
||||
<text x={nwkCx} y={prefNodeY+16} textAnchor="middle" fontSize={10} fontWeight="600" fill="#5B21B6">Mon, Tue,</text>
|
||||
<text x={nwkCx} y={prefNodeY+30} textAnchor="middle" fontSize={10} fontWeight="600" fill="#5B21B6">or Wed?</text>
|
||||
<text x={nwkCx} y={prefNodeY+48} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">→ ask time</text>
|
||||
{/* no2: Date received + day-open check */}
|
||||
<rect x={rcx-noW/2} y={no2y} width={noW} height={no2h} rx={8} fill="#ECFDF5" stroke="#10B981" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no2y+18} textAnchor="middle" fontSize={11} fontWeight="700" fill="#065F46">Check: Is office open on that day?</text>
|
||||
<text x={rcx} y={no2y+34} textAnchor="middle" fontSize={9} fill="#6B7280">(reads Office Hours settings)</text>
|
||||
<text x={rcx} y={no2y+52} textAnchor="middle" fontSize={9} fill="#15803D" fontWeight="600">✓ Open → ask what time</text>
|
||||
<text x={rcx} y={no2y+68} textAnchor="middle" fontSize={9} fill="#DC2626" fontWeight="600">✗ Closed → "Office closed on [day]. Choose another day?"</text>
|
||||
{/* fail annotation */}
|
||||
<line x1={rcx+noW/2} y1={no2y+no2h-16} x2={failX-1} y2={no2y+no2h-16} stroke="#EF4444" strokeWidth={1} strokeDasharray="3 2" markerEnd="url(#rg2fail)" />
|
||||
<rect x={failX} y={no2y+no2h-28} width={failW} height={24} rx={5} fill="#FEF2F2" stroke="#FCA5A5" strokeWidth={1} />
|
||||
<text x={failX+failW/2} y={no2y+no2h-12} textAnchor="middle" fontSize={8} fill="#DC2626">↩ loops back to ask date</text>
|
||||
<line x1={rcx} y1={no2y+no2h} x2={rcx} y2={no3y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* ── Time-slot node (shared by both paths) ─────────────────── */}
|
||||
{/* Left vertical from ASAP node */}
|
||||
<line x1={asakCx} y1={prefNodeY+prefNodeH} x2={asakCx} y2={prefNodeY+prefNodeH+18}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
{/* Right vertical from NextWeek node */}
|
||||
<line x1={nwkCx} y1={prefNodeY+prefNodeH} x2={nwkCx} y2={prefNodeY+prefNodeH+18}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
{/* Horizontal converge line */}
|
||||
<line x1={asakCx} y1={prefNodeY+prefNodeH+18} x2={nwkCx} y2={prefNodeY+prefNodeH+18}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} />
|
||||
{/* Drop to time node */}
|
||||
<line x1={rsYesCx} y1={prefNodeY+prefNodeH+18} x2={rsYesCx} y2={prefNodeY+prefNodeH+36}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
{/* no3: What time on [date]? */}
|
||||
<rect x={rcx-noW/2} y={no3y} width={noW} height={no3h} rx={8} fill="#ECFDF5" stroke="#10B981" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no3y+20} textAnchor="middle" fontSize={11} fontWeight="600" fill="#065F46">AI: "What time do you prefer</text>
|
||||
<text x={rcx} y={no3y+36} textAnchor="middle" fontSize={11} fontWeight="600" fill="#065F46">on [date]?"</text>
|
||||
<text x={rcx} y={no3y+52} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">Patient replies with a time (e.g. "1 pm")</text>
|
||||
<line x1={rcx} y1={no3y+no3h} x2={rcx} y2={no4y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* Time-slot node */}
|
||||
<rect x={rsYesCx-52} y={prefNodeY+prefNodeH+40} width={104} height={54} rx={8}
|
||||
fill="#ECFDF5" stroke="#10B981" strokeWidth={1.5} />
|
||||
<text x={rsYesCx} y={prefNodeY+prefNodeH+58} textAnchor="middle" fontSize={10} fontWeight="600" fill="#065F46">Morning or</text>
|
||||
<text x={rsYesCx} y={prefNodeY+prefNodeH+72} textAnchor="middle" fontSize={10} fontWeight="600" fill="#065F46">afternoon?</text>
|
||||
{/* no4: Time received + hours check */}
|
||||
<rect x={rcx-noW/2} y={no4y} width={noW} height={no4h} rx={8} fill="#ECFDF5" stroke="#10B981" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no4y+18} textAnchor="middle" fontSize={11} fontWeight="700" fill="#065F46">Check: Is time within office hours?</text>
|
||||
<text x={rcx} y={no4y+34} textAnchor="middle" fontSize={9} fill="#6B7280">(e.g. not during lunch 12–1pm)</text>
|
||||
<text x={rcx} y={no4y+52} textAnchor="middle" fontSize={9} fill="#15803D" fontWeight="600">✓ In hours → ask to confirm</text>
|
||||
<text x={rcx} y={no4y+68} textAnchor="middle" fontSize={9} fill="#DC2626" fontWeight="600">✗ → "Not available. Our hours: [AM]–[PM]. Other time?"</text>
|
||||
<line x1={rcx+noW/2} y1={no4y+no4h-16} x2={failX-1} y2={no4y+no4h-16} stroke="#EF4444" strokeWidth={1} strokeDasharray="3 2" markerEnd="url(#rg2fail)" />
|
||||
<rect x={failX} y={no4y+no4h-28} width={failW} height={24} rx={5} fill="#FEF2F2" stroke="#FCA5A5" strokeWidth={1} />
|
||||
<text x={failX+failW/2} y={no4y+no4h-12} textAnchor="middle" fontSize={8} fill="#DC2626">↩ loops back to ask time</text>
|
||||
<line x1={rcx} y1={no4y+no4h} x2={rcx} y2={no5y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* DB update node (dashed) */}
|
||||
<line x1={rsYesCx} y1={prefNodeY+prefNodeH+94} x2={rsYesCx} y2={prefNodeY+prefNodeH+112}
|
||||
stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#ah)" />
|
||||
<rect x={rsYesCx-52} y={prefNodeY+prefNodeH+116} width={104} height={54} rx={8}
|
||||
{/* no5: Just to confirm */}
|
||||
<rect x={rcx-noW/2} y={no5y} width={noW} height={no5h} rx={8} fill="#ECFDF5" stroke="#10B981" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no5y+20} textAnchor="middle" fontSize={11} fontWeight="600" fill="#065F46">AI: "Just to confirm —</text>
|
||||
<text x={rcx} y={no5y+36} textAnchor="middle" fontSize={11} fontWeight="600" fill="#065F46">do you prefer [date at time]?"</text>
|
||||
<text x={rcx} y={no5y+52} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">Patient replies YES or NO</text>
|
||||
<line x1={rcx} y1={no5y+no5h} x2={rcx} y2={no6y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* no6: Patient YES/NO */}
|
||||
<rect x={rcx-noW/2} y={no6y} width={noW} height={no6h} rx={8} fill="#F9FAFB" stroke="#D1D5DB" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no6y+18} textAnchor="middle" fontSize={11} fontWeight="600" fill="#374151">Patient confirms or corrects</text>
|
||||
<text x={rcx} y={no6y+36} textAnchor="middle" fontSize={9} fill="#15803D" fontWeight="600">✓ YES → check slot availability</text>
|
||||
<text x={rcx} y={no6y+52} textAnchor="middle" fontSize={9} fill="#DC2626" fontWeight="600">✗ NO → "No problem! What day/time?"</text>
|
||||
<text x={rcx} y={no6y+66} textAnchor="middle" fontSize={8} fill="#9CA3AF" fontStyle="italic">↩ returns to date step</text>
|
||||
<line x1={rcx} y1={no6y+no6h} x2={rcx} y2={no7y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* no7: Slot availability check */}
|
||||
<rect x={rcx-noW/2} y={no7y} width={noW} height={no7h} rx={8} fill="#ECFDF5" stroke="#10B981" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no7y+18} textAnchor="middle" fontSize={11} fontWeight="700" fill="#065F46">Check: Is slot available for staff?</text>
|
||||
<text x={rcx} y={no7y+34} textAnchor="middle" fontSize={9} fill="#6B7280">(no overlapping appointments)</text>
|
||||
<text x={rcx} y={no7y+52} textAnchor="middle" fontSize={9} fill="#15803D" fontWeight="600">✓ Free → move appointment</text>
|
||||
<text x={rcx} y={no7y+68} textAnchor="middle" fontSize={9} fill="#DC2626" fontWeight="600">✗ Taken → "[date] not available. Other time?"</text>
|
||||
<line x1={rcx+noW/2} y1={no7y+no7h-16} x2={failX-1} y2={no7y+no7h-16} stroke="#EF4444" strokeWidth={1} strokeDasharray="3 2" markerEnd="url(#rg2fail)" />
|
||||
<rect x={failX} y={no7y+no7h-28} width={failW} height={24} rx={5} fill="#FEF2F2" stroke="#FCA5A5" strokeWidth={1} />
|
||||
<text x={failX+failW/2} y={no7y+no7h-12} textAnchor="middle" fontSize={8} fill="#DC2626">↩ loops back to ask date</text>
|
||||
<line x1={rcx} y1={no7y+no7h} x2={rcx} y2={no8y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* no8: DB move + AI badge */}
|
||||
<rect x={rcx-noW/2} y={no8y} width={noW} height={no8h} rx={8}
|
||||
fill="#F0F9FF" stroke="#0EA5E9" strokeWidth={1.5} strokeDasharray="5 3" />
|
||||
<rect x={rsYesCx-38} y={prefNodeY+prefNodeH+108} width={76} height={20} rx={10}
|
||||
fill="#E0F2FE" stroke="#0EA5E9" strokeWidth={1.5} />
|
||||
<text x={rsYesCx} y={prefNodeY+prefNodeH+122} textAnchor="middle" fontSize={9} fontWeight="700" fill="#0369A1">DB Update</text>
|
||||
<text x={rsYesCx} y={prefNodeY+prefNodeH+138} textAnchor="middle" fontSize={10} fontWeight="600" fill="#0369A1">Appt. moved!</text>
|
||||
<text x={rsYesCx} y={prefNodeY+prefNodeH+154} textAnchor="middle" fontSize={9} fill="#6B7280" fontStyle="italic">"See you on [day] at [time]"</text>
|
||||
<rect x={rcx-46} y={no8y-11} width={92} height={22} rx={11} fill="#E0F2FE" stroke="#0EA5E9" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no8y+3} textAnchor="middle" fontSize={9} fontWeight="700" fill="#0369A1">DB Update</text>
|
||||
<text x={rcx} y={no8y+22} textAnchor="middle" fontSize={11} fontWeight="600" fill="#0369A1">Appointment moved!</text>
|
||||
<text x={rcx} y={no8y+38} textAnchor="middle" fontSize={9} fill="#6B7280" fontStyle="italic">"Appt moved to [date at time].</text>
|
||||
<text x={rcx} y={no8y+52} textAnchor="middle" fontSize={9} fill="#6B7280" fontStyle="italic">Receptionist will confirm tomorrow."</text>
|
||||
<text x={rcx} y={no8y+68} textAnchor="middle" fontSize={9} fill="#0369A1" fontWeight="600">🤖 AI badge shown on schedule grid</text>
|
||||
<line x1={rcx} y1={no8y+no8h} x2={rcx} y2={no9y-2} stroke="#9CA3AF" strokeWidth={1.5} markerEnd="url(#rg2ah)" />
|
||||
|
||||
{/* no9: Patient thanks */}
|
||||
<rect x={rcx-noW/2} y={no9y} width={noW} height={no9h} rx={8} fill="#F9FAFB" stroke="#D1D5DB" strokeWidth={1.5} />
|
||||
<text x={rcx} y={no9y+20} textAnchor="middle" fontSize={11} fontWeight="600" fill="#374151">Patient: "Thank you / OK"</text>
|
||||
<text x={rcx} y={no9y+38} textAnchor="middle" fontSize={9} fill="#9CA3AF" fontStyle="italic">AI: "Thank you for choosing us! See you on [date]"</text>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user