riseup-squad18/MEDICONNECT 2/AGENDAMENTO-SLOTS-API.md
guisilvagomes 6b9bfbbd29 feat: implementa sistema de agendamento com API de slots
- Adiciona Edge Function para calcular slots disponíveis
- Implementa método callFunction() no apiClient para Edge Functions
- Atualiza appointmentService com getAvailableSlots() e create()
- Simplifica AgendamentoConsulta removendo lógica manual de slots
- Remove arquivos de teste e documentação temporária
- Atualiza README com documentação completa
- Adiciona AGENDAMENTO-SLOTS-API.md com detalhes da implementação
- Corrige formatação de dados (telefone, CPF, nomes)
- Melhora diálogos de confirmação e feedback visual
- Otimiza performance e user experience
2025-10-30 12:56:52 -03:00

279 lines
6.2 KiB
Markdown

# 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<GetAvailableSlotsResponse> {
const response = await apiClient.post<GetAvailableSlotsResponse>(
"/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<Appointment> {
const payload = {
...data,
duration_minutes: data.duration_minutes || 30,
appointment_type: data.appointment_type || "presencial",
status: "requested",
};
const response = await apiClient.post<Appointment[]>(
"/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