From 23e0765c5b7fd9754c351c3c48ef34fd964f3b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo?= <166467972+JoaoGustavo-dev@users.noreply.github.com> Date: Sat, 18 Oct 2025 14:52:26 -0300 Subject: [PATCH] add-list-appointments-endpoints --- .../app/(main-routes)/consultas/page.tsx | 414 ++++++++++-------- susconecta/lib/api.ts | 35 ++ 2 files changed, 269 insertions(+), 180 deletions(-) diff --git a/susconecta/app/(main-routes)/consultas/page.tsx b/susconecta/app/(main-routes)/consultas/page.tsx index 47365d8..ebdc9ad 100644 --- a/susconecta/app/(main-routes)/consultas/page.tsx +++ b/susconecta/app/(main-routes)/consultas/page.tsx @@ -1,7 +1,7 @@ "use client"; import Link from "next/link"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { MoreHorizontal, PlusCircle, @@ -10,6 +10,7 @@ import { Edit, Trash2, ArrowLeft, + Loader2, } from "lucide-react"; import { Badge } from "@/components/ui/badge"; @@ -53,10 +54,10 @@ import { SelectValue, } from "@/components/ui/select"; -import { mockAppointments, mockProfessionals } from "@/lib/mocks/appointment-mocks"; +import { mockProfessionals } from "@/lib/mocks/appointment-mocks"; +import { listarAgendamentos, buscarPacientesPorIds, buscarMedicosPorIds } from "@/lib/api"; import { CalendarRegistrationForm } from "@/components/forms/calendar-registration-form"; - const formatDate = (date: string | Date) => { if (!date) return ""; return new Date(date).toLocaleDateString("pt-BR", { @@ -69,37 +70,41 @@ const formatDate = (date: string | Date) => { }; const capitalize = (s: string) => { - if (typeof s !== 'string' || s.length === 0) return ''; - return s.charAt(0).toUpperCase() + s.slice(1); + if (typeof s !== "string" || s.length === 0) return ""; + return s.charAt(0).toUpperCase() + s.slice(1); }; export default function ConsultasPage() { - const [appointments, setAppointments] = useState(mockAppointments); + const [appointments, setAppointments] = useState([]); + const [isLoading, setIsLoading] = useState(true); const [showForm, setShowForm] = useState(false); const [editingAppointment, setEditingAppointment] = useState(null); const [viewingAppointment, setViewingAppointment] = useState(null); const mapAppointmentToFormData = (appointment: any) => { - const professional = mockProfessionals.find(p => p.id === appointment.professional); - const appointmentDate = new Date(appointment.time); - + const professional = mockProfessionals.find((p) => p.id === appointment.professional); + const appointmentDate = new Date(appointment.time || appointment.scheduled_at || Date.now()); + return { - id: appointment.id, - patientName: appointment.patient, - professionalName: professional ? professional.name : '', - appointmentDate: appointmentDate.toISOString().split('T')[0], - startTime: appointmentDate.toTimeString().split(' ')[0].substring(0, 5), - endTime: new Date(appointmentDate.getTime() + appointment.duration * 60000).toTimeString().split(' ')[0].substring(0, 5), - status: appointment.status, - appointmentType: appointment.type, - notes: appointment.notes, - cpf: '', - rg: '', - birthDate: '', - phoneCode: '+55', - phoneNumber: '', - email: '', - unit: 'nei', + id: appointment.id, + patientName: appointment.patient, + professionalName: professional ? professional.name : "", + appointmentDate: appointmentDate.toISOString().split("T")[0], + startTime: appointmentDate.toTimeString().split(" ")[0].substring(0, 5), + endTime: new Date(appointmentDate.getTime() + (appointment.duration || 30) * 60000) + .toTimeString() + .split(" ")[0] + .substring(0, 5), + status: appointment.status, + appointmentType: appointment.type, + notes: appointment.notes || "", + cpf: "", + rg: "", + birthDate: "", + phoneCode: "+55", + phoneNumber: "", + email: "", + unit: "nei", }; }; @@ -114,7 +119,7 @@ export default function ConsultasPage() { setEditingAppointment(formData); setShowForm(true); }; - + const handleView = (appointment: any) => { setViewingAppointment(appointment); }; @@ -125,40 +130,116 @@ export default function ConsultasPage() { }; const handleSave = (formData: any) => { - const updatedAppointment = { - id: formData.id, - patient: formData.patientName, - time: new Date(`${formData.appointmentDate}T${formData.startTime}`).toISOString(), - duration: 30, - type: formData.appointmentType as any, - status: formData.status as any, - professional: appointments.find(a => a.id === formData.id)?.professional || '', - notes: formData.notes, + id: formData.id, + patient: formData.patientName, + time: new Date(`${formData.appointmentDate}T${formData.startTime}`).toISOString(), + duration: 30, + type: formData.appointmentType as any, + status: formData.status as any, + professional: appointments.find((a) => a.id === formData.id)?.professional || "", + notes: formData.notes, }; - setAppointments(prev => - prev.map(a => a.id === updatedAppointment.id ? updatedAppointment : a) - ); - handleCancel(); + setAppointments((prev) => prev.map((a) => (a.id === updatedAppointment.id ? updatedAppointment : a))); + handleCancel(); }; + useEffect(() => { + let mounted = true; + + async function load() { + try { + const arr = await listarAgendamentos("select=*&order=scheduled_at.desc&limit=200"); + if (!mounted) return; + + // Collect unique patient_ids and doctor_ids + const patientIds = new Set(); + const doctorIds = new Set(); + for (const a of arr || []) { + if (a.patient_id) patientIds.add(String(a.patient_id)); + if (a.doctor_id) doctorIds.add(String(a.doctor_id)); + } + + // Batch fetch patients and doctors + const patientsMap = new Map(); + const doctorsMap = new Map(); + + try { + if (patientIds.size) { + const list = await buscarPacientesPorIds(Array.from(patientIds)); + for (const p of list || []) patientsMap.set(String(p.id), p); + } + } catch (e) { + console.warn("[ConsultasPage] Falha ao buscar pacientes em lote", e); + } + + try { + if (doctorIds.size) { + const list = await buscarMedicosPorIds(Array.from(doctorIds)); + for (const d of list || []) doctorsMap.set(String(d.id), d); + } + } catch (e) { + console.warn("[ConsultasPage] Falha ao buscar médicos em lote", e); + } + + // Map appointments using the maps + const mapped = (arr || []).map((a: any) => { + const patient = a.patient_id ? patientsMap.get(String(a.patient_id))?.full_name || String(a.patient_id) : ""; + const professional = a.doctor_id ? doctorsMap.get(String(a.doctor_id))?.full_name || String(a.doctor_id) : ""; + return { + id: a.id, + patient, + time: a.scheduled_at || a.created_at || "", + duration: a.duration_minutes || 30, + type: a.appointment_type || "presencial", + status: a.status || "requested", + professional, + notes: a.notes || a.patient_notes || "", + }; + }); + + setAppointments(mapped); + setIsLoading(false); + } catch (err) { + console.warn("[ConsultasPage] Falha ao carregar agendamentos, usando mocks", err); + setAppointments([]); + setIsLoading(false); + } + } + + load(); + return () => { + mounted = false; + }; + }, []); + + // editing view: render the calendar registration form with controlled data if (showForm && editingAppointment) { + const [localForm, setLocalForm] = useState(editingAppointment); + const onFormChange = (d: any) => setLocalForm(d); + + const saveLocal = () => { + handleSave(localForm); + }; + return ( -
-
- -

Editar Consulta

-
- +
+
+ +

Editar Consulta

- ) + +
+ + +
+
+ ); } return ( @@ -172,9 +253,7 @@ export default function ConsultasPage() {
@@ -183,17 +262,11 @@ export default function ConsultasPage() { Consultas Agendadas - - Visualize, filtre e gerencie todas as consultas da clínica. - + Visualize, filtre e gerencie todas as consultas da clínica.
- +