import { useState, useMemo, useEffect } from 'react'; import { useNavigate, Link } from 'react-router-dom'; import { XerticaAssistant, generateDemoResponse } from 'xertica-ui/assistant'; import { useLayout } from 'xertica-ui/hooks'; import { Header } from 'xertica-ui/layout'; import { useTranslation } from 'react-i18next'; import { Button, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, } from 'xertica-ui/ui'; import { AppLayout } from '../app/components/AppLayout'; import { ArrowLeft, Plus, MessageSquare, Trash2, FileEdit } from 'lucide-react'; // ─── Types ─────────────────────────────────────────────────────────────────── interface ChatMessage { id: string; type: 'user' | 'assistant'; content: string; timestamp: Date; } interface Conversation { id: string; label: string; group: 'hoje' | 'ontem' | 'semana'; messages: ChatMessage[]; } // ─── Data ──────────────────────────────────────────────────────────────────── const d = (offsetMinutes: number) => { const t = new Date(); t.setMinutes(t.getMinutes() - offsetMinutes); return t; }; const INITIAL_CONVERSATIONS: Conversation[] = [ { id: 'conversa-1', label: 'Análise de dados de vendas Q1', group: 'hoje', messages: [ { id: 'm1', type: 'user', content: 'Preciso de uma análise dos dados de vendas do primeiro trimestre. Tivemos crescimento em algumas regiões mas queda em outras.', timestamp: d(60), }, { id: 'm2', type: 'assistant', content: 'Com base nos dados do Q1, identifiquei os seguintes padrões:\n\n**Regiões com crescimento:**\n- Sudeste: +18% comparado ao Q1 do ano anterior\n- Sul: +12%\n\n**Regiões com queda:**\n- Norte: -8%\n- Nordeste: -4%\n\nO crescimento no Sudeste foi impulsionado principalmente pelo aumento no ticket médio (+22%), enquanto a queda no Norte está correlacionada com a redução de representantes comerciais ativos na região. Recomendo aumentar a cobertura comercial no Norte e Nordeste para o Q2.', timestamp: d(58), }, { id: 'm3', type: 'user', content: 'Que ações específicas você recomenda para o Norte?', timestamp: d(55), }, { id: 'm4', type: 'assistant', content: 'Para reverter a queda no Norte, recomendo:\n\n1. **Contratar 2 representantes regionais** focados nos estados do Pará e Amazonas\n2. **Programa de incentivo para distribuidores locais** com bonificação por volume trimestral\n3. **Campanhas segmentadas** com preços ajustados ao poder aquisitivo regional\n4. **Visitas presenciais quinzenais** nos 5 maiores clientes da região\n\nEssas ações têm potencial de recuperar 6-8% das vendas já no Q2.', timestamp: d(53), }, ], }, { id: 'conversa-2', label: 'Relatório de performance mensal', group: 'hoje', messages: [ { id: 'm1', type: 'user', content: 'Gera um relatório de performance do time de engenharia para o mês de abril.', timestamp: d(120), }, { id: 'm2', type: 'assistant', content: '# Relatório de Performance — Abril\n\n**Time de Engenharia**\n\n## Entregas\n- 42 tarefas concluídas (meta: 38) ✅\n- 3 sprints fechados dentro do prazo\n- Velocity médio: 87 pontos/sprint\n\n## Qualidade\n- Taxa de bugs em produção: 0,8% (melhora de 0,3pp vs março)\n- Cobertura de testes: 78%\n- Tempo médio de resolução de incidentes: 2h 15min\n\n## Destaques\n- Deploy do módulo de relatórios avançados (2 semanas antes do prazo)\n- Redução de 40% no tempo de build do pipeline\n\n## Pontos de atenção\n- Dívida técnica no módulo de autenticação precisa de endereçamento no Q2', timestamp: d(118), }, ], }, { id: 'conversa-3', label: 'Resumo das reuniões da semana', group: 'ontem', messages: [ { id: 'm1', type: 'user', content: 'Resume as principais decisões tomadas nas reuniões desta semana.', timestamp: d(1440 + 60), }, { id: 'm2', type: 'assistant', content: '## Decisões da Semana\n\n**Segunda — Planejamento Q2**\n- Meta de receita: R$ 4,2M (+15% vs Q1)\n- Novo produto B2B entra em beta em junho\n- Contratação de 3 devs aprovada para maio\n\n**Quarta — Review de Produto**\n- Funcionalidade de relatórios vai para produção na sexta\n- UX do onboarding será redesenhado (kickoff em 15/05)\n- Integração com ERP do cliente Alfa postergada para julho\n\n**Sexta — All Hands**\n- Empresa atingiu 500 clientes ativos 🎉\n- Novo programa de equity para colaboradores aprovado pelo board\n- Hackathon interno marcado para 20-21 de junho', timestamp: d(1440 + 58), }, { id: 'm3', type: 'user', content: 'Quando é o kickoff do redesign de UX exatamente?', timestamp: d(1440 + 50), }, { id: 'm4', type: 'assistant', content: 'O kickoff do redesign do onboarding está marcado para **15 de maio**, conforme decidido na reunião de Review de Produto de quarta-feira. O time de produto e design estará presente, e foi solicitado que o lead de engenharia frontend também participe.', timestamp: d(1440 + 48), }, ], }, { id: 'conversa-4', label: 'Dashboard de projetos ativos', group: 'ontem', messages: [ { id: 'm1', type: 'user', content: 'Quais projetos estão ativos agora e qual o status de cada um?', timestamp: d(1440 + 180), }, { id: 'm2', type: 'assistant', content: '## Projetos Ativos\n\n| Projeto | Status | Prazo | Responsável |\n|---|---|---|---|\n| Portal do Cliente | 🟢 No prazo | 30/05 | Ana Costa |\n| Integração ERP | 🟡 Em risco | 15/05 | Bruno Lima |\n| App Mobile v2 | 🟢 No prazo | 30/06 | Carla Melo |\n| Redesign Onboarding | 🔵 Iniciando | 30/07 | Diana Park |\n| API Pública v3 | 🟡 Em risco | 01/06 | Eduardo Cruz |\n\n**Projetos em risco:** A Integração ERP está aguardando credenciais do cliente Alfa há 10 dias. A API v3 tem bloqueio técnico na autenticação OAuth que precisa de decisão arquitetural.', timestamp: d(1440 + 178), }, ], }, { id: 'conversa-5', label: 'Análise de churn de clientes', group: 'ontem', messages: [ { id: 'm1', type: 'user', content: 'Analisa o churn do mês passado. Tivemos 12 cancelamentos.', timestamp: d(1440 + 300), }, { id: 'm2', type: 'assistant', content: '## Análise de Churn — Abril\n\n**12 cancelamentos** representam uma taxa de churn de **2,4%** (base de 500 clientes).\n\n### Principais motivos\n1. Preço / custo-benefício — 5 clientes (42%)\n2. Migração para concorrente — 4 clientes (33%)\n3. Encerramento do negócio — 2 clientes (17%)\n4. Insatisfação com suporte — 1 cliente (8%)\n\n### Perfil dos churned\n- Plano Basic: 8 (67%)\n- Plano Pro: 3 (25%)\n- Plano Enterprise: 1 (8%)\n\n**Insight:** A concentração no plano Basic sugere que o preço de renovação anual está sendo percebido como alto para clientes nesse tier. Recomendo revisar a proposta de valor ou criar um plano intermediário.', timestamp: d(1440 + 298), }, ], }, { id: 'conversa-6', label: 'Proposta comercial Projeto Alpha', group: 'semana', messages: [ { id: 'm1', type: 'user', content: 'Precisa de ajuda para montar a proposta comercial para o Projeto Alpha. É um cliente enterprise do setor de logística.', timestamp: d(3 * 1440), }, { id: 'm2', type: 'assistant', content: 'Para um cliente enterprise de logística, estruturo a proposta nos seguintes blocos:\n\n**1. Contexto e Desafios**\nIdentificar os 3 principais pain points do cliente (rastreamento, gestão de frotas, custo operacional).\n\n**2. Solução Proposta**\nDetalhar os módulos relevantes para logística: dashboard de rotas, alertas em tempo real, relatórios de KPI operacional.\n\n**3. Modelo Comercial**\n- Licença Enterprise: R$ 8.500/mês\n- Implementação e customização: R$ 45.000 (único)\n- SLA garantido: 99,9% uptime com suporte 24/7\n\n**4. ROI Estimado**\nRedução de 15-20% em custo operacional no primeiro ano.\n\n**5. Próximos Passos**\nPiloto de 30 dias sem custo para validar integração com sistema legado.\n\nDeseja que eu elabore alguma seção específica?', timestamp: d(3 * 1440 - 2), }, ], }, { id: 'conversa-7', label: 'KPIs do time de engenharia', group: 'semana', messages: [ { id: 'm1', type: 'user', content: 'Quais KPIs devo acompanhar para o time de engenharia?', timestamp: d(4 * 1440), }, { id: 'm2', type: 'assistant', content: '## KPIs Essenciais — Time de Engenharia\n\n**Velocidade e Entrega**\n- Velocity (pontos/sprint)\n- Lead time (do commit ao deploy)\n- Frequência de deploy\n- Taxa de conclusão de sprint\n\n**Qualidade**\n- Taxa de bugs em produção\n- Cobertura de testes (%)\n- MTTR — Mean Time to Recovery\n- Change failure rate\n\n**Saúde do Time**\n- Dívida técnica (story points estimados)\n- Satisfação do time (eNPS)\n- Tempo médio de code review\n\n**Negócio**\n- Tempo de entrega de features (time-to-market)\n- Uptime do sistema\n- Custo por deploy\n\nRecomendo começar com 5-7 KPIs no máximo para não sobrecarregar o processo de coleta.', timestamp: d(4 * 1440 - 2), }, ], }, { id: 'conversa-8', label: 'Planejamento de sprint Q2', group: 'semana', messages: [ { id: 'm1', type: 'user', content: 'Me ajuda a planejar o Q2. Temos 3 sprints de 2 semanas cada.', timestamp: d(5 * 1440), }, { id: 'm2', type: 'assistant', content: '## Planejamento Q2 — 3 Sprints\n\n**Sprint 1 (01–14/mai)**\n- Finalizar módulo de relatórios avançados\n- Correções críticas de UX do onboarding\n- Setup da infraestrutura para o App Mobile v2\n\n**Sprint 2 (15–28/mai)**\n- Kickoff do redesign de onboarding\n- Início da API Pública v3\n- Integração com ERP (depende de credenciais do cliente)\n\n**Sprint 3 (29/mai–11/jun)**\n- Beta fechado do App Mobile v2\n- Estabilização da API v3\n- Testes de carga e segurança\n\n**Capacidade estimada:** 85 pontos/sprint × 3 = 255 pontos no Q2\n\nSugestão: reserve 15% da capacidade de cada sprint para bugs e dívida técnica.', timestamp: d(5 * 1440 - 2), }, ], }, ]; // ─── Component ─────────────────────────────────────────────────────────────── export function AssistantPage() { const navigate = useNavigate(); const { t } = useTranslation(); const { sidebarExpanded, setSidebarExpanded } = useLayout(); const [conversations, setConversations] = useState(INITIAL_CONVERSATIONS); const [selectedId, setSelectedId] = useState(null); const [searchValue, setSearchValue] = useState(''); const [deleteTarget, setDeleteTarget] = useState(null); const [renameTarget, setRenameTarget] = useState(null); const [renameValue, setRenameValue] = useState(''); useEffect(() => { if (!sidebarExpanded) setSidebarExpanded(true); }, [sidebarExpanded, setSidebarExpanded]); const selectedConversation = conversations.find(c => c.id === selectedId) ?? null; const GROUP_CONFIG = useMemo( () => [ { id: 'hoje', label: t('assistant.page.today') }, { id: 'ontem', label: t('assistant.page.yesterday') }, { id: 'semana', label: t('assistant.page.thisWeek') }, ], [t] ); const richSuggestions = useMemo( () => [ { id: 'chart-1', text: t('assistant.richSuggestions.viewPerformance') }, { id: 'table-1', text: t('assistant.richSuggestions.generateReport') }, { id: 'doc-1', text: t('assistant.richSuggestions.createDocument') }, { id: 'pod-1', text: t('assistant.richSuggestions.generatePodcast') }, ], [t] ); const feedbackOptions = useMemo( () => [ t('assistant.feedback.notWhatIWanted'), t('assistant.feedback.incorrectInfo'), t('assistant.feedback.incompleteAnswer'), ], [t] ); const navigationGroups = useMemo(() => { const query = searchValue.toLowerCase(); return GROUP_CONFIG.map(group => ({ id: group.id, label: group.label, icon: MessageSquare, items: conversations .filter(c => c.group === group.id) .filter(c => !query || c.label.toLowerCase().includes(query)) .map(c => ({ path: `/assistente/${c.id}`, label: c.label, actions: [ { label: t('assistant.page.rename'), icon: FileEdit, onClick: () => { setRenameTarget(c); setRenameValue(c.label); }, }, { label: t('assistant.page.delete'), icon: Trash2, onClick: () => setDeleteTarget(c), variant: 'destructive' as const, }, ], })), })).filter(g => g.items.length > 0); }, [conversations, searchValue, GROUP_CONFIG, t]); const handleSelectConversation = (path: string) => { if (path.startsWith('/assistente/')) { setSelectedId(path.replace('/assistente/', '')); } else { navigate(path); } }; const handleDelete = () => { if (!deleteTarget) return; setConversations(prev => prev.filter(c => c.id !== deleteTarget.id)); if (selectedId === deleteTarget.id) setSelectedId(null); setDeleteTarget(null); }; const handleRename = () => { if (!renameTarget || !renameValue.trim()) return; setConversations(prev => prev.map(c => (c.id === renameTarget.id ? { ...c, label: renameValue.trim() } : c)) ); setRenameTarget(null); }; const sidebarProps = { width: 320, fixedArea: { show: true, icon: Plus, onClick: () => setSelectedId(null), content: ( ), }, search: { show: true, placeholder: t('assistant.page.searchConversations'), value: searchValue, onChange: setSearchValue, }, navigationGroups, location: { pathname: selectedId ? `/assistente/${selectedId}` : '/assistente' }, navigate: handleSelectConversation, }; return ( <>
} actions={[ { id: 'back', label: t('assistant.back'), icon: , onClick: () => navigate('/home'), className: 'bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground', }, ]} />
navigate('/settings')} onEvaluation={(messageId, type, reason) => { console.log( `Avaliação recebida: ${type} na mensagem ${messageId}. Motivo: ${reason}` ); }} />
{/* Modal: Excluir conversa */} !open && setDeleteTarget(null)}> {t('assistant.page.deleteConversationTitle')} {t('assistant.page.deleteConversationDesc', { name: deleteTarget?.label })} {t('assistant.page.cancel')} {t('assistant.page.delete')} {/* Modal: Renomear conversa */} !open && setRenameTarget(null)}> {t('assistant.page.renameConversationTitle')}
setRenameValue(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleRename()} autoFocus />
); }