"use client"; import { useEffect, useMemo, useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { MoreHorizontal, Plus, Search, Eye, Edit, Trash2, ArrowLeft } from "lucide-react"; import { Paciente, Endereco, listarPacientes, buscarPacientes, buscarPacientePorId, excluirPaciente } from "@/lib/api"; import { PatientRegistrationForm } from "@/components/features/forms/patient-registration-form"; import AssignmentForm from "@/components/features/admin/AssignmentForm"; function normalizePaciente(p: any): Paciente { return { id: String(p.id ?? p.uuid ?? p.paciente_id ?? ""), full_name: p.full_name ?? p.name ?? p.nome ?? "", social_name: p.social_name ?? p.nome_social ?? null, cpf: p.cpf ?? "", rg: p.rg ?? p.document_number ?? null, sex: p.sex ?? p.sexo ?? null, birth_date: p.birth_date ?? p.data_nascimento ?? null, phone_mobile: p.phone_mobile ?? p.telefone ?? "", email: p.email ?? "", cep: p.cep ?? "", street: p.street ?? p.logradouro ?? "", number: p.number ?? p.numero ?? "", complement: p.complement ?? p.complemento ?? "", neighborhood: p.neighborhood ?? p.bairro ?? "", city: p.city ?? p.cidade ?? "", state: p.state ?? p.estado ?? "", notes: p.notes ?? p.observacoes ?? null, }; } export default function PacientesPage() { const [patients, setPatients] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [search, setSearch] = useState(""); const [showForm, setShowForm] = useState(false); const [editingId, setEditingId] = useState(null); const [viewingPatient, setViewingPatient] = useState(null); const [assignDialogOpen, setAssignDialogOpen] = useState(false); const [assignPatientId, setAssignPatientId] = useState(null); // Paginação const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage, setItemsPerPage] = useState(10); async function loadAll() { try { setLoading(true); const data = await listarPacientes({ page: 1, limit: 50 }); if (Array.isArray(data)) { setPatients(data.map(normalizePaciente)); } else { setPatients([]); } setError(null); } catch (e: any) { setPatients([]); setError(e?.message || "Erro ao carregar pacientes."); } finally { setLoading(false); } } useEffect(() => { loadAll(); }, []); const filtered = useMemo(() => { if (!search.trim()) return patients; const q = search.toLowerCase().trim(); const qDigits = q.replace(/\D/g, ""); return patients.filter((p) => { // Busca por nome const byName = (p.full_name || "").toLowerCase().includes(q); // Busca por CPF (remove formatação) const byCPF = qDigits.length >= 3 && (p.cpf || "").replace(/\D/g, "").includes(qDigits); // Busca por ID (UUID completo ou parcial) const byId = (p.id || "").toLowerCase().includes(q); // Busca por email const byEmail = (p.email || "").toLowerCase().includes(q); return byName || byCPF || byId || byEmail; }); }, [patients, search]); // Dados paginados const paginatedData = useMemo(() => { const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; return filtered.slice(startIndex, endIndex); }, [filtered, currentPage, itemsPerPage]); const totalPages = Math.ceil(filtered.length / itemsPerPage); // Reset para página 1 quando mudar a busca ou itens por página useEffect(() => { setCurrentPage(1); }, [search, itemsPerPage]); function handleAdd() { setEditingId(null); setShowForm(true); } function handleEdit(id: string) { setEditingId(id); setShowForm(true); } function handleView(patient: Paciente) { setViewingPatient(patient); } async function handleDelete(id: string) { if (!confirm("Excluir este paciente?")) return; try { await excluirPaciente(id); setPatients((prev) => prev.filter((x) => String(x.id) !== String(id))); } catch (e: any) { alert(e?.message || "Não foi possível excluir."); } } function handleSaved(p: Paciente) { const saved = normalizePaciente(p); setPatients((prev) => { const i = prev.findIndex((x) => String(x.id) === String(saved.id)); if (i < 0) return [saved, ...prev]; const clone = [...prev]; clone[i] = saved; return clone; }); setShowForm(false); } async function handleBuscarServidor() { const q = search.trim(); if (!q) return loadAll(); try { setLoading(true); setError(null); // Se parece com ID (UUID), busca diretamente if (q.includes('-') && q.length > 10) { const one = await buscarPacientePorId(q); setPatients(one ? [normalizePaciente(one)] : []); setError(one ? null : "Paciente não encontrado."); // Limpa o campo de busca para que o filtro não interfira setSearch(""); return; } // Para outros termos, usa busca avançada const results = await buscarPacientes(q); setPatients(results.map(normalizePaciente)); setError(results.length === 0 ? "Nenhum paciente encontrado." : null); // Limpa o campo de busca para que o filtro não interfira setSearch(""); } catch (e: any) { setPatients([]); setError(e?.message || "Erro na busca."); } finally { setLoading(false); } } if (loading) return

Carregando pacientes...

; if (error) return

{error}

; if (showForm) { return (

{editingId ? "Editar paciente" : "Novo paciente"}

setShowForm(false)} />
); } return (

Pacientes

Gerencie os pacientes

setSearch(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleBuscarServidor()} />
Nome CPF Telefone Cidade Estado Ações {paginatedData.length > 0 ? ( paginatedData.map((p) => ( {p.full_name || "(sem nome)"} {p.cpf || "-"} {p.phone_mobile || "-"} {p.city || "-"} {p.state || "-"} handleView(p)}> Ver handleEdit(String(p.id))}> Editar handleDelete(String(p.id))} className="text-destructive"> Excluir { setAssignPatientId(String(p.id)); setAssignDialogOpen(true); }}> Atribuir profissional )) ) : ( Nenhum paciente encontrado )}
{/* Controles de paginação */}
Itens por página: Mostrando {paginatedData.length > 0 ? (currentPage - 1) * itemsPerPage + 1 : 0} a{" "} {Math.min(currentPage * itemsPerPage, filtered.length)} de {filtered.length}
Página {currentPage} de {totalPages || 1}
{viewingPatient && ( setViewingPatient(null)}> Detalhes do Paciente Informações detalhadas de {viewingPatient.full_name}.
{viewingPatient.full_name}
{viewingPatient.cpf}
{viewingPatient.phone_mobile}
{`${viewingPatient.street || ''}, ${viewingPatient.number || ''} - ${viewingPatient.neighborhood || ''}, ${viewingPatient.city || ''} - ${viewingPatient.state || ''}`}
{viewingPatient.notes || "Nenhuma"}
)} {/* Assignment dialog */} {assignDialogOpen && assignPatientId && ( { setAssignDialogOpen(false); setAssignPatientId(null); }} onSaved={() => { setAssignDialogOpen(false); setAssignPatientId(null); loadAll(); }} /> )}
); }