"use client"; import { useState, useEffect, useCallback } from "react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Edit, Trash2, Eye, Calendar, Filter, Loader2, MoreVertical, Phone, MapPin, Activity, ChevronLeft, ChevronRight } from "lucide-react"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { patientsService } from "@/services/patientsApi.mjs"; import Sidebar from "@/components/Sidebar"; export default function PacientesPage() { // --- ESTADOS --- const [searchTerm, setSearchTerm] = useState(""); const [convenioFilter, setConvenioFilter] = useState("all"); const [vipFilter, setVipFilter] = useState("all"); const [allPatients, setAllPatients] = useState([]); const [filteredPatients, setFilteredPatients] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // --- PAGINAÇÃO --- const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(10); const totalPages = Math.ceil(filteredPatients.length / pageSize); const startIndex = (page - 1) * pageSize; const endIndex = startIndex + pageSize; const currentPatients = filteredPatients.slice(startIndex, endIndex); // --- DIALOGS --- const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [patientToDelete, setPatientToDelete] = useState(null); const [detailsDialogOpen, setDetailsDialogOpen] = useState(false); const [patientDetails, setPatientDetails] = useState(null); // --- LÓGICA DE NÚMEROS DA PAGINAÇÃO (LIMITADO A 3) --- const getPageNumbers = () => { const maxVisible = 3; if (totalPages <= maxVisible) { return Array.from({ length: totalPages }, (_, i) => i + 1); } let start = Math.max(1, page - 1); let end = Math.min(totalPages, start + maxVisible - 1); if (end === totalPages) { start = Math.max(1, end - maxVisible + 1); } const pages = []; for (let i = start; i <= end; i++) { pages.push(i); } return pages; }; // --- FETCH DADOS --- const fetchAllPacientes = useCallback(async () => { setLoading(true); setError(null); try { const res = await patientsService.list(); const mapped = res.map((p: any) => ({ id: String(p.id ?? ""), nome: p.full_name ?? "—", telefone: p.phone_mobile ?? p.phone1 ?? "—", cidade: p.city ?? "—", estado: p.state ?? "—", ultimoAtendimento: p.last_visit_at?.split('T')[0] ?? "—", proximoAtendimento: p.next_appointment_at?.split('T')[0] ?? "—", vip: Boolean(p.vip ?? false), convenio: p.convenio ?? "Particular", status: p.status ?? undefined, })); setAllPatients(mapped); } catch (e: any) { console.error(e); setError(e?.message || "Erro ao buscar pacientes"); } finally { setLoading(false); } }, []); useEffect(() => { const filtered = allPatients.filter((patient) => { const matchesSearch = patient.nome?.toLowerCase().includes(searchTerm.toLowerCase()) || patient.telefone?.includes(searchTerm); const matchesConvenio = convenioFilter === "all" || patient.convenio === convenioFilter; const matchesVip = vipFilter === "all" || (vipFilter === "vip" && patient.vip) || (vipFilter === "regular" && !patient.vip); return matchesSearch && matchesConvenio && matchesVip; }); setFilteredPatients(filtered); setPage(1); }, [allPatients, searchTerm, convenioFilter, vipFilter]); useEffect(() => { fetchAllPacientes(); }, []); // --- AÇÕES --- const openDetailsDialog = async (patientId: string) => { setDetailsDialogOpen(true); setPatientDetails(null); try { const res = await patientsService.getById(patientId); setPatientDetails(Array.isArray(res) ? res[0] : res); } catch (e: any) { setPatientDetails({ error: e?.message || "Erro ao buscar detalhes" }); } }; const handleDeletePatient = async (patientId: string) => { try { await patientsService.delete(patientId); setAllPatients((prev) => prev.filter((p) => String(p.id) !== String(patientId))); } catch (e: any) { alert(`Erro ao deletar paciente: ${e?.message || "Erro desconhecido"}`); } setDeleteDialogOpen(false); setPatientToDelete(null); }; const ActionMenu = ({ patientId }: { patientId: string }) => (
openDetailsDialog(String(patientId))}> Ver detalhes Editar Marcar consulta { setPatientToDelete(patientId); setDeleteDialogOpen(true); }}> Excluir
); return (
{/* Header */}

Pacientes

Gerencie as informações de seus pacientes

{/* Filtros */}
setSearchTerm(e.target.value)} className="w-full sm:flex-grow sm:max-w-[300px] p-2 border rounded-md text-sm" />
Convênio
VIP
{/* Loading / Erro / Conteúdo */} {error ? (
{`Erro: ${error}`}
) : loading ? (
Carregando...
) : ( <> {/* LISTA MOBILE */}
{currentPatients.length === 0 ? (
Nenhum paciente encontrado.
) : ( currentPatients.map((patient) => (
{patient.nome?.charAt(0) || "?"}
{patient.nome}{patient.vip && VIP}
{patient.convenio}
{patient.telefone}
{patient.cidade}
Última: {patient.ultimoAtendimento}
)) )}
{/* TABELA DESKTOP */}
{currentPatients.length === 0 ? ( ) : ( currentPatients.map((patient) => ( )) )}
Nome Telefone Cidade / Estado Convênio Último atendimento Próximo atendimento Ações
Nenhum paciente encontrado
{patient.nome?.charAt(0) || "?"}
{patient.nome}{patient.vip && VIP}
{patient.telefone} {`${patient.cidade} / ${patient.estado}`} {patient.convenio} {patient.ultimoAtendimento} {patient.proximoAtendimento}
)} {/* --- RODAPÉ DE PAGINAÇÃO --- */} {totalPages > 1 && !loading && (
{/* 1. PAGINAÇÃO MOBILE (Simples) */}
{page} de {totalPages}
{/* 2. PAGINAÇÃO DESKTOP (Numerada Limitada) */}
{getPageNumbers().map((pageNum) => ( ))}
)} {/* Dialogs */} Confirmar exclusãoTem certeza que deseja excluir este paciente? Cancelar patientToDelete && handleDeletePatient(patientToDelete)} className="bg-destructive hover:bg-destructive/90">Excluir Detalhes do Paciente {patientDetails ? (!patientDetails.error ? (

NOME

{patientDetails.full_name}

EMAIL

{patientDetails.email}

TELEFONE

{patientDetails.phone_mobile}

DATA NASC.

{patientDetails.birth_date}

Endereço

{patientDetails.street}, {patientDetails.number}

{patientDetails.cidade}/{patientDetails.estado}

) :

{patientDetails.error}

) : }
Fechar
); }