// El Mirador — Chatbot dock // Globals: EMChatbot const { useState: useChat, useRef: useChatRef, useEffect: useChatEffect } = React; // Local guide responses — observational, editorial, never corporate const GUIDE_RESPONSES = { "¿Dónde puedo trabajar tranquilo?": "Estudio Norte (19 Pte 506) tiene mesas anchas y buena conexión — llena entre las diez y la una, tranquila después. Don Rafael también sirve: se queda sin preguntar cuánto tiempo llevas.", "¿Qué cafés tienen buena luz?": "Don Rafael tiene luz norte durante toda la mañana — suave, sin sombras directas. Tostadora Luz, por el oriente, es mejor antes de las diez. Después entra el sol de frente.", "¿Qué negocios clásicos siguen vivos?": "Sastrería Núñez (15 Norte 902) lleva desde 1958, tres generaciones. El mercado de la 23 también, aunque ya es distinto. Y Don Rafael, que sube la cortina desde el 86.", "¿Qué lugares nuevos valen la pena?": "Almacén 27 — una bodega reconvertida en librería, abrió en marzo. Y Estudio Norte, que ya tiene dos años pero sigue sintiéndose nuevo. La colonia está en ese momento.", }; const FALLBACK_RESPONSES = [ "Eso habría que ir a verlo. La colonia tiene más respuestas en la calle que en cualquier pantalla.", "No tengo la respuesta exacta, pero el mapa vivo tiene capas para eso — busca por hora del día.", "Esa pregunta merece una caminata. Te sugiero empezar por la 25 Poniente y ver qué encuentras.", ]; function getResponse(query) { const exact = GUIDE_RESPONSES[query]; if (exact) return exact; // Partial keyword match const lower = query.toLowerCase(); if (lower.includes("café") || lower.includes("cafe") || lower.includes("mañana")) return GUIDE_RESPONSES["¿Qué cafés tienen buena luz?"]; if (lower.includes("trabajo") || lower.includes("trabajar") || lower.includes("wifi") || lower.includes("cowork")) return GUIDE_RESPONSES["¿Dónde puedo trabajar tranquilo?"]; if (lower.includes("clásico") || lower.includes("antiguo") || lower.includes("años")) return GUIDE_RESPONSES["¿Qué negocios clásicos siguen vivos?"]; if (lower.includes("nuevo") || lower.includes("apertura") || lower.includes("abrió")) return GUIDE_RESPONSES["¿Qué lugares nuevos valen la pena?"]; // Default return FALLBACK_RESPONSES[Math.floor(Math.random() * FALLBACK_RESPONSES.length)]; } const SUGGESTIONS = [ "¿Dónde puedo trabajar tranquilo?", "¿Qué cafés tienen buena luz?", "¿Qué negocios clásicos siguen vivos?", "¿Qué lugares nuevos valen la pena?", ]; function EMChatbot() { const [open, setOpen] = useChat(false); const [value, setValue] = useChat(""); const [msgs, setMsgs] = useChat([]); const [typing, setTyping] = useChat(false); const threadRef = useChatRef(null); // Scroll thread to bottom whenever messages change useChatEffect(() => { if (threadRef.current) { threadRef.current.scrollTop = threadRef.current.scrollHeight; } }, [msgs, typing]); function send(text) { const q = (text || value).trim(); if (!q) return; setValue(""); const userMsg = { role: "user", text: q }; setMsgs(prev => [...prev, userMsg]); setTyping(true); // Simulate guide composing a reply — 900–1400ms delay const delay = 900 + Math.random() * 500; setTimeout(() => { setTyping(false); setMsgs(prev => [...prev, { role: "guide", text: getResponse(q) }]); }, delay); } if (!open) { return (
¿Qué estás buscando hoy en El Mirador?
) : (