"use client" import { useEffect, useState, useRef } from "react" import { fetchApi } from "@/lib/api-config" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { ScrollArea } from "@/components/ui/scroll-area" import { Loader2, CheckCircle2, XCircle, AlertCircle } from "lucide-react" interface HybridScriptMonitorProps { sessionId: string | null title?: string description?: string onClose: () => void onComplete?: (success: boolean) => void } interface ScriptInteraction { type: "msgbox" | "yesno" | "inputbox" | "menu" id: string title: string text: string data?: string } interface LogEntry { timestamp: string message: string type: "info" | "error" | "warning" | "success" } export function HybridScriptMonitor({ sessionId, title = "Script Execution", description = "Monitoring script execution...", onClose, onComplete, }: HybridScriptMonitorProps) { const [logs, setLogs] = useState([]) const [interaction, setInteraction] = useState(null) const [status, setStatus] = useState<"running" | "completed" | "failed">("running") const [inputValue, setInputValue] = useState("") const [selectedMenuItem, setSelectedMenuItem] = useState("") const [isResponding, setIsResponding] = useState(false) const scrollRef = useRef(null) const pollingIntervalRef = useRef(null) // Auto-scroll to bottom when logs update useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight } }, [logs]) // Poll for logs and status useEffect(() => { if (!sessionId) return const pollScript = async () => { try { console.log("[v0] Polling script status and logs for session:", sessionId) // Get status const statusData = await fetchApi(`/api/scripts/status/${sessionId}`) console.log("[v0] Status data:", statusData) if (statusData.status === "completed") { setStatus("completed") if (pollingIntervalRef.current) { clearInterval(pollingIntervalRef.current) } onComplete?.(true) } else if (statusData.status === "failed") { setStatus("failed") if (pollingIntervalRef.current) { clearInterval(pollingIntervalRef.current) } onComplete?.(false) } // Get logs const logsData = await fetchApi(`/api/scripts/logs/${sessionId}`) console.log("[v0] Logs data:", logsData) if (logsData.logs && Array.isArray(logsData.logs)) { const parsedLogs: LogEntry[] = [] for (const logLine of logsData.logs) { // Check for web interaction if (logLine.includes("WEB_INTERACTION:")) { const parts = logLine.split("WEB_INTERACTION:")[1].split(":") if (parts.length >= 4) { const [type, id, title, text, ...dataParts] = parts const data = dataParts.join(":") console.log("[v0] Detected interaction:", { type, id, title, text, data }) setInteraction({ type: type as ScriptInteraction["type"], id, title: title.replace(/_/g, " "), text: text.replace(/_/g, " "), data, }) // Pause polling while waiting for user interaction if (pollingIntervalRef.current) { clearInterval(pollingIntervalRef.current) } } } else { // Regular log entry parsedLogs.push({ timestamp: new Date().toLocaleTimeString(), message: logLine, type: logLine.toLowerCase().includes("error") ? "error" : logLine.toLowerCase().includes("warning") ? "warning" : logLine.toLowerCase().includes("success") ? "success" : "info", }) } } setLogs(parsedLogs) } } catch (error) { console.error("[v0] Error polling script:", error) setLogs((prev) => [ ...prev, { timestamp: new Date().toLocaleTimeString(), message: `Error: ${error}`, type: "error", }, ]) } } // Initial poll pollScript() // Set up polling interval pollingIntervalRef.current = setInterval(pollScript, 2000) return () => { if (pollingIntervalRef.current) { clearInterval(pollingIntervalRef.current) } } }, [sessionId, onComplete]) const handleInteractionResponse = async (response: string) => { if (!interaction || !sessionId) return setIsResponding(true) try { console.log("[v0] Sending interaction response:", { session_id: sessionId, interaction_id: interaction.id, response, }) await fetchApi("/api/scripts/respond", { method: "POST", body: JSON.stringify({ session_id: sessionId, interaction_id: interaction.id, response, }), }) setInteraction(null) setInputValue("") setSelectedMenuItem("") // Resume polling if (!pollingIntervalRef.current && status === "running") { pollingIntervalRef.current = setInterval(async () => { // Polling logic here (same as above) }, 2000) } } catch (error) { console.error("[v0] Error responding to interaction:", error) setLogs((prev) => [ ...prev, { timestamp: new Date().toLocaleTimeString(), message: `Error responding: ${error}`, type: "error", }, ]) } finally { setIsResponding(false) } } const renderInteractionModal = () => { if (!interaction) return null switch (interaction.type) { case "msgbox": return ( {}}> {interaction.title} {interaction.text}
) case "yesno": return ( {}}> {interaction.title} {interaction.text}
) case "inputbox": return ( {}}> {interaction.title} {interaction.text}
setInputValue(e.target.value)} placeholder={interaction.data || "Enter value..."} />
) case "menu": const menuItems = interaction.data?.split("|").filter(Boolean) || [] return ( {}}> {interaction.title} {interaction.text}
{menuItems.map((item, index) => ( ))}
) default: return null } } if (!sessionId) return null return ( <> {status === "running" && } {status === "completed" && } {status === "failed" && } {title} {description}
{/* Logs Display */}
Execution Logs
{logs.length === 0 ? (
Waiting for logs...
) : ( logs.map((log, index) => (
[{log.timestamp}] {log.message}
)) )}
{/* Status footer */}
Session ID: {sessionId}
{status !== "running" && }
{/* Interaction Modal */} {renderInteractionModal()} ) }