// Blocos da ficha do cliente no CRM ligados aos registros reais: // - SugestaoCRM: a próxima ação calculada (CRMIndicadores.jsx), com atalho // para virar a "Próxima ação" do cliente. // - NegociosCliente: orçamentos e ações do cliente numa lista só, do mais // recente para o mais antigo. const NEGOCIO_STATUS_COR = { Aprovado: 'success', Enviado: 'warning', 'Em elaboração': 'default', Recusado: 'danger', Cancelado: 'danger', Realizado: 'success', Agendado: 'primary' }; const NEGOCIOS_VISIVEIS = 8; function SugestaoCRM({ sugestao, onUsar }) { if (!sugestao) return null; const cor = { followup: '#C2410C', contato: '#B45309', recuperacao: '#B91C1C' }[sugestao.tipo]; return (
Sugestão do sistema
{sugestao.texto}
{sugestao.detalhe}
Usar como próxima ação
); } function crmDiaBR(iso) { return iso ? new Date(String(iso).slice(0, 10) + 'T00:00:00').toLocaleDateString('pt-BR') : '—'; } function negociosDoCliente(clientId, events, budgets) { const hoje = window.crmHojeISO(); const orcs = budgets.filter(b => b.client_id === clientId).map(b => ({ key: 'b' + b.id, tipo: 'Orçamento', titulo: [b.code, b.event_name].filter(Boolean).join(' · ') || 'Orçamento', data: String(b.aprovado_em || b.created_at || '').slice(0, 10), status: b.status, valor: Number(b.value) || 0, })); const acoes = events.filter(e => e.client_id === clientId).map(e => { const data = String(e.event_date || '').slice(0, 10); const status = e.status === 'Cancelado' ? 'Cancelado' : (data && data <= hoje ? 'Realizado' : 'Agendado'); return { key: 'e' + e.id, tipo: 'Ação', titulo: e.name || 'Evento', data, status, valor: null }; }); return [...orcs, ...acoes].sort((a, b) => b.data.localeCompare(a.data)); } function NegociosCliente({ clientId, events, budgets }) { const [verTodos, setVerTodos] = React.useState(false); const lista = React.useMemo(() => negociosDoCliente(clientId, events, budgets), [clientId, events, budgets]); const visiveis = verTodos ? lista : lista.slice(0, NEGOCIOS_VISIVEIS); const nOrc = lista.filter(x => x.tipo === 'Orçamento').length; return (
Orçamentos e ações
{nOrc} orçamentos · {lista.length - nOrc} ações
{lista.length === 0 ? (
Nenhum orçamento ou evento vinculado a este cliente ainda.
) : ( <> {visiveis.map((n, i) => (
{crmDiaBR(n.data)}
{n.titulo}
{n.tipo}
{n.status} {n.valor !== null &&
R$ {Math.round(n.valor).toLocaleString('pt-BR')}
}
))} {lista.length > NEGOCIOS_VISIVEIS && ( )} )}
); } Object.assign(window, { SugestaoCRM, NegociosCliente });