// Animated corporate chat between colaboradores.
// Reused on hero AND in section 6 (the full demo).
const COLABS = [
{ id: 'director', name: 'Director General', role: 'Coordina', color: '#1B3A6B', initial: 'D' },
{ id: 'mkt', name: 'Marketing', role: 'Contenido', color: '#7C3AED', initial: 'M' },
{ id: 'analitica',name: 'Analítica', role: 'Métricas', color: '#0EA5E9', initial: 'A' },
{ id: 'soporte', name: 'Atención', role: 'Soporte', color: '#14B8A6', initial: 'S' },
{ id: 'logistica',name: 'Logística', role: 'Reparto', color: '#E8620A', initial: 'L' },
{ id: 'inventario',name:'Inventario', role: 'Catálogo', color: '#A16207', initial: 'I' },
];
const COLAB_BY = Object.fromEntries(COLABS.map(c => [c.id, c]));
// Script for the chat demo — designed to feel like the team is actually working
const CHAT_SCRIPT = [
{ who: 'mkt', text: 'Listos los 3 posts para esta semana. Adjunto imágenes generadas.', attach: 'imagen', delay: 1100 },
{ who: 'analitica', text: 'El miércoles 7pm es el mejor horario según métricas de las últimas 4 semanas.', delay: 1400 },
{ who: 'logistica', text: 'Coordinando entrega #142 — cliente confirmó dirección.', delay: 1300 },
{ who: 'director', text: 'Recibido. Programo publicación al miércoles 7pm y envío al dueño para aprobación.', tagOwner: true, delay: 1500 },
{ who: 'soporte', text: 'Tres consultas resueltas en los últimos 20 min. CSAT 4.9.', delay: 1300 },
{ who: 'inventario',text: 'Detecté 2 productos sin descripción SEO. Redactando.', delay: 1300 },
];
function Avatar({ c, size = 28 }) {
return (
{c.initial}
);
}
function TypingDots({ color = '#94A3B8' }) {
return (
{[0,1,2].map(i => (
))}
);
}
function ChatMessage({ msg, isLast, typing }) {
const c = COLAB_BY[msg.who];
return (
{c.name}
{c.role}
ahora
{msg.text}
{msg.tagOwner && (
@dueño
)}
{msg.attach === 'imagen' && (
{[0,1,2].map(i => (
IMG {i+1}
))}
)}
{isLast && typing && (
escribiendo…
)}
);
}
// Full chat window (used in section 6)
function ChatWindow({ compact = false, brandName = 'AI Company' }) {
const printing = typeof document !== 'undefined' && document.body.classList.contains('printing');
const [visible, setVisible] = React.useState(printing ? CHAT_SCRIPT.length : 1);
const [typing, setTyping] = React.useState(!printing);
const scrollRef = React.useRef(null);
React.useEffect(() => {
if (printing) return; // no animation in print
let stopped = false;
let to;
const step = () => {
setTyping(true);
to = setTimeout(() => {
if (stopped) return;
setTyping(false);
setVisible(v => {
const next = v >= CHAT_SCRIPT.length ? 1 : v + 1;
return next;
});
to = setTimeout(step, 450);
}, CHAT_SCRIPT[visible % CHAT_SCRIPT.length]?.delay || 1200);
};
step();
return () => { stopped = true; clearTimeout(to); };
}, [visible]);
React.useEffect(() => {
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
}, [visible, typing]);
return (
{/* Window chrome */}
# general — {brandName}
6 en línea
{/* Messages */}
{CHAT_SCRIPT.slice(0, visible).map((m, i) => (
))}
{/* Composer (decorative) */}
);
}
// Compact "activity dock" used inside hero (sleeker than full chat)
function ActivityDock({ brandName = 'AI Company' }) {
const items = [
{ c: COLAB_BY.mkt, text: 'Redactando post para Instagram', progress: 64 },
{ c: COLAB_BY.logistica, text: 'Coordinando entrega #142', progress: 88 },
{ c: COLAB_BY.analitica, text: 'Optimizando campaña Meta Ads', progress: 42 },
{ c: COLAB_BY.soporte, text: 'Resolviendo 3 tickets', progress: 71 },
];
const [tick, setTick] = React.useState(0);
React.useEffect(() => {
const i = setInterval(() => setTick(t => t + 1), 1400);
return () => clearInterval(i);
}, []);
return (
Equipo activo · {brandName}
en vivo
{items.map((it, i) => {
const prog = Math.min(100, (it.progress + tick * 3) % 110);
return (
{it.c.name}
{Math.round(prog)}%
{it.text}
);
})}
);
}
Object.assign(window, { ChatWindow, ActivityDock, Avatar, COLABS, COLAB_BY });