'use client'; import { useState, useRef, useEffect } from 'react'; import { Send, Sparkles, Shield, BookOpen, Heart, Brain, Eye, EyeOff, Bot, Mic, Paperclip, MoreHorizontal, } from 'lucide-react'; import AuraOrb from './AuraOrb'; import MarkdownMessage from '../chat/MarkdownMessage'; import ThinkingIndicator from '../chat/ThinkingIndicator'; interface Message { role: 'user' | 'assistant'; content: string; agent?: string; trace?: TraceStep[]; timestamp?: Date; } interface TraceStep { agent: string; action: string; result?: string; } const agentIcons: Record = { Gatekeeper: Shield, Theologian: BookOpen, Healer: Heart, Orchestrator: Brain, System: Sparkles, }; const agentColors: Record = { Gatekeeper: { bg: 'bg-purple-500/20', border: 'border-purple-500/30', text: 'text-purple-400' }, Theologian: { bg: 'bg-blue-500/20', border: 'border-blue-500/30', text: 'text-blue-400' }, Healer: { bg: 'bg-rose-500/20', border: 'border-rose-500/30', text: 'text-rose-400' }, Orchestrator: { bg: 'bg-amber-500/20', border: 'border-amber-500/30', text: 'text-amber-400' }, System: { bg: 'bg-neutral-500/20', border: 'border-neutral-500/30', text: 'text-neutral-400' }, }; const quickActions = [ { label: 'Pray with me', icon: Heart }, { label: 'Explain a verse', icon: BookOpen }, { label: 'Daily reflection', icon: Sparkles }, { label: 'Seek guidance', icon: Brain }, ]; export default function ChatInterface() { const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [isTyping, setIsTyping] = useState(false); const [activeAgent, setActiveAgent] = useState('Gatekeeper'); const [orbState, setOrbState] = useState<'idle' | 'listening' | 'thinking' | 'speaking'>('idle'); const [showTrace, setShowTrace] = useState>({}); const messagesEndRef = useRef(null); const inputRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; useEffect(() => { scrollToBottom(); }, [messages, isTyping]); // Auto-resize textarea useEffect(() => { if (inputRef.current) { inputRef.current.style.height = 'auto'; inputRef.current.style.height = `${Math.min(inputRef.current.scrollHeight, 120)}px`; } }, [input]); const handleSend = async () => { if (!input.trim() || isTyping) return; const userMsg: Message = { role: 'user', content: input, timestamp: new Date(), }; setMessages(prev => [...prev, userMsg]); setInput(''); setIsTyping(true); setOrbState('thinking'); setActiveAgent('Gatekeeper'); try { const response = await fetch('http://localhost:6000/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: input }) }); const data = await response.json(); if (data.success) { if (data.response.agent !== 'Gatekeeper') { setActiveAgent(data.response.agent); await new Promise(resolve => setTimeout(resolve, 300)); } setOrbState('speaking'); const assistantMsg: Message = { role: 'assistant', content: data.response.content, agent: data.response.agent, trace: data.response.trace || [], timestamp: new Date(), }; setMessages(prev => [...prev, assistantMsg]); // Return to idle after a moment setTimeout(() => setOrbState('idle'), 2000); } } catch (error) { console.error('Chat failed:', error); setMessages(prev => [...prev, { role: 'assistant', content: "I apologize, but I'm having trouble connecting to my reasoning core. Please ensure the ORA backend is running on port 6000.", agent: 'System', timestamp: new Date(), }]); setOrbState('idle'); } finally { setIsTyping(false); } }; const handleQuickAction = (action: string) => { setInput(action); inputRef.current?.focus(); }; const toggleTrace = (index: number) => { setShowTrace(prev => ({ ...prev, [index]: !prev[index] })); }; const AgentIcon = ({ agent }: { agent: string }) => { const Icon = agentIcons[agent] || Sparkles; const colors = agentColors[agent] || agentColors.System; return (
); }; // Empty state if (messages.length === 0) { return (
{/* Hero Section */}

Welcome to ORA

Your sovereign AI spiritual companion. I'm here to help you explore Scripture, reflect on your faith, and grow in wisdom.

{/* Quick Actions */}
{quickActions.map((action) => ( ))}
{/* Input Area */}