diff --git a/app/secretary/appointments/page.tsx b/app/secretary/appointments/page.tsx index 2687690..282dec5 100644 --- a/app/secretary/appointments/page.tsx +++ b/app/secretary/appointments/page.tsx @@ -8,132 +8,145 @@ import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Calendar, Clock, MapPin, Phone, CalendarDays, X, User } from "lucide-react"; +import { Calendar, Clock, MapPin, Phone, User, Trash2, Pencil } from "lucide-react"; import { toast } from "sonner"; import Link from "next/link"; - -const APPOINTMENTS_STORAGE_KEY = "clinic-appointments"; - -const initialAppointments = [ - { - id: 1, - patientName: "Carlos Pereira", - doctor: "Dr. João Silva", - specialty: "Cardiologia", - date: "2024-01-15", - time: "14:30", - status: "agendada", - location: "Consultório A - 2º andar", - phone: "(11) 3333-4444", - }, - { - id: 2, - patientName: "Ana Beatriz Costa", - doctor: "Dra. Maria Santos", - specialty: "Dermatologia", - date: "2024-01-22", - time: "10:00", - status: "agendada", - location: "Consultório B - 1º andar", - phone: "(11) 3333-5555", - }, - { - id: 3, - patientName: "Roberto Almeida", - doctor: "Dr. Pedro Costa", - specialty: "Ortopedia", - date: "2024-01-08", - time: "16:00", - status: "realizada", - location: "Consultório C - 3º andar", - phone: "(11) 3333-6666", - }, - { - id: 4, - patientName: "Fernanda Lima", - doctor: "Dra. Ana Lima", - specialty: "Ginecologia", - date: "2024-01-05", - time: "09:30", - status: "realizada", - location: "Consultório D - 2º andar", - phone: "(11) 3333-7777", - }, -]; +import { appointmentsService } from "@/services/appointmentsApi.mjs"; +import { patientsService } from "@/services/patientsApi.mjs"; +import { doctorsService } from "@/services/doctorsApi.mjs"; export default function SecretaryAppointments() { const [appointments, setAppointments] = useState([]); - const [rescheduleModal, setRescheduleModal] = useState(false); - const [cancelModal, setCancelModal] = useState(false); + const [isLoading, setIsLoading] = useState(true); const [selectedAppointment, setSelectedAppointment] = useState(null); - const [rescheduleData, setRescheduleData] = useState({ date: "", time: "", reason: "" }); - const [cancelReason, setCancelReason] = useState(""); + + // Estados dos Modais + const [deleteModal, setDeleteModal] = useState(false); + const [editModal, setEditModal] = useState(false); + + // Estado para o formulário de edição + const [editFormData, setEditFormData] = useState({ + date: "", + time: "", + status: "", + }); + + const fetchData = async () => { + setIsLoading(true); + try { + const [appointmentList, patientList, doctorList] = await Promise.all([ + appointmentsService.list(), + patientsService.list(), + doctorsService.list(), + ]); + + const patientMap = new Map(patientList.map((p: any) => [p.id, p])); + const doctorMap = new Map(doctorList.map((d: any) => [d.id, d])); + + const enrichedAppointments = appointmentList.map((apt: any) => ({ + ...apt, + patient: patientMap.get(apt.patient_id) || { full_name: "Paciente não encontrado" }, + doctor: doctorMap.get(apt.doctor_id) || { full_name: "Médico não encontrado", specialty: "N/A" }, + })); + + setAppointments(enrichedAppointments); + } catch (error) { + console.error("Falha ao buscar agendamentos:", error); + toast.error("Não foi possível carregar a lista de agendamentos."); + } finally { + setIsLoading(false); + } + }; useEffect(() => { - const storedAppointments = localStorage.getItem(APPOINTMENTS_STORAGE_KEY); - if (storedAppointments) { - setAppointments(JSON.parse(storedAppointments)); - } else { - setAppointments(initialAppointments); - localStorage.setItem(APPOINTMENTS_STORAGE_KEY, JSON.stringify(initialAppointments)); - } + fetchData(); }, []); - const updateAppointments = (updatedAppointments: any[]) => { - setAppointments(updatedAppointments); - localStorage.setItem(APPOINTMENTS_STORAGE_KEY, JSON.stringify(updatedAppointments)); - }; - - const handleReschedule = (appointment: any) => { + // --- LÓGICA DE EDIÇÃO --- + const handleEdit = (appointment: any) => { setSelectedAppointment(appointment); - setRescheduleData({ date: "", time: "", reason: "" }); - setRescheduleModal(true); + const appointmentDate = new Date(appointment.scheduled_at); + + setEditFormData({ + date: appointmentDate.toISOString().split('T')[0], + time: appointmentDate.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit', timeZone: 'UTC' }), + status: appointment.status, + }); + setEditModal(true); }; - const handleCancel = (appointment: any) => { - setSelectedAppointment(appointment); - setCancelReason(""); - setCancelModal(true); - }; - - const confirmReschedule = () => { - if (!rescheduleData.date || !rescheduleData.time) { - toast.error("Por favor, selecione uma nova data e horário"); + const confirmEdit = async () => { + if (!selectedAppointment || !editFormData.date || !editFormData.time || !editFormData.status) { + toast.error("Todos os campos são obrigatórios para a edição."); return; } - const updated = appointments.map((apt) => (apt.id === selectedAppointment.id ? { ...apt, date: rescheduleData.date, time: rescheduleData.time } : apt)); - updateAppointments(updated); - setRescheduleModal(false); - toast.success("Consulta reagendada com sucesso!"); - }; - const confirmCancel = () => { - if (!cancelReason.trim() || cancelReason.trim().length < 10) { - toast.error("O motivo do cancelamento é obrigatório e deve ter no mínimo 10 caracteres."); - return; + try { + const newScheduledAt = new Date(`${editFormData.date}T${editFormData.time}:00Z`).toISOString(); + const updatePayload = { + scheduled_at: newScheduledAt, + status: editFormData.status, + }; + + await appointmentsService.update(selectedAppointment.id, updatePayload); + + setAppointments(prevAppointments => + prevAppointments.map(apt => + apt.id === selectedAppointment.id ? { ...apt, scheduled_at: newScheduledAt, status: editFormData.status } : apt + ) + ); + + setEditModal(false); + toast.success("Consulta atualizada com sucesso!"); + + } catch (error) { + console.error("Erro ao atualizar consulta:", error); + toast.error("Não foi possível atualizar a consulta."); } - const updated = appointments.map((apt) => (apt.id === selectedAppointment.id ? { ...apt, status: "cancelada" } : apt)); - updateAppointments(updated); - setCancelModal(false); - toast.success("Consulta cancelada com sucesso!"); }; + // --- LÓGICA DE DELEÇÃO --- + const handleDelete = (appointment: any) => { + setSelectedAppointment(appointment); + setDeleteModal(true); + }; + + const confirmDelete = async () => { + if (!selectedAppointment) return; + try { + await appointmentsService.delete(selectedAppointment.id); + setAppointments((prev) => prev.filter((apt) => apt.id !== selectedAppointment.id)); + setDeleteModal(false); + toast.success("Consulta deletada com sucesso!"); + } catch (error) { + console.error("Erro ao deletar consulta:", error); + toast.error("Não foi possível deletar a consulta."); + } + }; + + // ** FUNÇÃO CORRIGIDA E MELHORADA ** const getStatusBadge = (status: string) => { switch (status) { - case "agendada": - return Agendada; - case "realizada": + case "requested": + return Solicitada; + case "confirmed": + return Confirmada; + case "checked_in": + return Check-in; + case "completed": return Realizada; - case "cancelada": + case "cancelled": return Cancelada; + case "no_show": + return Não Compareceu; default: return {status}; } }; const timeSlots = ["08:00", "08:30", "09:00", "09:30", "10:00", "10:30", "11:00", "11:30", "14:00", "14:30", "15:00", "15:30", "16:00", "16:30", "17:00", "17:30"]; + const appointmentStatuses = ["requested", "confirmed", "checked_in", "completed", "cancelled", "no_show"]; return ( @@ -144,22 +157,19 @@ export default function SecretaryAppointments() {

Gerencie as consultas dos pacientes

- +
- {appointments.length > 0 ? ( + {isLoading ?

Carregando consultas...

: appointments.length > 0 ? ( appointments.map((appointment) => (
- {appointment.doctor} - {appointment.specialty} + {appointment.doctor.full_name} + {appointment.doctor.specialty}
{getStatusBadge(appointment.status)}
@@ -169,41 +179,39 @@ export default function SecretaryAppointments() {
- {appointment.patientName} + {appointment.patient.full_name}
- {new Date(appointment.date).toLocaleDateString("pt-BR", { timeZone: "UTC" })} + {new Date(appointment.scheduled_at).toLocaleDateString("pt-BR", { timeZone: "UTC" })}
- {appointment.time} + {new Date(appointment.scheduled_at).toLocaleTimeString("pt-BR", { hour: '2-digit', minute: '2-digit', timeZone: "UTC" })}
- {appointment.location} + {appointment.doctor.location || "Local a definir"}
- {appointment.phone} + {appointment.doctor.phone || "N/A"}
- {appointment.status === "agendada" && ( -
- - -
- )} +
+ + +
)) @@ -213,68 +221,58 @@ export default function SecretaryAppointments() { - + {/* MODAL DE EDIÇÃO */} + - Reagendar Consulta - Reagendar consulta com {selectedAppointment?.doctor} para {selectedAppointment?.patientName} + Editar Consulta + + Altere os dados da consulta de {selectedAppointment?.patient.full_name}. +
- setRescheduleData((prev) => ({ ...prev, date: e.target.value }))} min={new Date().toISOString().split("T")[0]} /> + setEditFormData(prev => ({ ...prev, date: e.target.value }))} min={new Date().toISOString().split("T")[0]} />
- setEditFormData(prev => ({ ...prev, time: value }))}> + - {timeSlots.map((time) => ( - - {time} - - ))} + {timeSlots.map((time) => ({time}))}
- -