forked from RiseUP/riseup-squad21
191 lines
7.2 KiB
TypeScript
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>
|
|
);
|
|
} |