"use client" import { useEffect, useRef, useState } from "react" import { useDictionary } from "@/hooks/use-dictionary" import { wrapWithMxFile } from "@/lib/utils" // Dev XML presets for streaming simulator const DEV_XML_PRESETS: Record = { "Simple Box": ` `, "Two Boxes with Arrow": ` `, Flowchart: ` `, "Truncated (Error Test)": ` `, } interface DevXmlSimulatorProps { setMessages: React.Dispatch> onDisplayChart: (xml: string) => void onShowQuotaToast?: () => void } export function DevXmlSimulator({ setMessages, onDisplayChart, onShowQuotaToast, }: DevXmlSimulatorProps) { const dict = useDictionary() const [devXml, setDevXml] = useState("") const [isSimulating, setIsSimulating] = useState(false) const [devIntervalMs, setDevIntervalMs] = useState(1) const [devChunkSize, setDevChunkSize] = useState(10) const devStopRef = useRef(false) const devXmlInitializedRef = useRef(false) // Restore dev XML from localStorage on mount (after hydration) useEffect(() => { const saved = localStorage.getItem("dev-xml-simulator") if (saved) setDevXml(saved) devXmlInitializedRef.current = true }, []) // Save dev XML to localStorage (only after initial load) useEffect(() => { if (devXmlInitializedRef.current) { localStorage.setItem("dev-xml-simulator", devXml) } }, [devXml]) const handleDevSimulate = async () => { if (!devXml.trim() || isSimulating) return setIsSimulating(true) devStopRef.current = false const toolCallId = `dev-sim-${Date.now()}` const xml = devXml.trim() // Add user message and initial assistant message with empty XML const userMsg = { id: `user-${Date.now()}`, role: "user" as const, parts: [ { type: "text" as const, text: dict.dev.simulatingMessage, }, ], } const assistantMsg = { id: `assistant-${Date.now()}`, role: "assistant" as const, parts: [ { type: "tool-display_diagram" as const, toolCallId, state: "input-streaming" as const, input: { xml: "" }, }, ], } setMessages((prev) => [...prev, userMsg, assistantMsg] as any) // Stream characters progressively for (let i = 0; i < xml.length; i += devChunkSize) { if (devStopRef.current) { setIsSimulating(false) return } const chunk = xml.slice(0, i + devChunkSize) setMessages((prev) => { const updated = [...prev] const lastMsg = updated[updated.length - 1] as any if (lastMsg?.role === "assistant" && lastMsg.parts?.[0]) { lastMsg.parts[0].input = { xml: chunk } } return updated }) await new Promise((r) => setTimeout(r, devIntervalMs)) } if (devStopRef.current) { setIsSimulating(false) return } // Finalize: set state to output-available setMessages((prev) => { const updated = [...prev] const lastMsg = updated[updated.length - 1] as any if (lastMsg?.role === "assistant" && lastMsg.parts?.[0]) { lastMsg.parts[0].state = "output-available" lastMsg.parts[0].output = dict.dev.successMessage lastMsg.parts[0].input = { xml } } return updated }) // Display the final diagram const fullXml = wrapWithMxFile(xml) onDisplayChart(fullXml) setIsSimulating(false) } return (
{dict.dev.title}