// Caminho: app/(patient)/appointments/page.tsx (Corrigido e Alinhado com a API Real) "use client"; import type React from "react"; import { useState, useEffect, useCallback } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; 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, X, CalendarDays } from "lucide-react"; import { toast } from "sonner"; import { usuariosApi, User } from "@/services/usuariosApi"; import { agendamentosApi, Appointment } from "@/services/agendamentosApi"; // --- FUNÇÃO AUXILIAR --- const isAppointmentInPast = (scheduledAt: string): boolean => { const now = new Date(); const appointmentDate = new Date(scheduledAt); now.setHours(0, 0, 0, 0); appointmentDate.setHours(0, 0, 0, 0); return appointmentDate < now; }; // --- Componente Reutilizável para o Card de Agendamento --- const AppointmentCard: React.FC<{ appointment: Appointment; onReschedule: (appt: Appointment) => void; onCancel: (appt: Appointment) => void; }> = ({ appointment, onReschedule, onCancel }) => { const getStatusBadge = (status: string): React.ReactNode => { switch (status) { case "requested": return Solicitada; case "confirmed": return Confirmada; case "completed": return Realizada; case "cancelled": return Cancelada; default: return {status}; } }; const isMock = appointment.id.startsWith("mock-"); const isPast = isAppointmentInPast(appointment.scheduled_at); const canBeModified = !isPast && appointment.status !== "cancelled" && appointment.status !== "completed"; return ( {appointment.doctors?.full_name || "Médico não encontrado"} {isMock && (Exemplo)} {appointment.doctors?.specialty || "Especialidade não informada"} {getStatusBadge(appointment.status)} {new Date(appointment.scheduled_at).toLocaleDateString("pt-BR", { timeZone: "UTC" })} {new Date(appointment.scheduled_at).toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit", timeZone: "UTC" })} {appointment.appointment_type === 'telemedicina' ? 'Link da videochamada' : 'Clínica Central - Sala 101'} (11) 99999-9999 {canBeModified && ( onReschedule(appointment)}> Reagendar onCancel(appointment)}> Cancelar )} ); }; // --- Componente Principal da Página --- export default function PatientAppointments() { const [user, setUser] = useState(null); const [appointments, setAppointments] = useState([]); const [isLoading, setIsLoading] = useState(true); const [selectedAppointment, setSelectedAppointment] = useState(null); const [availableSlots, setAvailableSlots] = useState([]); const [isRescheduleModalOpen, setRescheduleModalOpen] = useState(false); const [isCancelModalOpen, setCancelModalOpen] = useState(false); const [rescheduleData, setRescheduleData] = useState({ date: "", time: "", reason: "" }); const [cancelReason, setCancelReason] = useState(""); const fetchData = useCallback(async () => { if (!user?.id) { setIsLoading(false); return; } setIsLoading(true); try { let patientAppointments = await agendamentosApi.listByPatient(user.id); if (patientAppointments.length === 0) { console.warn("Nenhum agendamento encontrado na API real. Buscando do mock..."); toast.info("Usando dados de exemplo para a lista de consultas."); patientAppointments = await agendamentosApi.getMockAppointments(); } setAppointments(patientAppointments); } catch (error) { console.error("Erro ao carregar consultas:", error); toast.error("Não foi possível carregar suas consultas. Tentando usar dados de exemplo."); try { const mockAppointments = await agendamentosApi.getMockAppointments(); setAppointments(mockAppointments); } catch (mockError) { console.error("Falha ao buscar dados do mock:", mockError); setAppointments([]); } } finally { setIsLoading(false); } }, [user?.id]); useEffect(() => { const loadInitialData = async () => { try { const currentUser = await usuariosApi.getCurrentUser(); setUser(currentUser); } catch (error) { console.error("Usuário não autenticado:", error); fetchData(); } }; loadInitialData(); }, [fetchData]); useEffect(() => { if (user) { fetchData(); } }, [user, fetchData]); useEffect(() => { if (rescheduleData.date && selectedAppointment?.doctor_id && selectedAppointment.id.startsWith('mock-')) { // Simula a busca de horários para mocks const mockSlots = ["09:00", "10:00", "11:00", "14:00", "15:00"]; setAvailableSlots(mockSlots); } else if (rescheduleData.date && selectedAppointment?.doctor_id) { agendamentosApi.getAvailableSlots(selectedAppointment.doctor_id, rescheduleData.date) .then(response => { const slots = response.slots.filter(s => s.available).map(s => s.time); setAvailableSlots(slots); }) .catch(() => toast.error("Não foi possível buscar horários para esta data.")); } }, [rescheduleData.date, selectedAppointment?.doctor_id, selectedAppointment?.id]); const handleReschedule = (appointment: Appointment) => { setSelectedAppointment(appointment); setRescheduleData({ date: "", time: "", reason: "" }); setAvailableSlots([]); setRescheduleModalOpen(true); }; const handleCancel = (appointment: Appointment) => { setSelectedAppointment(appointment); setCancelReason(""); setCancelModalOpen(true); }; const confirmReschedule = async () => { if (!selectedAppointment || !rescheduleData.date || !rescheduleData.time) { return toast.error("Por favor, selecione uma nova data e horário."); } const isMock = selectedAppointment.id.startsWith("mock-"); const newScheduledAt = new Date(`${rescheduleData.date}T${rescheduleData.time}:00Z`).toISOString(); if (isMock) { setAppointments(prev => prev.map(apt => apt.id === selectedAppointment.id ? { ...apt, scheduled_at: newScheduledAt, status: "requested" as const } : apt ) ); setRescheduleModalOpen(false); toast.success("Consulta de exemplo reagendada!"); return; } // Lógica para dados reais, informando que a funcionalidade não existe toast.warning("Funcionalidade indisponível.", { description: "A API não possui um endpoint para reagendar consultas." }); setRescheduleModalOpen(false); }; const confirmCancel = async () => { if (!selectedAppointment || cancelReason.trim().length < 10) { return toast.error("Por favor, informe um motivo com no mínimo 10 caracteres."); } const isMock = selectedAppointment.id.startsWith("mock-"); if (isMock) { setAppointments(prev => prev.map(apt => apt.id === selectedAppointment.id ? { ...apt, status: "cancelled" as const } : apt ) ); setCancelModalOpen(false); toast.success("Consulta de exemplo cancelada!"); return; } // Lógica para dados reais, informando que a funcionalidade não existe toast.warning("Funcionalidade indisponível.", { description: "A API não possui um endpoint para cancelar consultas." }); setCancelModalOpen(false); }; return ( Minhas Consultas Veja, reagende ou cancele suas consultas {isLoading ? ( Carregando suas consultas... ) : appointments.length > 0 ? ( appointments.map((appointment) => ( )) ) : ( Você ainda não possui consultas agendadas. )} {/* ... (Modais de Reagendamento e Cancelamento permanecem os mesmos) ... */} ); }
Veja, reagende ou cancele suas consultas
Carregando suas consultas...
Você ainda não possui consultas agendadas.