2025-10-20 21:49:35 -03:00

191 lines
7.2 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Eye, Edit, Calendar, Trash2 } from "lucide-react";
import { pacientesApi, Patient } from "@/services/pacientesApi";
import { PatientDetailsModal } from "@/components/ui/patient-details-modal";
import { toast } from "@/hooks/use-toast";
export default function PacientesPage() {
const [pacientes, setPacientes] = useState<Patient[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [selectedPatient, setSelectedPatient] = useState<Patient | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage] = useState(10);
const handleOpenModal = (patient: Patient) => {
setSelectedPatient(patient);
setIsModalOpen(true);
};
const handleCloseModal = () => {
setSelectedPatient(null);
setIsModalOpen(false);
};
const formatDate = (dateString?: string) => {
if (!dateString) return "N/A";
try {
const date = new Date(dateString);
return new Intl.DateTimeFormat('pt-BR').format(date);
} catch {
return "Data inválida";
}
};
const handleDelete = async (patientId: string) => {
if (!confirm("Tem certeza que deseja excluir este paciente?")) return;
try {
await pacientesApi.delete(patientId);
setPacientes(prevPacientes => prevPacientes.filter(p => p.id !== patientId));
toast({
title: "Sucesso",
description: "Paciente excluído com sucesso.",
});
} catch (err: any) {
toast({
title: "Erro",
description: err.message || "Não foi possível excluir o paciente.",
variant: "destructive",
});
}
};
useEffect(() => {
const fetchPacientes = async () => {
setIsLoading(true);
setError(null);
try {
const data = await pacientesApi.list();
setPacientes(data || []);
} catch (e: any) {
setError(e?.message || "Erro ao carregar pacientes");
console.error(e);
} finally {
setIsLoading(false);
}
};
fetchPacientes();
}, []);
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = pacientes.slice(indexOfFirstItem, indexOfLastItem);
const totalPages = Math.ceil(pacientes.length / itemsPerPage);
const paginate = (pageNumber: number) => setCurrentPage(pageNumber);
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold text-foreground">Pacientes</h1>
<p className="text-muted-foreground">Lista de pacientes vinculados</p>
</div>
<div className="bg-card rounded-lg border border-border">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-muted border-b border-border">
<tr>
<th className="text-left p-4 font-medium text-foreground">Nome</th>
<th className="text-left p-4 font-medium text-foreground">Telefone</th>
<th className="text-left p-4 font-medium text-foreground">Cidade</th>
<th className="text-left p-4 font-medium text-foreground">Estado</th>
<th className="text-left p-4 font-medium text-foreground">Último atendimento</th>
<th className="text-left p-4 font-medium text-foreground">Próximo atendimento</th>
<th className="text-left p-4 font-medium text-foreground">Ações</th>
</tr>
</thead>
<tbody>
{isLoading ? (
<tr>
<td colSpan={7} className="p-6 text-center text-muted-foreground">
Carregando pacientes...
</td>
</tr>
) : error ? (
<tr>
<td colSpan={7} className="p-6 text-center text-red-600">{`Erro: ${error}`}</td>
</tr>
) : currentItems.length === 0 ? (
<tr>
<td colSpan={7} className="p-8 text-center text-muted-foreground">
Nenhum paciente encontrado
</td>
</tr>
) : (
currentItems.map((p) => (
<tr key={p.id} className="border-b border-border hover:bg-accent">
<td className="p-4">{p.full_name}</td>
<td className="p-4 text-muted-foreground">{p.phone_mobile}</td>
<td className="p-4 text-muted-foreground">{p.city}</td>
<td className="p-4 text-muted-foreground">{p.state}</td>
<td className="p-4 text-muted-foreground">{formatDate(p.created_at)}</td>
<td className="p-4 text-muted-foreground">N/A</td>
<td className="p-4">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="text-primary hover:underline">Ações</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => handleOpenModal(p)}>
<Eye className="w-4 h-4 mr-2" />
Ver detalhes
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href={`/doctor/pacientes/${p.id}/laudos`}>
<Edit className="w-4 h-4 mr-2" />
Laudos
</Link>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => alert(`Agenda para paciente ID: ${p.id}`)}>
<Calendar className="w-4 h-4 mr-2" />
Ver agenda
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleDelete(p.id)}
className="text-red-600">
<Trash2 className="w-4 h-4 mr-2" />
Excluir
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
{pacientes.length > itemsPerPage && (
<div className="flex justify-center space-x-2 mt-4 p-4">
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => paginate(i + 1)}
className={`px-4 py-2 rounded-md ${currentPage === i + 1 ? 'bg-primary text-primary-foreground' : 'bg-secondary text-secondary-foreground'}`}
>
{i + 1}
</button>
))}
</div>
)}
</div>
<PatientDetailsModal
patient={selectedPatient}
isOpen={isModalOpen}
onClose={handleCloseModal}
/>
</div>
);
}