import React, { useState, useEffect } from 'react'; import { Filter, MessageSquare, UserPlus, CheckCircle, X, Loader2, Plus, ChevronDown } from 'lucide-react'; import { HybridBackend } from '../services/backend.ts'; import { Lead, Dentista } from '../types.ts'; import { useHybridBackend } from '../hooks/useHybridBackend.ts'; import { useToast } from '../contexts/ToastContext.tsx'; const LoadingSpinner = () => (
); const ErrorDisplay = ({ error }: { error: Error }) => (
ERRO AO CARREGAR LEADS: {error.message}
); const NovoLeadModal: React.FC<{ onClose: () => void; onSaved: () => void }> = ({ onClose, onSaved }) => { const toast = useToast(); const [form, setForm] = useState({ nome: '', sobrenome: '', whatsapp: '', tipoInteresse: 'Particular' }); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, [onClose]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!form.nome || !form.whatsapp) { toast.error('PREENCHA NOME E WHATSAPP.'); return; } try { await HybridBackend.saveLead({ ...form, status: 'Novo', dataCadastro: new Date().toISOString(), } as any); toast.success('LEAD CADASTRADO!'); onSaved(); onClose(); } catch { toast.error('ERRO AO CADASTRAR LEAD.'); } }; return (

CADASTRAR NOVO LEAD

setForm(f => ({ ...f, nome: e.target.value.toUpperCase() }))} className="w-full mt-1 border border-gray-300 rounded-lg p-2.5 text-sm font-semibold uppercase-input" placeholder="NOME" required />
setForm(f => ({ ...f, sobrenome: e.target.value.toUpperCase() }))} className="w-full mt-1 border border-gray-300 rounded-lg p-2.5 text-sm font-semibold uppercase-input" placeholder="SOBRENOME" />
setForm(f => ({ ...f, whatsapp: e.target.value }))} className="w-full mt-1 border border-gray-300 rounded-lg p-2.5 text-sm" placeholder="(XX) XXXXX-XXXX" required />
); }; import { PageHeader } from '../components/PageHeader.tsx'; export const LeadsView: React.FC = () => { const { data: leads, isLoading, error, refresh } = useHybridBackend(HybridBackend.getLeads); const { data: dentistas } = useHybridBackend(HybridBackend.getDentistas); const [isConvertModalOpen, setIsConvertModalOpen] = useState(false); const [isNovoLeadOpen, setIsNovoLeadOpen] = useState(false); const [selectedLead, setSelectedLead] = useState(null); const [convData, setConvData] = useState(''); const [convHora, setConvHora] = useState(''); const [convDentista, setConvDentista] = useState(''); const [converting, setConverting] = useState(false); const [filterStatus, setFilterStatus] = useState('TODOS'); const [isFilterOpen, setIsFilterOpen] = useState(false); const toast = useToast(); // Effect to handle Esc key to close modal useEffect(() => { if (!isConvertModalOpen) return; const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape') { setIsConvertModalOpen(false); } }; document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('keydown', handleKeyDown); }; }, [isConvertModalOpen]); const handleConvert = async (e: React.FormEvent) => { e.preventDefault(); if (!selectedLead || converting) return; setConverting(true); try { const r = await HybridBackend.converterLead(selectedLead.id, { data: convData || undefined, hora: convHora || undefined, dentistaId: convDentista || (dentistas && dentistas[0]?.id) || undefined, }); if (r && r.success === false) { toast.error(r.message || 'FALHA AO CONVERTER LEAD.'); return; } toast.success(`${selectedLead.nome.toUpperCase()} CONVERTIDO EM PACIENTE${r.agendamentoId ? ' E AGENDADO' : ''}.`); setIsConvertModalOpen(false); setConvData(''); setConvHora(''); setConvDentista(''); refresh(); } catch { toast.error("FALHA AO CONVERTER LEAD."); } finally { setConverting(false); } }; const filterOptions = ['TODOS', 'NOVO', 'CONVERTIDO']; const filteredLeads = leads?.filter(lead => { if (filterStatus === 'TODOS') return true; return lead.status?.toUpperCase() === filterStatus; }); return (
{/* Filter Dropdown */}
{isFilterOpen && (
{filterOptions.map(opt => ( ))}
)}
{/* New Lead Button */}
{isLoading && } {error && } {filteredLeads && filteredLeads.map(lead => (
{lead.status === 'Novo' && (
)}

{lead.nome} {lead.sobrenome}

{lead.whatsapp}

{lead.tipoInteresse}
CADASTRADO EM: {new Date(lead.dataCadastro).toLocaleDateString()}
{lead.status !== 'Convertido' ? ( ) : (
CONVERTIDO
)}
))} {filteredLeads?.length === 0 && !isLoading && (
NENHUM LEAD ENCONTRADO.
)}
{isConvertModalOpen && selectedLead && (

CONVERTER LEAD

AO SALVAR, O SISTEMA IRÁ AUTOMATICAMENTE CADASTRAR O PACIENTE E CRIAR O AGENDAMENTO.
setConvData(e.target.value)} className="w-full border border-gray-300 rounded-lg p-2.5 font-semibold" />
setConvHora(e.target.value)} className="w-full border border-gray-300 rounded-lg p-2.5 font-semibold" />

Sem data/hora, o lead vira paciente sem agendamento (você marca depois).

)} {isNovoLeadOpen && ( setIsNovoLeadOpen(false)} onSaved={refresh} /> )}
); };