/* ===== Growing Now — Agent Chat System (Groq) ===== */ (function () { const { useState, useEffect, useRef } = React; const Icon = window.Icon; const PRIVACY_NOTE = { es: 'No compartas contraseñas ni información sensible. La IA puede equivocarse.', en: 'Do not share passwords or sensitive information. AI can make mistakes.' }; const GREETINGS = { zuki: { es: 'Hola, soy Zuki 🦊, tu aliada para organizar ideas y convertirlas en acciones.', en: "Hi, I'm Zuki 🦊, your ally for organizing ideas and turning them into actions." }, tula: { es: 'Hola, soy Tula 🐢, estoy aquí para ayudarte a avanzar con calma y claridad.', en: "Hi, I'm Tula 🐢, I'm here to help you move forward with calm and clarity." }, piplo: { es: 'Hola, soy Piplo 🐦, observo conversaciones para descubrir oportunidades de crecimiento.', en: "Hi, I'm Piplo 🐦, I observe conversations to discover growth opportunities." }, nox: { es: 'Hola, soy Nox 🐺, tu estratega para detectar oportunidades y tomar mejores decisiones.', en: "Hi, I'm Nox 🐺, your strategist for spotting opportunities and making better decisions." }, hugo: { es: 'Hola, soy Hugo 🦉, tu creativo para convertir ideas en mensajes que conectan.', en: "Hi, I'm Hugo 🦉, your creative for turning ideas into messages that connect." }, max: { es: 'Hola, soy Max 🐻, tu aliado para transformar planes en resultados.', en: "Hi, I'm Max 🐻, your ally for transforming plans into results." } }; async function callGroq(agentId, messages, lang) { const r = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ agentId, lang, messages }) }); if (!r.ok) throw new Error('API error'); const d = await r.json(); return d.text; } /* ── AgentChatPanel: panel modal para cualquier agente ── */ function AgentChatPanel({ agent, lang, onClose }) { const id = agent.id; const greeting = GREETINGS[id]?.[lang] || GREETINGS.zuki[lang]; const [msgs, setMsgs] = useState([{ role: 'assistant', text: greeting }]); const [input, setInput] = useState(''); const [busy, setBusy] = useState(false); const bodyRef = useRef(null); useEffect(() => { setMsgs([{ role: 'assistant', text: GREETINGS[id]?.[lang] || GREETINGS.zuki[lang] }]); }, [id, lang]); useEffect(() => { if (bodyRef.current) bodyRef.current.scrollTop = bodyRef.current.scrollHeight; }, [msgs, busy]); async function send(text) { const content = (text ?? input).trim(); if (!content || busy) return; const history = [...msgs, { role: 'user', text: content }]; setMsgs(history); setInput(''); setBusy(true); const apiMsgs = history.map(m => ({ role: m.role === 'user' ? 'user' : 'assistant', content: m.text })); try { const reply = await callGroq(id, apiMsgs, lang); setMsgs(m => [...m, { role: 'assistant', text: reply }]); } catch { setMsgs(m => [...m, { role: 'assistant', text: lang === 'es' ? `Ahora mismo no puedo conectar 😅 ¡Agenda una llamada con el botón de arriba!` : `Can't connect right now 😅 Book a call with the button above!` }]); } setBusy(false); } return (
e.stopPropagation()} className="glass modal-card" style={{ maxWidth: 420, width: '100%', height: 'min(600px,calc(100vh - 80px))', borderRadius: 26, display: 'flex', flexDirection: 'column', overflow: 'hidden', background: `linear-gradient(180deg,${agent.tint}f0,rgba(255,255,255,.97))` }}> {/* Header */}
{agent.name}
{agent.name}
{agent.role[lang]}
{/* Messages */}
{msgs.map((m, i) => (
{m.text}
))} {busy && (
{[0,1,2].map(i => )}
)}
{/* Cal.com */} {lang === 'es' ? `Agendar llamada con ${agent.name}` : `Book a call with ${agent.name}`} {/* Input */}
setInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && send()} placeholder={lang === 'es' ? `Escríbele a ${agent.name}…` : `Message ${agent.name}…`} style={{ flex: 1, border: 'none', outline: 'none', background: 'rgba(0,0,0,.04)', borderRadius: 99, padding: '11px 16px', fontFamily: 'var(--font-body)', fontSize: '.95rem' }} />
{PRIVACY_NOTE[lang]}
); } /* ── ZukiLauncher: botón flotante + panel de Zuki ── */ function ZukiLauncher({ lang, openSignal }) { const L = window.I18N.STR[lang]; const zuki = window.GN.byId.zuki; const [open, setOpen] = useState(false); const [msgs, setMsgs] = useState([{ role: 'assistant', text: GREETINGS.zuki[lang] }]); const [input, setInput] = useState(''); const [busy, setBusy] = useState(false); const bodyRef = useRef(null); useEffect(() => { setMsgs([{ role: 'assistant', text: GREETINGS.zuki[lang] }]); }, [lang]); useEffect(() => { if (openSignal) setOpen(true); }, [openSignal]); useEffect(() => { if (bodyRef.current) bodyRef.current.scrollTop = bodyRef.current.scrollHeight; }, [msgs, busy, open]); async function send(text) { const content = (text ?? input).trim(); if (!content || busy) return; const history = [...msgs, { role: 'user', text: content }]; setMsgs(history); setInput(''); setBusy(true); const apiMsgs = history.map(m => ({ role: m.role === 'user' ? 'user' : 'assistant', content: m.text })); try { const reply = await callGroq('zuki', apiMsgs, lang); setMsgs(m => [...m, { role: 'assistant', text: reply }]); } catch { setMsgs(m => [...m, { role: 'assistant', text: lang === 'es' ? 'Ahora mismo no puedo conectar 😅. ¡Agenda una llamada con el botón de arriba!' : "Can't reach my brain right now 😅. Book a call with the button above!" }]); } setBusy(false); } return ( <> {/* Launcher button */} {/* Zuki panel */} {open && (
{/* Header */}
Zuki
{L.chat_title}
{L.chat_role}
{/* Messages */}
{msgs.map((m, i) => (
{m.text}
))} {busy && (
{[0,1,2].map(i => )}
)}
{/* Cal.com */} {L.chat_book} {/* Input */}
setInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && send()} placeholder={L.chat_ph} style={{ flex: 1, border: 'none', outline: 'none', background: 'rgba(0,0,0,.04)', borderRadius: 99, padding: '11px 16px', fontFamily: 'var(--font-body)', fontSize: '.95rem' }} />
{PRIVACY_NOTE[lang]}
)} ); } window.AgentChatPanel = AgentChatPanel; window.ZukiLauncher = ZukiLauncher; })();