diff --git a/.env.example b/.env.example
index e62b46e..1b61f48 100644
--- a/.env.example
+++ b/.env.example
@@ -1,4 +1,5 @@
VITE_SUPABASE_URL=https://yuanqfswhberkoevtmfr.supabase.co
+VITE_API_BASE_URL=https://yuanqfswhberkoevtmfr.supabase.co/functions/v1
VITE_SUPABASE_REST_URL=https://yuanqfswhberkoevtmfr.supabase.co/rest/v1
VITE_SUPABASE_FUNCTIONS_URL=https://yuanqfswhberkoevtmfr.supabase.co/functions/v1
VITE_SUPABASE_STORAGE_URL=https://yuanqfswhberkoevtmfr.supabase.co/storage/v1
diff --git a/docs/repository-api-audit.md b/docs/repository-api-audit.md
index 4025e5b..4943b59 100644
--- a/docs/repository-api-audit.md
+++ b/docs/repository-api-audit.md
@@ -1,82 +1,49 @@
-# Auditoria dos repositories contra a API
+# Auditoria de Implementacao e Mapeamento da API
-Fonte da documentacao: https://do5wegrct3.apidog.io/llms.txt
+Este documento resume o estado atual da integracao entre o front-end e os endpoints da API.
-## Endpoints documentados
+## Integrado no front
-| Grupo | Metodo | Endpoint | Status no frontend |
-| --- | --- | --- | --- |
-| Autenticacao | POST | `/auth/v1/token?grant_type=password` | Sem repository dedicado |
-| Autenticacao | POST | `/auth/v1/otp` | Sem repository dedicado |
-| Autenticacao | POST | `/auth/v1/logout` | Sem repository dedicado |
-| Autenticacao | GET | `/auth/v1/user` | Sem repository dedicado; relacionado a `profileRepository` |
-| Usuarios | POST | `/delete-user` | Sem repository dedicado |
-| Usuarios | POST | `/functions/v1/create-user` | Sem repository dedicado |
-| Usuarios | POST | `/functions/v1/create-user-with-password` | Sem repository dedicado |
-| Usuarios | POST | `/request-password-reset` | Sem repository dedicado |
-| Usuarios | POST | `/functions/v1/user-info` | Sem repository dedicado; relacionado a `profileRepository` |
-| Usuarios | POST | `/functions/v1/user-info-by-id` | Sem repository dedicado |
-| SMS | POST | `/functions/v1/send-sms` | `communicationRepository` nao implementa chamada real |
-| Pacientes | GET | `/rest/v1/patients` | Implementado em `patientRepository.getAll` |
-| Pacientes | POST | `/rest/v1/patients` | Implementado em `patientRepository.create` |
-| Pacientes | PATCH | `/rest/v1/patients?id=eq.{id}` | Implementado em `patientRepository.update` |
-| Pacientes | DELETE | `/rest/v1/patients?id=eq.{id}` | Implementado em `patientRepository.remove` |
-| Pacientes | POST | `/functions/v1/create-patient` | Implementado em `patientRepository.createWithValidation` |
-| Pacientes | POST | `/functions/v1/register-patient` | Nao implementado |
-| Medicos | GET | `/rest/v1/doctors` | `professionalRepository.getAll` usa mock |
-| Medicos | POST | `/functions/v1/create-doctor` | Nao implementado |
-| Agendamentos | GET | `/rest/v1/appointments` | `appointmentRepository.getAll` usa mock |
-| Agendamentos | POST | `/rest/v1/appointments` | Nao implementado |
-| Agendamentos | POST | `/functions/v1/get-available-slots` | Nao implementado |
-| Disponibilidade | GET | `/rest/v1/doctor_availability` | Nao implementado |
-| Disponibilidade | POST | `/rest/v1/doctor_availability` | Nao implementado |
-| Disponibilidade | PATCH | `/rest/v1/doctor_availability?id=eq.{id}` | Nao implementado |
-| Disponibilidade | DELETE | `/rest/v1/doctor_availability?id=eq.{id}` | Nao implementado |
-| Disponibilidade | GET | `/rest/v1/doctor_exceptions` | Nao implementado |
-| Disponibilidade | POST | `/rest/v1/doctor_exceptions` | Nao implementado |
-| Storage | POST | `/storage/v1/object/avatars/{path}` | Nao implementado |
-| Storage | GET | `/storage/v1/object/avatars/{path}` | Nao implementado |
-| Reports | GET | `/rest/v1/reports` | `reportRepository.getInitialReports` usa mock |
-| Reports | POST | `/rest/v1/reports` | Nao implementado |
-| Reports | PATCH | `/rest/v1/reports?id=eq.{id}` | Nao implementado |
+- **Autenticacao**
+ - Login com email e senha via Supabase Auth (`/auth/v1/token`).
+ - Solicitar reset de senha: tenta `/solicitar-reset-de-senha` e usa `/auth/v1/recover` como fallback.
+ - Dados do usuario autenticado: tenta `/informacoes-do-usuario-autenticado` e usa `/auth/v1/user` como fallback.
+ - Logout: tenta `/logout`, usa `/auth/v1/logout` como fallback e sempre limpa a sessao local.
-## Repositories ainda nao implementados
+- **Pacientes**
+ - Listar, criar, atualizar e deletar pacientes via Supabase REST.
+ - Criar paciente com validacao via Edge Function quando disponivel.
-| Repository | Metodos atuais | Endpoint equivalente | Observacao |
-| --- | --- | --- | --- |
-| `analyticsRepository` | `getDashboardData` | Nao documentado | Retorna dados estaticos de KPIs, graficos e pacientes frequentes. |
-| `appointmentRepository` | `getAll`, `getTodayTimeline`, `getPredictiveQueueSummary`, `getWeekDays` | Parcial: `GET /rest/v1/appointments`, `POST /rest/v1/appointments`, `POST /functions/v1/get-available-slots` | `getAll` deveria chamar a API; demais metodos sao derivados/visuais e nao aparecem na doc. |
-| `communicationRepository` | `getCampaigns`, `getInitialMessages`, `getInitialTemplates` | Parcial: `POST /functions/v1/send-sms` | A API so documenta envio de SMS; nao ha endpoints para campanhas, mensagens ou templates. |
-| `homeRepository` | `getDashboardOverview` | Nao documentado | Tela inicial usa agregados estaticos. |
-| `medicalRecordRepository` | `getRecordTypes`, `getInitialRecords` | Nao documentado | Nao ha endpoint de prontuarios/medical records na doc atual. |
-| `professionalRepository` | `getAll`, `getCoverageMap` | Parcial: `GET /rest/v1/doctors`, `POST /functions/v1/create-doctor` | `getAll` deveria usar doctors; `getCoverageMap` parece derivado de disponibilidade, mas nao bate direto com um endpoint. |
-| `profileRepository` | `getCurrentUserProfile` | Parcial: `GET /auth/v1/user`, `POST /functions/v1/user-info` | Retorna perfil fixo; deveria consumir dados do usuario autenticado. |
-| `reportRepository` | `getAdminUsers`, `getCurrentUser`, `getDoctors`, `getInitialReports`, `getReportTypes`, `getTemplates` | Parcial: `GET/POST/PATCH /rest/v1/reports` | Lista e metadados sao mockados; nao existem metodos de criar/atualizar usando API. |
-| `settingsRepository` | `getIntegrations`, `getSections` | Nao documentado | Configuracoes exibidas sao estaticas. |
-| `visitRepository` | `getCareQueue`, `getStages` | Nao documentado | Nao ha endpoint de atendimentos/fila/visits na doc atual. |
+- **Agendamentos**
+ - Listar agendamentos: tenta `GET /agendamentos` e usa Supabase REST `appointments` como fallback.
+ - Criar agendamento: tenta `POST /agendamentos` e usa Supabase REST `appointments` como fallback.
-## Inconsistencias encontradas
+- **Laudos Medicos**
+ - Listar relatorios: tenta `GET /reports` e usa Supabase REST `reports` como fallback.
+ - Criar relatorio: tenta `POST /reports` e usa Supabase REST `reports` como fallback.
+ - Atualizar relatorio: tenta `PATCH /reports/{id}`, depois `PATCH /reports`, e usa Supabase REST `reports` como fallback.
-- `patientRepository.getById(patientId)` nao bate com um endpoint documentado especifico. Ele chama `getAll()` e filtra em memoria; se a API aceitar filtro Supabase por id, o ideal seria usar `/rest/v1/patients?id=eq.{id}&select=*`, mas isso nao aparece como endpoint proprio na documentacao.
-- `patientRepository.getDirectoryRows()` transforma pacientes em campos de UI e preenche `insurance`, `city`, `state`, `vip`, `lastVisit` e `nextVisit` com valores fixos. Esses campos nao estao descritos na resposta de `GET /rest/v1/patients`.
-- `patientRepository.create(data)` e `createWithValidation(data)` enviam `created_by` com UUID zerado quando nao informado. A documentacao nao confirma esse fallback; isso pode gerar registro invalido se a API exigir usuario real.
-- `patientRepository.createWithValidation(data)` usa a Edge Function documentada (`/functions/v1/create-patient`), mas a API tambem possui o endpoint publico `/functions/v1/register-patient`, ainda sem metodo correspondente.
-- `appointmentRepository.getAll()` nao chama `GET /rest/v1/appointments`; usa `mockData`. Alem disso, nao existem metodos para `POST /rest/v1/appointments` nem para `POST /functions/v1/get-available-slots`.
-- `professionalRepository.getAll()` nao chama `GET /rest/v1/doctors`; usa `mockData`. Tambem falta metodo para `POST /functions/v1/create-doctor`.
-- `reportRepository.getInitialReports()` nao chama `GET /rest/v1/reports`; usa dados estaticos e nomes/status em portugues (`rascunho`, `finalizado`, `enviado`) diferentes dos status documentados (`draft`, `completed`).
-- `reportRepository` expoe templates, tipos, usuarios admin e medico atual, mas esses recursos nao aparecem na API documentada de Reports.
-- `communicationRepository` tem campanhas, mensagens e templates, mas a documentacao so possui `POST /functions/v1/send-sms`; nao ha equivalencia para listar ou gerenciar esses dados.
-- `profileRepository.getCurrentUserProfile()` retorna perfil fixo; deveria ser alinhado com `GET /auth/v1/user` ou `POST /functions/v1/user-info`.
-- `homeRepository`, `analyticsRepository`, `settingsRepository`, `visitRepository` e `medicalRecordRepository` nao possuem endpoints equivalentes na documentacao atual.
+- **Medicos / Profissionais**
+ - Listar medicos: tenta `GET /listar-medicos` e usa Supabase REST `doctors` como fallback.
-## Configuracao extraida
+- **Mensageria**
+ - Enviar SMS: tenta `POST /enviar-sms-via-twilio` e usa Edge Function `send-sms` como fallback.
+ - O formulario agora coleta telefone quando o canal selecionado e SMS.
-As variaveis reutilizaveis de API foram centralizadas em `src/config/api.js`:
+- **Storage**
+ - Upload de avatar: tenta `/upload-avatar` e usa Supabase Storage no bucket `avatars` como fallback.
+ - A tela de perfil atualiza a imagem exibida apos upload bem-sucedido.
-- `VITE_SUPABASE_URL`
-- `VITE_SUPABASE_REST_URL`
-- `VITE_SUPABASE_FUNCTIONS_URL`
-- `VITE_SUPABASE_STORAGE_URL`
-- `VITE_SUPABASE_ANON_KEY`
+## Ainda sem endpoint consolidado documentado
-O arquivo mantem os valores atuais como fallback para nao quebrar o ambiente local, mas o ideal e configurar esses valores via `.env`.
+- Dashboard / Inicio (`HomePage` / `homeRepository.js`).
+- Estatisticas e BI (`AnalyticsPage` / `analyticsRepository.js`).
+- Prontuarios especificos separados de laudos (`MedicalRecordsPage` / `medicalRecordRepository.js`).
+- Consultas isoladas fora de agendamento (`VisitsPage` / `visitRepository.js`).
+- Configuracoes gerais do tenant (`SettingsPage` / `settingsRepository.js`).
+
+## Observacoes
+
+- `VITE_API_BASE_URL` define a base dos endpoints nomeados da API. Quando nao informado, o front usa `VITE_SUPABASE_FUNCTIONS_URL`.
+- Os reposititorios aceitam formatos de resposta comuns como arrays diretos ou objetos com chaves `data`, `reports`, `agendamentos`, `medicos` etc.
+- Os fallbacks existem para manter o front funcional em ambientes onde parte das Edge Functions ainda nao foi publicada.
diff --git a/src/App.jsx b/src/App.jsx
index 790bdc6..2a9c4ed 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,5 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from 'react'
+import { authRepository } from './repositories/authRepository.js'
+
import './App.css'
import { AppShell } from './components/AppShell.jsx'
import { AgendaPage } from './pages/AgendaPage.jsx'
@@ -48,11 +50,16 @@ function App() {
}, [])
const route = useMemo(() => resolveRoute(location.pathname, navigate), [location.pathname, navigate])
+ const isAuthenticated = authRepository.isAuthenticated()
if (!route.withShell) {
return route.element
}
+ if (!isAuthenticated) {
+ return
+ }
+
return (
{route.element}
@@ -119,15 +126,10 @@ function resolveRoute(pathname, navigate) {
if (pathname.startsWith('/pacientes/')) {
const patientId = pathname.split('/')[2]
- const patient = patientRepository.getById(patientId)
return {
- element: patient ? (
-
- ) : (
-
- ),
- title: patient?.name || 'Paciente nao encontrado',
+ element: ,
+ title: 'Paciente',
withShell: true,
}
}
@@ -195,6 +197,33 @@ function resolveRoute(pathname, navigate) {
}
}
+function PatientDetailRoute({ navigate, patientId }) {
+ const [patient, setPatient] = useState(null)
+ const [loading, setLoading] = useState(true)
+
+ useEffect(() => {
+ let active = true
+
+ patientRepository.getById(patientId)
+ .then((data) => {
+ if (active) setPatient(data)
+ })
+ .finally(() => {
+ if (active) setLoading(false)
+ })
+
+ return () => {
+ active = false
+ }
+ }, [patientId])
+
+ if (loading) {
+ return