"use client"; import Link from "next/link"; import { useEffect, useState } from "react"; import { MoreHorizontal, PlusCircle, Search, Eye, Edit, Trash2, ArrowLeft, Loader2, } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; 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", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", }); }; const capitalize = (s: string) => { if (typeof s !== "string" || s.length === 0) return ""; return s.charAt(0).toUpperCase() + s.slice(1); }; export default function ConsultasPage() { 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 || 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 || 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", }; }; const handleDelete = (appointmentId: string) => { if (window.confirm("Tem certeza que deseja excluir esta consulta?")) { setAppointments((prev) => prev.filter((a) => a.id !== appointmentId)); } }; const handleEdit = (appointment: any) => { const formData = mapAppointmentToFormData(appointment); setEditingAppointment(formData); setShowForm(true); }; const handleView = (appointment: any) => { setViewingAppointment(appointment); }; const handleCancel = () => { setEditingAppointment(null); setShowForm(false); }; 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, }; 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

); } return (

Gerenciamento de Consultas

Visualize, filtre e gerencie todas as consultas da clínica.

Consultas Agendadas Visualize, filtre e gerencie todas as consultas da clínica.
{isLoading ? (
Carregando agendamentos...
) : ( Paciente Médico Status Data e Hora Ações {appointments.map((appointment) => { // appointment.professional may now contain the doctor's name (resolved) const professionalLookup = mockProfessionals.find((p) => p.id === appointment.professional); const professionalName = typeof appointment.professional === "string" && appointment.professional && !professionalLookup ? appointment.professional : (professionalLookup ? professionalLookup.name : (appointment.professional || "Não encontrado")); return ( {appointment.patient} {professionalName} {capitalize(appointment.status)} {formatDate(appointment.time)} handleView(appointment)}> Ver handleEdit(appointment)}> Editar handleDelete(appointment.id)} className="text-destructive"> Excluir ); })}
)}
{viewingAppointment && ( setViewingAppointment(null)}> Detalhes da Consulta Informações detalhadas da consulta de {viewingAppointment?.patient}.
{viewingAppointment?.patient}
{viewingAppointment?.professional || 'Não encontrado'}
{viewingAppointment?.time ? formatDate(viewingAppointment.time) : ''}
{capitalize(viewingAppointment?.status || "")}
{capitalize(viewingAppointment?.type || "")}
{viewingAppointment?.notes || "Nenhuma"}
)}
); }