# Sistema de Agendamento com API de Slots ## Implementação Concluída ✅ ### Fluxo de Agendamento 1. **Usuário seleciona médico** → Mostra calendário 2. **Usuário seleciona data** → Chama API de slots disponíveis 3. **API calcula horários** → Considera: - Disponibilidade do médico (agenda configurada) - Exceções (bloqueios e horários extras) - Antecedência mínima para agendamento - Consultas já agendadas 4. **Usuário seleciona horário** e preenche motivo 5. **Sistema cria agendamento** → Salva no banco --- ## APIs Implementadas ### 1. Calcular Slots Disponíveis **Endpoint**: `POST /functions/v1/get-available-slots` **Request**: ```json { "doctor_id": "uuid-do-medico", "date": "2025-10-30" } ``` **Response**: ```json { "slots": [ { "time": "09:00", "available": true }, { "time": "09:30", "available": false }, { "time": "10:00", "available": true } ] } ``` **Código Implementado**: ```typescript // src/services/appointments/appointmentService.ts async getAvailableSlots(data: GetAvailableSlotsInput): Promise { const response = await apiClient.post( "/functions/v1/get-available-slots", data ); return response.data; } ``` --- ### 2. Criar Agendamento **Endpoint**: `POST /rest/v1/appointments` **Request**: ```json { "doctor_id": "uuid-do-medico", "patient_id": "uuid-do-paciente", "scheduled_at": "2025-10-30T09:00:00Z", "duration_minutes": 30, "appointment_type": "presencial", "chief_complaint": "Consulta de rotina", "created_by": "uuid-do-usuario" } ``` **Response**: ```json { "id": "uuid-do-agendamento", "order_number": "APT-2025-0001", "status": "requested", ... } ``` **Código Implementado**: ```typescript // src/services/appointments/appointmentService.ts async create(data: CreateAppointmentInput): Promise { const payload = { ...data, duration_minutes: data.duration_minutes || 30, appointment_type: data.appointment_type || "presencial", status: "requested", }; const response = await apiClient.post( "/rest/v1/appointments", payload, { headers: { Prefer: "return=representation", }, } ); return response.data[0]; } ``` --- ## Componente AgendamentoConsulta ### Principais Melhorias #### Antes ❌ - Calculava slots manualmente no frontend - Precisava carregar disponibilidade + exceções separadamente - Lógica complexa de validação no cliente - Não considerava antecedência mínima - Não verificava consultas já agendadas #### Depois ✅ - Usa Edge Function para calcular slots - API retorna apenas horários realmente disponíveis - Validações centralizadas no backend - Considera todas as regras de negócio - Performance melhorada (menos requisições) ### Código Simplificado ```typescript // src/components/AgendamentoConsulta.tsx const calculateAvailableSlots = useCallback(async () => { if (!selectedDate || !selectedMedico) { setAvailableSlots([]); return; } try { const dateStr = format(selectedDate, "yyyy-MM-dd"); // Chama a Edge Function const response = await appointmentService.getAvailableSlots({ doctor_id: selectedMedico.id, date: dateStr, }); if (response && response.slots) { // Filtra apenas slots disponíveis const available = response.slots .filter((slot) => slot.available) .map((slot) => slot.time); setAvailableSlots(available); } else { setAvailableSlots([]); } } catch (error) { console.error("Erro ao buscar slots:", error); setAvailableSlots([]); } }, [selectedDate, selectedMedico]); const confirmAppointment = async () => { if (!selectedMedico || !selectedDate || !selectedTime || !user) return; try { const scheduledAt = format(selectedDate, "yyyy-MM-dd") + "T" + selectedTime + ":00Z"; // Cria o agendamento const appointment = await appointmentService.create({ patient_id: user.id, doctor_id: selectedMedico.id, scheduled_at: scheduledAt, duration_minutes: 30, appointment_type: appointmentType === "online" ? "telemedicina" : "presencial", chief_complaint: motivo, }); console.log("Consulta criada:", appointment); setBookingSuccess(true); } catch (error) { setBookingError(error.message); } }; ``` --- ## Tipos TypeScript ```typescript // src/services/appointments/types.ts export interface GetAvailableSlotsInput { doctor_id: string; date: string; // YYYY-MM-DD } export interface TimeSlot { time: string; // HH:MM (ex: "09:00") available: boolean; } export interface GetAvailableSlotsResponse { slots: TimeSlot[]; } export interface CreateAppointmentInput { patient_id: string; doctor_id: string; scheduled_at: string; // ISO 8601 duration_minutes?: number; appointment_type?: "presencial" | "telemedicina"; chief_complaint?: string; patient_notes?: string; insurance_provider?: string; } ``` --- ## Benefícios da Implementação ✅ **Performance**: Menos requisições ao backend ✅ **Confiabilidade**: Validações centralizadas ✅ **Manutenibilidade**: Lógica de negócio no servidor ✅ **Escalabilidade**: Edge Functions são otimizadas ✅ **UX**: Interface mais responsiva e clara ✅ **Segurança**: Validações no backend não podem ser burladas --- ## Próximos Passos (Opcional) - [ ] Adicionar loading states mais detalhados - [ ] Implementar cache de slots (evitar chamadas repetidas) - [ ] Adicionar retry automático em caso de falha - [ ] Mostrar motivo quando slot não está disponível - [ ] Implementar notificações (SMS/Email) após agendamento --- ## Testando ### 1. Selecione um médico ### 2. Selecione uma data futura ### 3. Verifique os slots disponíveis ### 4. Selecione um horário ### 5. Preencha o motivo ### 6. Confirme o agendamento **Logs no Console**: ``` [AppointmentService] Buscando slots para: {doctor_id, date} [AppointmentService] Slots recebidos: 12 slots [AppointmentService] Criando agendamento... [AppointmentService] Consulta criada: {id, order_number, ...} ``` --- ## Data de Implementação **30 de Outubro de 2025** Implementado por: GitHub Copilot Revisado por: Equipe RiseUp Squad 18