// Caririaçu Guincho — Motoristas + Seguradoras Screens const { useState: useStateM, useEffect: useEffectMC } = React; // ── Modal de Detalhes do Motorista ─────────────────────────────────────── const MotoristaDetailModal = ({ motorista, onClose, onEdit, onToggleStatus }) => { const [assistencias, setAssist] = useStateM([]); const [frotaInfo, setFrotaInfo] = useStateM({}); useEffectMC(() => { if (!motorista) return; db.list('assistencias', { eq: { motorista_id: motorista.id }, order: 'data' }).then(setAssist); if (motorista.guincho_code) { db.list('frota', { eq: { code: motorista.guincho_code } }).then(rows => setFrotaInfo(rows[0] || {})); } else setFrotaInfo({}); }, [motorista?.id]); if (!motorista) return null; const sc = { disponivel: { bg: 'linear-gradient(135deg,#10B981 0%,#059669 100%)', label: 'Disponível' }, atendimento: { bg: 'linear-gradient(135deg,#F59E0B 0%,#D97706 100%)', label: 'Em Atendimento' }, inativo: { bg: 'linear-gradient(135deg,#64748B 0%,#475569 100%)', label: 'Inativo' }, }[motorista.status] || { bg: 'linear-gradient(135deg,#3B82F6 0%,#2563EB 100%)', label: motorista.status }; const faturamento = assistencias.filter(a => a.status === 'finalizada').reduce((s,a) => s + Number(a.valor || 0), 0); const finalizadas = assistencias.filter(a => a.status === 'finalizada').length; const taxa = assistencias.length > 0 ? Math.round(finalizadas / assistencias.length * 100) : 0; const venc = motorista.venc_cnh ? new Date(motorista.venc_cnh) : null; const hoje = new Date(); const diasParaVenc = venc ? Math.ceil((venc - hoje) / (1000 * 60 * 60 * 24)) : null; const cnhAlerta = diasParaVenc !== null && diasParaVenc < 90; const KpiCard = ({ icon, label, value, color, sub }) => (
{label}
{value}
{sub &&
{sub}
}
); const InfoBlock = ({ icon, title, color, children, full }) => (
{title}
{children}
); const Field = ({ label, value, mono, color }) => (
{label}
{value || '—'}
); return (
{motorista.avatar || motorista.nome.split(' ').map(w => w[0]).join('').slice(0,2).toUpperCase()}
{motorista.nome}
{motorista.telefone || '—'} {motorista.guincho_code || '—'}
Status
{sc.label}
0 ? `${diasParaVenc} dias` : `vencida há ${-diasParaVenc} dias`) : '—'} />
0 ? 'Regular' : 'Vencida') : '—'} color={diasParaVenc !== null && diasParaVenc > 0 ? '#10B981' : '#EF4444'} />
{cnhAlerta && diasParaVenc > 0 && (
CNH vence em {diasParaVenc} dias — providenciar renovação
)}
{frotaInfo.placa ? (
) : (
Sem guincho vinculado
)}
Taxa de Finalização {taxa}%
Volume de Atendimentos {assistencias.length}
Assistências recentes {assistencias.length} registros
{assistencias.length === 0 ? (
Nenhuma assistência vinculada a este motorista.
) : ( {['Nº','Data','Cliente','Serviço','Valor','Status'].map(h => ( ))} {assistencias.map((a,i) => ( ))}
{h}
{a.numero || `#${a.id}`} {new Date(a.data).toLocaleDateString('pt-BR')} {a.cliente} {a.servico} R$ {Number(a.valor).toFixed(2)}
)}
motorista.telefone ? window.location.href = `tel:${motorista.telefone}` : showToast('Sem telefone cadastrado','warning')}>Ligar
{motorista.status === 'inativo' ? 'Ativar' : 'Inativar'} Editar
); }; const MotoristasScreen = () => { const [motoristas, setMotoristas] = useStateM([]); const [loading, setLoading] = useStateM(true); const [modal, setModal] = useStateM(false); const [editItem, setEditItem] = useStateM(null); const [detailItem, setDetailItem] = useStateM(null); const [busca, setBusca] = useStateM(''); const [form, setForm] = useStateM({ nome: '', telefone: '', cpf: '', cnh: '', categoria: 'E', venc_cnh: '', status: 'disponivel' }); const set = (k, v) => setForm(f => ({ ...f, [k]: v })); const refresh = async () => { setLoading(true); setMotoristas(await db.list('motoristas', { order: 'nome', asc: true })); setLoading(false); }; useEffectMC(() => { refresh(); }, []); const filtered = motoristas.filter(m => !busca || m.nome.toLowerCase().includes(busca.toLowerCase())); const openNew = () => { setEditItem(null); setForm({ nome: '', telefone: '', cpf: '', cnh: '', categoria: 'E', venc_cnh: '', status: 'disponivel' }); setModal(true); }; const openEdit = (item) => { setEditItem(item); setForm({ nome: item.nome, telefone: item.telefone || '', cpf: item.cpf || '', cnh: item.cnh || '', categoria: item.categoria || 'E', venc_cnh: item.venc_cnh || '', status: item.status }); setModal(true); }; const handleSave = async () => { if (!form.nome) { showToast('Informe o nome', 'warning'); return; } const av = form.nome.split(' ').map(w => w[0]).join('').slice(0,2).toUpperCase(); const payload = { ...form, avatar: av, venc_cnh: form.venc_cnh || null }; if (editItem) { const updated = await db.update('motoristas', editItem.id, payload); if (updated) { showToast('Motorista atualizado!', 'success'); refresh(); } } else { const created = await db.insert('motoristas', payload); if (created) { showToast('Motorista cadastrado!', 'success'); refresh(); } } setModal(false); }; const toggleStatus = async (m) => { const novoStatus = m.status === 'inativo' ? 'disponivel' : 'inativo'; const updated = await db.update('motoristas', m.id, { status: novoStatus }); if (updated) { showToast('Status atualizado!', 'success'); refresh(); } }; return (

Motoristas

{motoristas.length} motoristas · {motoristas.filter(m=>m.status==='disponivel').length} disponíveis
Novo Motorista
{[ { label: 'Disponíveis', val: motoristas.filter(m=>m.status==='disponivel').length, color: '#10B981' }, { label: 'Em Atendimento', val: motoristas.filter(m=>m.status==='atendimento').length, color: '#F59E0B' }, { label: 'Inativos', val: motoristas.filter(m=>m.status==='inativo').length, color: '#94A3B8' }, { label: 'Total', val: motoristas.length, color: '#3B82F6' }, ].map(s => (
{s.val}
{s.label}
))}
setBusca(e.target.value)} placeholder="Buscar por nome..." style={{ width: '100%', paddingLeft: 34, paddingRight: 12, paddingTop: 9, paddingBottom: 9, borderRadius: 8, border: '1px solid #E2E8F0', fontSize: 13, fontFamily: 'Inter, sans-serif', outline: 'none', boxSizing: 'border-box' }} />
{loading ? (
Carregando...
) : filtered.length === 0 ? (
{motoristas.length === 0 ? 'Nenhum motorista cadastrado' : 'Nenhum resultado'}
{motoristas.length === 0 ? 'Cadastre o primeiro motorista clicando em "Novo Motorista"' : 'Tente outra busca'}
) : (
{['Motorista','Telefone','CNH','Categoria','Venc. CNH','Guincho','Assistências','Status','Ações'].map(h => ( ))} {filtered.map((m, i) => ( setDetailItem(m)} onMouseEnter={e=>e.currentTarget.style.background='#EFF6FF'} onMouseLeave={e=>e.currentTarget.style.background=i%2?'#F8FAFC':'#fff'}> ))}
{h}
w[0]).join('').slice(0,2).toUpperCase()} size={32} /> {m.nome}
{m.telefone || '—'} {m.cnh || '—'} Cat. {m.categoria || '—'} {m.venc_cnh ? new Date(m.venc_cnh).toLocaleDateString('pt-BR') : '—'} {m.guincho_code || '—'} {m.assistencias || 0} e.stopPropagation()}>
)}
setDetailItem(null)} onEdit={() => { const m = detailItem; setDetailItem(null); openEdit(m); }} onToggleStatus={() => { const m = detailItem; setDetailItem(null); toggleStatus(m); }} /> setModal(false)} title={editItem ? 'Editar Motorista' : 'Novo Motorista'} width={520}>
set('nome',e.target.value)} style={{gridColumn:'1/-1'}}/> set('telefone',e.target.value)}/> set('cpf',e.target.value)}/> set('cnh',e.target.value)}/> set('venc_cnh',e.target.value)}/> set('nome',e.target.value)}/>
set('contato',e.target.value)}/> set('telefone',e.target.value)}/>
set('email',e.target.value)}/>