// Caminho: app/(patient)/schedule/page.tsx (Completo e Corrigido) "use client"; import type React from "react"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { format, getDay } from "date-fns"; import { ptBR } from "date-fns/locale"; // A importação do PatientLayout foi REMOVIDA import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Calendar as CalendarIcon, Clock, User as UserIcon } from "lucide-react"; import { Calendar } from "@/components/ui/calendar"; import { toast } from "sonner"; import { cn } from "@/lib/utils"; import { usuariosApi, User } from "@/services/usuariosApi"; import { medicosApi, Doctor } from "@/services/medicosApi"; import { agendamentosApi } from "@/services/agendamentosApi"; import { disponibilidadeApi, DoctorAvailability, DoctorException } from "@/services/disponibilidadeApi"; interface AvailabilityRules { weekly: DoctorAvailability[]; exceptions: DoctorException[]; } export default function ScheduleAppointment() { const router = useRouter(); const [user, setUser] = useState(null); const [doctors, setDoctors] = useState([]); const [availableSlots, setAvailableSlots] = useState([]); const [availabilityRules, setAvailabilityRules] = useState(null); const [isAvailabilityLoading, setIsAvailabilityLoading] = useState(false); const [formData, setFormData] = useState<{ doctorId: string; date: Date | undefined; time: string; appointmentType: string; duration: string; reason: string; }>({ doctorId: "", date: undefined, time: "", appointmentType: "presencial", duration: "30", reason: "", }); const [isLoading, setIsLoading] = useState(true); const [isSlotsLoading, setIsSlotsLoading] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); useEffect(() => { const loadInitialData = async () => { try { const currentUser = await usuariosApi.getCurrentUser(); setUser(currentUser); let activeDoctors = await medicosApi.list({ active: true }); if (activeDoctors.length === 0) { console.warn("Nenhum médico ativo encontrado. Buscando do mock..."); toast.info("Usando dados de exemplo para a lista de médicos."); activeDoctors = await medicosApi.getMockDoctors(); } setDoctors(activeDoctors); } catch (e) { console.error("Erro ao carregar dados iniciais:", e); setError("Não foi possível carregar os dados necessários para o agendamento."); } finally { setIsLoading(false); } }; loadInitialData(); }, []); useEffect(() => { const fetchDoctorAvailability = async () => { if (!formData.doctorId) { setAvailabilityRules(null); return; } if (formData.doctorId.startsWith("mock-")) { setAvailabilityRules({ weekly: [], exceptions: [] }); return; } setIsAvailabilityLoading(true); try { const [weekly, exceptions] = await Promise.all([ disponibilidadeApi.list({ doctor_id: formData.doctorId, active: true }), disponibilidadeApi.listExceptions({ doctor_id: formData.doctorId }), ]); setAvailabilityRules({ weekly, exceptions }); } catch (err) { console.error("Erro ao buscar disponibilidade do médico:", err); toast.error("Não foi possível carregar a agenda do médico."); setAvailabilityRules(null); } finally { setIsAvailabilityLoading(false); } }; fetchDoctorAvailability(); }, [formData.doctorId]); const fetchAvailableSlots = (doctorId: string, date: Date | undefined) => { if (!doctorId || !date) return; setIsSlotsLoading(true); setAvailableSlots([]); if (doctorId.startsWith("mock-")) { setTimeout(() => { const mockSlots = ["09:00", "10:00", "11:00", "14:00", "15:00"]; setAvailableSlots(mockSlots); setIsSlotsLoading(false); }, 500); return; } const formattedDate = format(date, "yyyy-MM-dd"); agendamentosApi.getAvailableSlots(doctorId, formattedDate) .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.")) .finally(() => setIsSlotsLoading(false)); }; const handleSelectChange = (name: keyof typeof formData) => (value: string | Date | undefined) => { const newFormData = { ...formData, [name]: value } as any; if (name === 'doctorId') { newFormData.date = undefined; newFormData.time = ""; } if (name === 'date') { newFormData.time = ""; fetchAvailableSlots(newFormData.doctorId, newFormData.date); } setFormData(newFormData); }; const handleInputChange = (e: React.ChangeEvent) => { const { id, value } = e.target; setFormData(prev => ({ ...prev, [id]: value })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!user?.id || !formData.date) { toast.error("Erro de autenticação ou data inválida."); return; } if (formData.doctorId.startsWith("mock-")) { toast.success("Simulação de agendamento com médico de exemplo concluída!"); router.push("/patient/appointments"); return; } setIsSubmitting(true); try { const newScheduledAt = new Date(`${format(formData.date, "yyyy-MM-dd")}T${formData.time}:00Z`).toISOString(); await agendamentosApi.create({ doctor_id: formData.doctorId, patient_id: user.id, scheduled_at: newScheduledAt, duration_minutes: parseInt(formData.duration, 10), appointment_type: formData.appointmentType as 'presencial' | 'telemedicina', status: "requested", created_by: user.id, notes: formData.reason, }); toast.success("Consulta agendada com sucesso!"); router.push("/patient/appointments"); } catch (error) { console.error("Erro ao agendar consulta:", error); toast.error("Falha ao agendar a consulta. Tente novamente."); } finally { setIsSubmitting(false); } }; const isDateDisabled = (date: Date): boolean => { if (date < new Date(new Date().setDate(new Date().getDate() - 1))) { return true; } if (!availabilityRules) { return false; } const dateString = format(date, "yyyy-MM-dd"); const dayOfWeek = getDay(date); const fullDayBlock = availabilityRules.exceptions.find( ex => ex.date === dateString && ex.kind === 'bloqueio' && !ex.start_time ); if (fullDayBlock) { return true; } const worksOnThisDay = availabilityRules.weekly.some( avail => avail.weekday === dayOfWeek ); return !worksOnThisDay; }; const selectedDoctorDetails = doctors.find((d) => d.id === formData.doctorId); const isFormInvalid = !formData.doctorId || !formData.date || !formData.time || isSubmitting; return (

Agendar Consulta

Escolha o médico, data e horário para sua consulta

{isLoading ? (

Carregando...

) : error ? (

{error}

) : (
Dados da Consulta Preencha as informações para agendar sua consulta