chore: limpar arquivos de teste e documentação temporária
This commit is contained in:
parent
a4851de2e0
commit
0e27dbf1ff
@ -1,315 +0,0 @@
|
||||
# Configuração das APIs - MediConnect
|
||||
|
||||
## ✅ APIs Testadas e Funcionando
|
||||
|
||||
### 1. Autenticação (Auth API)
|
||||
|
||||
**Base URL:** `https://yuanqfswhberkoevtmfr.supabase.co/auth/v1`
|
||||
|
||||
#### Endpoints Funcionais:
|
||||
|
||||
- **Login** ✅
|
||||
- `POST /token?grant_type=password`
|
||||
- Body: `{ email, password }`
|
||||
- Retorna: `{ access_token, refresh_token, user }`
|
||||
|
||||
- **Recuperação de Senha** ✅
|
||||
- `POST /recover`
|
||||
- Body: `{ email, options: { redirectTo: url } }`
|
||||
- Envia email com link de recuperação
|
||||
|
||||
- **Atualizar Senha** ✅
|
||||
- `PUT /user`
|
||||
- Headers: `Authorization: Bearer <access_token>`
|
||||
- Body: `{ password: "nova_senha" }`
|
||||
- **IMPORTANTE:** Nova senha deve ser diferente da anterior (erro 422 se for igual)
|
||||
|
||||
### 2. REST API
|
||||
|
||||
**Base URL:** `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1`
|
||||
|
||||
#### Tabelas e Campos Corretos:
|
||||
|
||||
##### **appointments** ✅
|
||||
```typescript
|
||||
{
|
||||
id: string (UUID)
|
||||
order_number: string (auto-gerado: APT-YYYY-NNNN)
|
||||
patient_id: string (UUID)
|
||||
doctor_id: string (UUID)
|
||||
scheduled_at: string (ISO 8601 DateTime)
|
||||
duration_minutes: number
|
||||
appointment_type: "presencial" | "telemedicina"
|
||||
status: "requested" | "confirmed" | "checked_in" | "in_progress" | "completed" | "cancelled" | "no_show"
|
||||
chief_complaint: string | null
|
||||
patient_notes: string | null
|
||||
notes: string | null
|
||||
insurance_provider: string | null
|
||||
checked_in_at: string | null
|
||||
completed_at: string | null
|
||||
cancelled_at: string | null
|
||||
cancellation_reason: string | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
created_by: string (UUID)
|
||||
updated_by: string | null
|
||||
}
|
||||
```
|
||||
|
||||
**Criar Consulta:**
|
||||
```bash
|
||||
POST /rest/v1/appointments
|
||||
Headers:
|
||||
- apikey: <SUPABASE_ANON_KEY>
|
||||
- Authorization: Bearer <user_access_token>
|
||||
- Content-Type: application/json
|
||||
- Prefer: return=representation
|
||||
|
||||
Body:
|
||||
{
|
||||
"patient_id": "uuid",
|
||||
"doctor_id": "uuid",
|
||||
"scheduled_at": "2025-11-03T10:00:00.000Z",
|
||||
"duration_minutes": 30,
|
||||
"appointment_type": "presencial",
|
||||
"chief_complaint": "Motivo da consulta"
|
||||
}
|
||||
```
|
||||
|
||||
##### **doctor_availability** ✅
|
||||
```typescript
|
||||
{
|
||||
id: string (UUID)
|
||||
doctor_id: string (UUID)
|
||||
weekday: "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday"
|
||||
start_time: string (HH:MM:SS, ex: "07:00:00")
|
||||
end_time: string (HH:MM:SS, ex: "19:00:00")
|
||||
slot_duration_minutes: number (ex: 30)
|
||||
appointment_type: "presencial" | "telemedicina"
|
||||
is_active: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
created_by: string (UUID)
|
||||
updated_by: string | null
|
||||
}
|
||||
```
|
||||
|
||||
**Criar Disponibilidade:**
|
||||
```bash
|
||||
POST /rest/v1/doctor_availability
|
||||
Headers:
|
||||
- apikey: <SUPABASE_ANON_KEY>
|
||||
- Authorization: Bearer <admin_access_token>
|
||||
- Content-Type: application/json
|
||||
- Prefer: return=representation
|
||||
|
||||
Body:
|
||||
{
|
||||
"doctor_id": "uuid",
|
||||
"weekday": "monday", // ⚠️ Texto, não número!
|
||||
"start_time": "07:00:00",
|
||||
"end_time": "19:00:00",
|
||||
"slot_duration_minutes": 30,
|
||||
"appointment_type": "presencial",
|
||||
"is_active": true,
|
||||
"created_by": "admin_user_id"
|
||||
}
|
||||
```
|
||||
|
||||
##### **patients** ✅
|
||||
```typescript
|
||||
{
|
||||
id: string (UUID)
|
||||
user_id: string (UUID) // ⚠️ Deve estar vinculado ao auth.users
|
||||
full_name: string
|
||||
email: string
|
||||
cpf: string
|
||||
phone_mobile: string
|
||||
// ... outros campos
|
||||
}
|
||||
```
|
||||
|
||||
**Atualizar Patient:**
|
||||
```bash
|
||||
PATCH /rest/v1/patients?id=eq.<patient_id>
|
||||
Headers:
|
||||
- apikey: <SUPABASE_ANON_KEY>
|
||||
- Authorization: Bearer <admin_access_token>
|
||||
- Content-Type: application/json
|
||||
|
||||
Body:
|
||||
{
|
||||
"user_id": "auth_user_id"
|
||||
}
|
||||
```
|
||||
|
||||
##### **doctors** ✅
|
||||
```typescript
|
||||
{
|
||||
id: string (UUID)
|
||||
user_id: string (UUID)
|
||||
full_name: string
|
||||
email: string
|
||||
crm: string
|
||||
crm_uf: string
|
||||
specialty: string
|
||||
// ... outros campos
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Edge Functions
|
||||
|
||||
**Base URL:** `https://yuanqfswhberkoevtmfr.supabase.co/functions/v1`
|
||||
|
||||
#### Funcionais:
|
||||
|
||||
- **create-user-with-password** ✅
|
||||
- `POST /functions/v1/create-user-with-password`
|
||||
- Cria usuário com senha e perfil completo
|
||||
- Body:
|
||||
```json
|
||||
{
|
||||
"email": "email@example.com",
|
||||
"password": "senha123",
|
||||
"full_name": "Nome Completo",
|
||||
"phone_mobile": "(11) 99999-9999",
|
||||
"cpf": "12345678900",
|
||||
"create_patient_record": true,
|
||||
"role": "paciente"
|
||||
}
|
||||
```
|
||||
|
||||
#### Com Problemas:
|
||||
|
||||
- **request-password-reset** ❌
|
||||
- CORS blocking - não usar
|
||||
- Usar diretamente `/auth/v1/recover` em vez disso
|
||||
|
||||
## 🔑 Chaves de API
|
||||
|
||||
```typescript
|
||||
SUPABASE_URL = "https://yuanqfswhberkoevtmfr.supabase.co"
|
||||
SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ"
|
||||
```
|
||||
|
||||
## 👥 Usuários de Teste
|
||||
|
||||
### Admin
|
||||
- Email: `riseup@popcode.com.br`
|
||||
- Senha: `riseup`
|
||||
|
||||
### Dr. Fernando Pirichowski
|
||||
- Email: `fernando.pirichowski@souunit.com.br`
|
||||
- Senha: `fernando123`
|
||||
- User ID: `38aca60d-7418-4c35-95b6-cb206bb18a0a`
|
||||
- Doctor ID: `6dad001d-229b-40b5-80f3-310243c4599c`
|
||||
- CRM: `24245`
|
||||
- Disponibilidade: Segunda a Domingo, 07:00-19:00
|
||||
|
||||
### Aurora Sabrina Clara Nascimento (Paciente)
|
||||
- Email: `aurora-nascimento94@gmx.com`
|
||||
- Senha: `auroranasc94`
|
||||
- User ID: `6dc15cc5-7dae-4b30-924a-a4b4fa142f24`
|
||||
- Patient ID: `b85486f7-9135-4b67-9aa7-b884d9603d12`
|
||||
- CPF: `66864784231`
|
||||
- Telefone: `(21) 99856-3014`
|
||||
|
||||
## ⚠️ Pontos de Atenção
|
||||
|
||||
### 1. Weekday no doctor_availability
|
||||
- ❌ **NÃO** usar números (0-6)
|
||||
- ✅ **USAR** strings em inglês: `"sunday"`, `"monday"`, `"tuesday"`, `"wednesday"`, `"thursday"`, `"friday"`, `"saturday"`
|
||||
|
||||
### 2. scheduled_at em appointments
|
||||
- ❌ **NÃO** usar campos separados `appointment_date` e `appointment_time`
|
||||
- ✅ **USAR** campo único `scheduled_at` com ISO 8601 DateTime
|
||||
- Exemplo: `"2025-11-03T10:00:00.000Z"`
|
||||
|
||||
### 3. user_id nas tabelas patients e doctors
|
||||
- ⚠️ Sempre vincular ao `auth.users.id`
|
||||
- Sem esse vínculo, queries por `user_id` não funcionam
|
||||
|
||||
### 4. Senha na recuperação
|
||||
- ⚠️ Nova senha DEVE ser diferente da anterior
|
||||
- Erro 422 com `error_code: "same_password"` se tentar usar a mesma
|
||||
|
||||
### 5. redirectTo no password recovery
|
||||
- ⚠️ Supabase pode ignorar o parâmetro `redirectTo`
|
||||
- ✅ Implementar detecção de token no lado do cliente
|
||||
- Verificar tanto query string `?token=` quanto hash `#access_token=`
|
||||
|
||||
## 📦 Estrutura de Serviços no Frontend
|
||||
|
||||
```typescript
|
||||
// Tudo configurado em:
|
||||
src/services/api/config.ts // URLs e chaves
|
||||
src/services/api/client.ts // Cliente axios
|
||||
src/services/appointments/ // Serviço de consultas
|
||||
src/services/availability/ // Disponibilidade médicos
|
||||
src/services/auth/ // Autenticação
|
||||
src/services/doctors/ // Médicos
|
||||
src/services/patients/ // Pacientes
|
||||
src/services/index.ts // Exportações centralizadas
|
||||
```
|
||||
|
||||
## ✅ Status Atual
|
||||
|
||||
- [x] Autenticação funcionando
|
||||
- [x] Recuperação de senha funcionando
|
||||
- [x] Criação de usuários funcionando
|
||||
- [x] Criação de pacientes funcionando
|
||||
- [x] Criação de disponibilidade médica funcionando
|
||||
- [x] Criação de consultas funcionando
|
||||
- [x] Vinculação user_id ↔ patient_id corrigida
|
||||
- [x] Todos os serviços usando campos corretos
|
||||
|
||||
## 🚀 Próximos Passos
|
||||
|
||||
1. Testar agendamento completo no frontend
|
||||
2. Verificar listagem de consultas
|
||||
3. Testar cancelamento e atualização de consultas
|
||||
4. Verificar notificações SMS
|
||||
5. Testar fluxo completo de check-in e prontuário
|
||||
|
||||
## 📝 Exemplos de Uso
|
||||
|
||||
### Criar Consulta
|
||||
```typescript
|
||||
import { appointmentService } from '@/services';
|
||||
|
||||
const appointment = await appointmentService.create({
|
||||
patient_id: 'patient-uuid',
|
||||
doctor_id: 'doctor-uuid',
|
||||
scheduled_at: '2025-11-03T10:00:00.000Z',
|
||||
duration_minutes: 30,
|
||||
appointment_type: 'presencial',
|
||||
chief_complaint: 'Consulta de rotina'
|
||||
});
|
||||
```
|
||||
|
||||
### Criar Disponibilidade
|
||||
```typescript
|
||||
import { availabilityService } from '@/services';
|
||||
|
||||
const availability = await availabilityService.create({
|
||||
doctor_id: 'doctor-uuid',
|
||||
weekday: 'monday',
|
||||
start_time: '07:00:00',
|
||||
end_time: '19:00:00',
|
||||
slot_duration_minutes: 30,
|
||||
appointment_type: 'presencial'
|
||||
});
|
||||
```
|
||||
|
||||
### Login
|
||||
```typescript
|
||||
import { authService } from '@/services';
|
||||
|
||||
const response = await authService.login({
|
||||
email: 'user@example.com',
|
||||
password: 'senha123'
|
||||
});
|
||||
|
||||
// response.access_token - JWT token
|
||||
// response.user - dados do usuário
|
||||
```
|
||||
@ -1,76 +0,0 @@
|
||||
const axios = require("axios");
|
||||
|
||||
const ANON_KEY =
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ";
|
||||
const BASE_URL = "https://yuanqfswhberkoevtmfr.supabase.co";
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log("🔐 Fazendo login como admin...");
|
||||
const loginRes = await axios.post(
|
||||
`${BASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: "riseup@popcode.com.br",
|
||||
password: "riseup",
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
apikey: ANON_KEY,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log("✅ Login admin bem-sucedido!\n");
|
||||
const token = loginRes.data.access_token;
|
||||
|
||||
// Buscar o ID do Fernando no profiles
|
||||
console.log("🔍 Buscando ID do Fernando...");
|
||||
const profileRes = await axios.get(
|
||||
`${BASE_URL}/rest/v1/profiles?email=eq.fernando.pirichowski@souunit.com.br&select=*`,
|
||||
{
|
||||
headers: {
|
||||
apikey: ANON_KEY,
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (profileRes.data.length === 0) {
|
||||
console.log("❌ Fernando não encontrado no profiles");
|
||||
return;
|
||||
}
|
||||
|
||||
const fernandoId = profileRes.data[0].id;
|
||||
console.log("✅ Fernando encontrado! ID:", fernandoId);
|
||||
|
||||
// Criar entrada na tabela patients
|
||||
console.log("\n📋 Criando entrada na tabela patients...");
|
||||
const patientRes = await axios.post(
|
||||
`${BASE_URL}/rest/v1/patients`,
|
||||
{
|
||||
id: fernandoId,
|
||||
email: "fernando.pirichowski@souunit.com.br",
|
||||
full_name: "Fernando Pirichowski",
|
||||
phone_mobile: "51999999999",
|
||||
cpf: "12345678909", // CPF válido fictício
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
apikey: ANON_KEY,
|
||||
Authorization: `Bearer ${token}`,
|
||||
Prefer: "return=representation",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log("✅ Entrada na tabela patients criada!");
|
||||
console.log("\n🎉 Usuário Fernando Pirichowski completo!");
|
||||
console.log("📧 Email: fernando.pirichowski@souunit.com.br");
|
||||
console.log("🔑 Senha: fernando123");
|
||||
console.log("\n✨ Agora você pode testar a recuperação de senha!");
|
||||
} catch (err) {
|
||||
console.error("❌ Erro:", err.response?.data || err.message);
|
||||
}
|
||||
})();
|
||||
@ -1,121 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const SUPABASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
|
||||
async function createAppointment() {
|
||||
try {
|
||||
console.log('🔐 Fazendo login como Aurora...');
|
||||
|
||||
// Login como Aurora
|
||||
const loginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: 'aurora-nascimento94@gmx.com',
|
||||
password: 'auroranasc94'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const auroraToken = loginResponse.data.access_token;
|
||||
console.log('✅ Login realizado como Aurora');
|
||||
|
||||
// Buscar o patient_id da Aurora
|
||||
console.log('\n👤 Buscando dados da paciente...');
|
||||
const patientResponse = await axios.get(
|
||||
`${SUPABASE_URL}/rest/v1/patients?user_id=eq.${loginResponse.data.user.id}`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${auroraToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!patientResponse.data || patientResponse.data.length === 0) {
|
||||
throw new Error('Paciente não encontrada');
|
||||
}
|
||||
|
||||
const patientId = patientResponse.data[0].id;
|
||||
console.log(`✅ Patient ID: ${patientId}`);
|
||||
|
||||
// Buscar disponibilidade do Dr. Fernando para segunda-feira
|
||||
console.log('\n📅 Buscando disponibilidade do Dr. Fernando...');
|
||||
const availabilityResponse = await axios.get(
|
||||
`${SUPABASE_URL}/rest/v1/doctor_availability?doctor_id=eq.6dad001d-229b-40b5-80f3-310243c4599c&weekday=eq.monday`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${auroraToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!availabilityResponse.data || availabilityResponse.data.length === 0) {
|
||||
throw new Error('Disponibilidade não encontrada');
|
||||
}
|
||||
|
||||
const availability = availabilityResponse.data[0];
|
||||
console.log(`✅ Disponibilidade encontrada: ${availability.start_time} - ${availability.end_time}`);
|
||||
|
||||
// Criar consulta para próxima segunda-feira às 10:00
|
||||
const today = new Date();
|
||||
const daysUntilMonday = (1 - today.getDay() + 7) % 7 || 7; // Próxima segunda
|
||||
const appointmentDate = new Date(today);
|
||||
appointmentDate.setDate(today.getDate() + daysUntilMonday);
|
||||
appointmentDate.setHours(10, 0, 0, 0);
|
||||
|
||||
const scheduledAt = appointmentDate.toISOString();
|
||||
|
||||
console.log(`\n📝 Criando consulta para ${scheduledAt}...`);
|
||||
|
||||
const appointmentData = {
|
||||
patient_id: patientId,
|
||||
doctor_id: '6dad001d-229b-40b5-80f3-310243c4599c',
|
||||
scheduled_at: scheduledAt,
|
||||
duration_minutes: 30,
|
||||
appointment_type: 'presencial',
|
||||
chief_complaint: 'Consulta de rotina'
|
||||
};
|
||||
|
||||
const appointmentResponse = await axios.post(
|
||||
`${SUPABASE_URL}/rest/v1/appointments`,
|
||||
appointmentData,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${auroraToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
'Prefer': 'return=representation'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n✅ Consulta criada com sucesso!');
|
||||
console.log('\n📋 Detalhes da consulta:');
|
||||
console.log(` - Paciente: Aurora Sabrina Clara Nascimento`);
|
||||
console.log(` - Médico: Dr. Fernando Pirichowski`);
|
||||
console.log(` - Data/Hora: ${scheduledAt}`);
|
||||
console.log(` - Duração: 30 minutos`);
|
||||
console.log(` - Tipo: presencial`);
|
||||
|
||||
if (appointmentResponse.data && appointmentResponse.data.length > 0) {
|
||||
console.log(` - ID da consulta: ${appointmentResponse.data[0].id}`);
|
||||
console.log(` - Order Number: ${appointmentResponse.data[0].order_number}`);
|
||||
console.log(` - Status: ${appointmentResponse.data[0].status}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao criar consulta:', error.response?.data || error.message);
|
||||
if (error.response?.data) {
|
||||
console.error('Detalhes:', JSON.stringify(error.response.data, null, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createAppointment();
|
||||
@ -1,91 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const SUPABASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
|
||||
// IDs
|
||||
const DOCTOR_ID = '6dad001d-229b-40b5-80f3-310243c4599c'; // Fernando (CRM 24245)
|
||||
const ADMIN_ID = 'c7fcd702-9a6e-4b7c-abd3-956b25af407d'; // Admin (riseup)
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('🔐 Fazendo login como admin...');
|
||||
|
||||
const loginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: 'riseup@popcode.com.br',
|
||||
password: 'riseup'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_ANON_KEY
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const adminToken = loginResponse.data.access_token;
|
||||
console.log('✅ Login realizado\n');
|
||||
|
||||
console.log('📅 Criando disponibilidade para Dr. Fernando...');
|
||||
console.log('⏰ Horário: 07:00 às 19:00');
|
||||
console.log('📆 Dias: Segunda a Domingo\n');
|
||||
|
||||
const weekdays = [
|
||||
{ num: 'sunday', name: 'Domingo' },
|
||||
{ num: 'monday', name: 'Segunda-feira' },
|
||||
{ num: 'tuesday', name: 'Terça-feira' },
|
||||
{ num: 'wednesday', name: 'Quarta-feira' },
|
||||
{ num: 'thursday', name: 'Quinta-feira' },
|
||||
{ num: 'friday', name: 'Sexta-feira' },
|
||||
{ num: 'saturday', name: 'Sábado' }
|
||||
];
|
||||
|
||||
for (const day of weekdays) {
|
||||
try {
|
||||
const availabilityData = {
|
||||
doctor_id: DOCTOR_ID,
|
||||
weekday: day.num,
|
||||
start_time: '07:00:00',
|
||||
end_time: '19:00:00',
|
||||
slot_minutes: 30,
|
||||
appointment_type: 'presencial',
|
||||
active: true,
|
||||
created_by: ADMIN_ID
|
||||
};
|
||||
|
||||
const response = await axios.post(
|
||||
`${SUPABASE_URL}/rest/v1/doctor_availability`,
|
||||
availabilityData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${adminToken}`,
|
||||
'Prefer': 'return=representation'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`✅ ${day.name}: Disponibilidade criada`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ ${day.name}: Erro -`, error.response?.data?.message || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n🎉 Disponibilidade criada com sucesso!');
|
||||
console.log('\n📋 Resumo:');
|
||||
console.log('- Médico: Dr. Fernando Pirichowski');
|
||||
console.log('- Dias: Todos os dias da semana (Domingo a Sábado)');
|
||||
console.log('- Horário: 07:00 às 19:00');
|
||||
console.log('- Duração consulta: 30 minutos');
|
||||
console.log('- Tipo: Presencial');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro geral:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@ -1,87 +0,0 @@
|
||||
const axios = require("axios");
|
||||
|
||||
const ANON_KEY =
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ";
|
||||
const BASE_URL = "https://yuanqfswhberkoevtmfr.supabase.co";
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log("🔐 Fazendo login como admin...");
|
||||
const loginRes = await axios.post(
|
||||
`${BASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: "riseup@popcode.com.br",
|
||||
password: "riseup",
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
apikey: ANON_KEY,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log("✅ Login admin bem-sucedido!\n");
|
||||
const token = loginRes.data.access_token;
|
||||
|
||||
console.log("👤 Criando usuário Fernando Pirichowski...");
|
||||
|
||||
// Criar usuário via signup
|
||||
const signupRes = await axios.post(
|
||||
`${BASE_URL}/auth/v1/signup`,
|
||||
{
|
||||
email: "fernando.pirichowski@souunit.com.br",
|
||||
password: "fernando123", // Senha temporária
|
||||
options: {
|
||||
data: {
|
||||
full_name: "Fernando Pirichowski",
|
||||
phone: "51999999999",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
apikey: ANON_KEY,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log("✅ Usuário criado com sucesso!");
|
||||
console.log("📧 Email:", signupRes.data.user.email);
|
||||
console.log("🆔 ID:", signupRes.data.user.id);
|
||||
console.log("🔑 Senha temporária: fernando123\n");
|
||||
|
||||
// Criar entrada na tabela patients
|
||||
console.log("📋 Criando entrada na tabela patients...");
|
||||
const patientRes = await axios.post(
|
||||
`${BASE_URL}/rest/v1/patients`,
|
||||
{
|
||||
id: signupRes.data.user.id,
|
||||
email: "fernando.pirichowski@souunit.com.br",
|
||||
full_name: "Fernando Pirichowski",
|
||||
phone_mobile: "51999999999",
|
||||
cpf: "12345678909", // CPF válido fictício
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
apikey: ANON_KEY,
|
||||
Authorization: `Bearer ${token}`,
|
||||
Prefer: "return=representation",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log("✅ Entrada na tabela patients criada!");
|
||||
console.log("\n🎉 Usuário Fernando Pirichowski criado com sucesso!");
|
||||
console.log("📧 Email: fernando.pirichowski@souunit.com.br");
|
||||
console.log("🔑 Senha: fernando123");
|
||||
console.log("\n💡 Agora você pode testar a recuperação de senha!");
|
||||
} catch (err) {
|
||||
console.error("❌ Erro:", err.response?.data || err.message);
|
||||
if (err.response?.data?.msg) {
|
||||
console.error("Mensagem:", err.response.data.msg);
|
||||
}
|
||||
}
|
||||
})();
|
||||
@ -1,78 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
// Configuração
|
||||
const SUPABASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
|
||||
// Credenciais do admin
|
||||
const ADMIN_EMAIL = 'riseup@popcode.com.br';
|
||||
const ADMIN_PASSWORD = 'riseup';
|
||||
|
||||
// Dados do paciente (Aurora Sabrina Clara Nascimento)
|
||||
const PATIENT_DATA = {
|
||||
email: 'aurora-nascimento94@gmx.com',
|
||||
password: 'auroranasc94',
|
||||
full_name: 'Aurora Sabrina Clara Nascimento',
|
||||
phone_mobile: '(21) 99856-3014',
|
||||
cpf: '66864784231', // CPF sem pontuação
|
||||
create_patient_record: true,
|
||||
role: 'paciente'
|
||||
};
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('🔐 1. Fazendo login como admin...');
|
||||
|
||||
// 1. Login do admin
|
||||
const loginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: ADMIN_EMAIL,
|
||||
password: ADMIN_PASSWORD
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_ANON_KEY
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const adminToken = loginResponse.data.access_token;
|
||||
console.log('✅ Login realizado com sucesso!');
|
||||
console.log('🔑 Token:', adminToken.substring(0, 30) + '...');
|
||||
|
||||
console.log('\n👤 2. Criando paciente...');
|
||||
console.log('Dados:', JSON.stringify(PATIENT_DATA, null, 2));
|
||||
|
||||
// 2. Criar paciente
|
||||
const createResponse = await axios.post(
|
||||
`${SUPABASE_URL}/functions/v1/create-user-with-password`,
|
||||
PATIENT_DATA,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${adminToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n✅ Paciente criado com sucesso!');
|
||||
console.log('Resposta:', JSON.stringify(createResponse.data, null, 2));
|
||||
|
||||
if (createResponse.data.patient_id) {
|
||||
console.log('\n📋 ID do paciente:', createResponse.data.patient_id);
|
||||
console.log('✉️ Email de confirmação enviado para:', PATIENT_DATA.email);
|
||||
console.log('🔐 Senha temporária:', PATIENT_DATA.password);
|
||||
console.log('\n⚠️ O usuário precisa confirmar o email antes de fazer login!');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro:', error.response?.data || error.message);
|
||||
console.error('Status:', error.response?.status);
|
||||
console.error('URL:', error.config?.url);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@ -1,72 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const SUPABASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
|
||||
async function fixAuroraUserId() {
|
||||
try {
|
||||
console.log('🔐 Fazendo login como admin...');
|
||||
|
||||
const loginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: 'riseup@popcode.com.br',
|
||||
password: 'riseup'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const adminToken = loginResponse.data.access_token;
|
||||
console.log('✅ Login realizado');
|
||||
|
||||
// Fazer login como Aurora para pegar o user_id
|
||||
console.log('\n👤 Fazendo login como Aurora...');
|
||||
const auroraLoginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: 'aurora-nascimento94@gmx.com',
|
||||
password: 'auroranasc94'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const auroraUserId = auroraLoginResponse.data.user.id;
|
||||
console.log(`✅ User ID da Aurora: ${auroraUserId}`);
|
||||
|
||||
// Atualizar patient com user_id
|
||||
console.log('\n📝 Atualizando registro da paciente...');
|
||||
const updateResponse = await axios.patch(
|
||||
`${SUPABASE_URL}/rest/v1/patients?id=eq.b85486f7-9135-4b67-9aa7-b884d9603d12`,
|
||||
{
|
||||
user_id: auroraUserId
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${adminToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
'Prefer': 'return=representation'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log('✅ Registro atualizado com sucesso!');
|
||||
console.log(` - Patient ID: b85486f7-9135-4b67-9aa7-b884d9603d12`);
|
||||
console.log(` - User ID: ${auroraUserId}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
fixAuroraUserId();
|
||||
@ -1,59 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const SUPABASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('🔐 Fazendo login como admin...');
|
||||
|
||||
const loginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: 'riseup@popcode.com.br',
|
||||
password: 'riseup'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_ANON_KEY
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const adminToken = loginResponse.data.access_token;
|
||||
console.log('✅ Login realizado\n');
|
||||
|
||||
console.log('👤 Buscando dados de Aurora na tabela patients...');
|
||||
|
||||
const patientsResponse = await axios.get(
|
||||
`${SUPABASE_URL}/rest/v1/patients?email=eq.aurora-nascimento94@gmx.com`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${adminToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (patientsResponse.data.length > 0) {
|
||||
const patient = patientsResponse.data[0];
|
||||
console.log('✅ Paciente encontrada!\n');
|
||||
console.log('📋 DADOS DA AURORA:\n');
|
||||
console.log('User ID (auth):', patient.id);
|
||||
console.log('Patient ID:', patient.id); // Em patients, o id é o mesmo do auth
|
||||
console.log('Nome:', patient.full_name);
|
||||
console.log('Email:', patient.email);
|
||||
console.log('CPF:', patient.cpf);
|
||||
console.log('Telefone:', patient.phone_mobile);
|
||||
console.log('\n📄 Dados completos:', JSON.stringify(patient, null, 2));
|
||||
} else {
|
||||
console.log('❌ Paciente não encontrada na tabela patients');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@ -1,76 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const SUPABASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('🔐 Fazendo login como admin...');
|
||||
|
||||
const loginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: 'riseup@popcode.com.br',
|
||||
password: 'riseup'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_ANON_KEY
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const adminToken = loginResponse.data.access_token;
|
||||
console.log('✅ Login realizado\n');
|
||||
|
||||
console.log('🔍 Buscando Fernando em profiles...');
|
||||
|
||||
const profilesResponse = await axios.get(
|
||||
`${SUPABASE_URL}/rest/v1/profiles?email=eq.fernando.pirichowski@souunit.com.br`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${adminToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (profilesResponse.data.length > 0) {
|
||||
console.log(`✅ ${profilesResponse.data.length} perfil(is) encontrado(s)!\n`);
|
||||
|
||||
profilesResponse.data.forEach((profile, index) => {
|
||||
console.log(`📋 PERFIL ${index + 1}:\n`);
|
||||
console.log('User ID:', profile.id);
|
||||
console.log('Email:', profile.email);
|
||||
console.log('Nome:', profile.full_name);
|
||||
console.log('Telefone:', profile.phone || 'Não informado');
|
||||
console.log('\n' + '='.repeat(60) + '\n');
|
||||
});
|
||||
|
||||
// Pegar roles do primeiro perfil
|
||||
const userId = profilesResponse.data[0].id;
|
||||
console.log('🔍 Buscando roles...');
|
||||
|
||||
const rolesResponse = await axios.get(
|
||||
`${SUPABASE_URL}/rest/v1/user_roles?user_id=eq.${userId}`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${adminToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log('📌 Roles:', rolesResponse.data.map(r => r.role).join(', '));
|
||||
|
||||
} else {
|
||||
console.log('❌ Nenhum perfil encontrado');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@ -1,78 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const SUPABASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('🔐 Fazendo login como admin...');
|
||||
|
||||
const loginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: 'riseup@popcode.com.br',
|
||||
password: 'riseup'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_ANON_KEY
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const adminToken = loginResponse.data.access_token;
|
||||
console.log('✅ Login realizado\n');
|
||||
|
||||
console.log('👨⚕️ Buscando dados de Fernando na tabela doctors...');
|
||||
|
||||
const doctorsResponse = await axios.get(
|
||||
`${SUPABASE_URL}/rest/v1/doctors?email=eq.fernando.pirichowski@souunit.com.br`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${adminToken}`,
|
||||
'Prefer': 'return=representation'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (doctorsResponse.data.length > 0) {
|
||||
console.log(`✅ ${doctorsResponse.data.length} médico(s) encontrado(s)!\n`);
|
||||
|
||||
doctorsResponse.data.forEach((doctor, index) => {
|
||||
console.log(`📋 MÉDICO ${index + 1}:\n`);
|
||||
console.log('Doctor ID:', doctor.id);
|
||||
console.log('Nome:', doctor.full_name);
|
||||
console.log('Email:', doctor.email);
|
||||
console.log('CRM:', doctor.crm);
|
||||
console.log('Especialidade:', doctor.specialty || 'Não informada');
|
||||
console.log('Telefone:', doctor.phone || 'Não informado');
|
||||
console.log('\n' + '='.repeat(60) + '\n');
|
||||
});
|
||||
} else {
|
||||
console.log('❌ Nenhum médico chamado Fernando encontrado');
|
||||
console.log('\n🔍 Buscando todos os médicos...');
|
||||
|
||||
const allDoctorsResponse = await axios.get(
|
||||
`${SUPABASE_URL}/rest/v1/doctors`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_ANON_KEY,
|
||||
'Authorization': `Bearer ${adminToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`\n📊 Total de médicos cadastrados: ${allDoctorsResponse.data.length}`);
|
||||
allDoctorsResponse.data.forEach((doctor, index) => {
|
||||
console.log(`${index + 1}. ${doctor.full_name} - ${doctor.email}`);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@ -1,38 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const SUPABASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('🔐 Fazendo login como Fernando...');
|
||||
|
||||
const loginResponse = await axios.post(
|
||||
`${SUPABASE_URL}/auth/v1/token?grant_type=password`,
|
||||
{
|
||||
email: 'fernando.pirichowski@souunit.com.br',
|
||||
password: 'fernando123'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_ANON_KEY
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const userData = loginResponse.data;
|
||||
console.log('✅ Login realizado\n');
|
||||
|
||||
console.log('📋 DADOS DO FERNANDO (AUTH):\n');
|
||||
console.log('User ID:', userData.user.id);
|
||||
console.log('Email:', userData.user.email);
|
||||
console.log('Role:', userData.user.role);
|
||||
console.log('\n' + '='.repeat(60));
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@ -1,86 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ';
|
||||
const BASE_URL = 'https://yuanqfswhberkoevtmfr.supabase.co';
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log('🔐 Fazendo login como admin...');
|
||||
const loginRes = await axios.post(`${BASE_URL}/auth/v1/token?grant_type=password`, {
|
||||
email: 'riseup@popcode.com.br',
|
||||
password: 'riseup'
|
||||
}, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': ANON_KEY
|
||||
}
|
||||
});
|
||||
|
||||
console.log('✅ Login admin bem-sucedido!\n');
|
||||
const token = loginRes.data.access_token;
|
||||
|
||||
console.log('🔍 Buscando usuário fernando na tabela profiles...');
|
||||
const profilesRes = await axios.get(`${BASE_URL}/rest/v1/profiles?select=*`, {
|
||||
headers: {
|
||||
'apikey': ANON_KEY,
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`📊 Total de profiles: ${profilesRes.data.length}\n`);
|
||||
|
||||
const fernandoProfile = profilesRes.data.find(u =>
|
||||
u.email && (
|
||||
u.email.toLowerCase().includes('fernando') ||
|
||||
u.full_name?.toLowerCase().includes('fernando')
|
||||
)
|
||||
);
|
||||
|
||||
if (fernandoProfile) {
|
||||
console.log('✅ Fernando encontrado na tabela profiles:');
|
||||
console.log(JSON.stringify(fernandoProfile, null, 2));
|
||||
} else {
|
||||
console.log('❌ Fernando NÃO encontrado na tabela profiles\n');
|
||||
}
|
||||
|
||||
// Buscar nos pacientes também
|
||||
console.log('\n🔍 Buscando fernando na tabela patients...');
|
||||
const patientsRes = await axios.get(`${BASE_URL}/rest/v1/patients?select=*`, {
|
||||
headers: {
|
||||
'apikey': ANON_KEY,
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`📊 Total de patients: ${patientsRes.data.length}\n`);
|
||||
|
||||
const fernandoPatient = patientsRes.data.find(p =>
|
||||
p.email && (
|
||||
p.email.toLowerCase().includes('fernando') ||
|
||||
p.full_name?.toLowerCase().includes('fernando')
|
||||
)
|
||||
);
|
||||
|
||||
if (fernandoPatient) {
|
||||
console.log('✅ Fernando encontrado na tabela patients:');
|
||||
console.log(JSON.stringify(fernandoPatient, null, 2));
|
||||
} else {
|
||||
console.log('❌ Fernando NÃO encontrado na tabela patients\n');
|
||||
}
|
||||
|
||||
// Listar alguns emails para referência
|
||||
if (!fernandoProfile && !fernandoPatient) {
|
||||
console.log('\n📧 Alguns emails cadastrados nos profiles:');
|
||||
profilesRes.data.slice(0, 10).forEach((u, i) => {
|
||||
if (u.email) console.log(` ${i+1}. ${u.email} - ${u.full_name || 'sem nome'}`);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('❌ Erro:', err.response?.data || err.message);
|
||||
if (err.response) {
|
||||
console.error('Status:', err.response.status);
|
||||
console.error('Headers:', err.response.headers);
|
||||
}
|
||||
}
|
||||
})();
|
||||
@ -1,54 +0,0 @@
|
||||
const axios = require("axios");
|
||||
|
||||
const ANON_KEY =
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ";
|
||||
const BASE_URL = "https://yuanqfswhberkoevtmfr.supabase.co";
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log("\n=== TESTE DE RECUPERAÇÃO COM REDIRECT_TO CORRETO ===\n");
|
||||
|
||||
const email = "fernando.pirichowski@souunit.com.br";
|
||||
const redirectTo = "https://mediconnectbrasil.app/reset-password";
|
||||
|
||||
console.log(`📧 Enviando email de recuperação para: ${email}`);
|
||||
console.log(`🔗 Redirect URL: ${redirectTo}\n`);
|
||||
|
||||
const response = await axios.post(
|
||||
`${BASE_URL}/auth/v1/recover`,
|
||||
{
|
||||
email: email,
|
||||
options: {
|
||||
redirectTo: redirectTo,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
apikey: ANON_KEY,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log("✅ Email de recuperação enviado com sucesso!");
|
||||
console.log("Status:", response.status);
|
||||
console.log("Response:", JSON.stringify(response.data, null, 2));
|
||||
|
||||
console.log("\n📬 Verifique o email:", email);
|
||||
console.log("🔗 O link DEVE redirecionar para:", redirectTo);
|
||||
console.log("\n💡 IMPORTANTE: Se ainda vier o link errado, você precisa:");
|
||||
console.log(" 1. Acessar o painel do Supabase");
|
||||
console.log(" 2. Ir em Authentication > URL Configuration");
|
||||
console.log(
|
||||
' 3. Atualizar o "Site URL" para: https://mediconnectbrasil.app'
|
||||
);
|
||||
console.log(
|
||||
' 4. Adicionar https://mediconnectbrasil.app/* nos "Redirect URLs"'
|
||||
);
|
||||
|
||||
console.log("\n=== TESTE CONCLUÍDO ===\n");
|
||||
} catch (error) {
|
||||
console.error("❌ Erro ao enviar email de recuperação:");
|
||||
console.error(error.response?.data || error.message);
|
||||
}
|
||||
})();
|
||||
188
README.md
188
README.md
@ -61,12 +61,14 @@ O MediConnect é uma plataforma web que conecta **pacientes**, **médicos** e **
|
||||
### Camadas da Aplicação
|
||||
|
||||
1. **Apresentação (UI)**
|
||||
|
||||
- React 18.3.1 com TypeScript
|
||||
- React Router para navegação
|
||||
- Tailwind CSS para estilização
|
||||
- Lucide React para ícones
|
||||
|
||||
2. **Lógica de Negócio (Services)**
|
||||
|
||||
- Services organizados por domínio
|
||||
- Axios para requisições HTTP
|
||||
- Interceptors para autenticação automática
|
||||
@ -81,6 +83,7 @@ O MediConnect é uma plataforma web que conecta **pacientes**, **médicos** e **
|
||||
## 🛠️ Tecnologias
|
||||
|
||||
### Frontend
|
||||
|
||||
- **React** 18.3.1 - Biblioteca UI
|
||||
- **TypeScript** 5.9.3 - Tipagem estática
|
||||
- **Vite** 7.1.10 - Build tool
|
||||
@ -91,11 +94,13 @@ O MediConnect é uma plataforma web que conecta **pacientes**, **médicos** e **
|
||||
- **date-fns** 4.1.0 - Manipulação de datas
|
||||
|
||||
### Backend
|
||||
|
||||
- **Supabase** - Backend as a Service
|
||||
- **PostgreSQL** - Banco de dados relacional
|
||||
- **Supabase Auth** - Autenticação JWT
|
||||
|
||||
### Deploy
|
||||
|
||||
- **Cloudflare Pages** - Hospedagem frontend
|
||||
- **Wrangler** 4.44.0 - CLI Cloudflare
|
||||
|
||||
@ -187,106 +192,112 @@ export const API_CONFIG = {
|
||||
STORAGE_KEYS: {
|
||||
ACCESS_TOKEN: "mediconnect_access_token",
|
||||
REFRESH_TOKEN: "mediconnect_refresh_token",
|
||||
USER: "mediconnect_user"
|
||||
}
|
||||
}
|
||||
USER: "mediconnect_user",
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Serviços Disponíveis
|
||||
|
||||
#### 1. **authService** - Autenticação
|
||||
|
||||
```typescript
|
||||
// Login
|
||||
await authService.login({ email, password })
|
||||
await authService.login({ email, password });
|
||||
|
||||
// Registro
|
||||
await authService.signup({ email, password, full_name })
|
||||
await authService.signup({ email, password, full_name });
|
||||
|
||||
// Logout
|
||||
await authService.logout()
|
||||
await authService.logout();
|
||||
|
||||
// Recuperação de senha
|
||||
await authService.requestPasswordReset(email)
|
||||
await authService.updatePassword(accessToken, newPassword)
|
||||
await authService.requestPasswordReset(email);
|
||||
await authService.updatePassword(accessToken, newPassword);
|
||||
|
||||
// Refresh token
|
||||
await authService.refreshToken(refreshToken)
|
||||
await authService.refreshToken(refreshToken);
|
||||
```
|
||||
|
||||
#### 2. **userService** - Usuários
|
||||
|
||||
```typescript
|
||||
// Buscar informações do usuário autenticado
|
||||
const userInfo = await userService.getUserInfo()
|
||||
const userInfo = await userService.getUserInfo();
|
||||
|
||||
// Criar usuário com role
|
||||
await userService.createUser({ email, full_name, role })
|
||||
await userService.createUser({ email, full_name, role });
|
||||
|
||||
// Deletar usuário
|
||||
await userService.deleteUser(userId)
|
||||
await userService.deleteUser(userId);
|
||||
```
|
||||
|
||||
#### 3. **patientService** - Pacientes
|
||||
|
||||
```typescript
|
||||
// Listar pacientes
|
||||
const patients = await patientService.list()
|
||||
const patients = await patientService.list();
|
||||
|
||||
// Buscar por ID
|
||||
const patient = await patientService.getById(id)
|
||||
const patient = await patientService.getById(id);
|
||||
|
||||
// Criar paciente
|
||||
await patientService.create({ email, full_name, cpf, phone })
|
||||
await patientService.create({ email, full_name, cpf, phone });
|
||||
|
||||
// Atualizar
|
||||
await patientService.update(id, data)
|
||||
await patientService.update(id, data);
|
||||
|
||||
// Registrar paciente (público)
|
||||
await patientService.register({ email, full_name, cpf })
|
||||
await patientService.register({ email, full_name, cpf });
|
||||
```
|
||||
|
||||
#### 4. **doctorService** - Médicos
|
||||
|
||||
```typescript
|
||||
// Listar médicos
|
||||
const doctors = await doctorService.list()
|
||||
const doctors = await doctorService.list();
|
||||
|
||||
// Buscar por ID
|
||||
const doctor = await doctorService.getById(id)
|
||||
const doctor = await doctorService.getById(id);
|
||||
|
||||
// Buscar disponibilidade
|
||||
const slots = await doctorService.getAvailableSlots(doctorId, date)
|
||||
const slots = await doctorService.getAvailableSlots(doctorId, date);
|
||||
```
|
||||
|
||||
#### 5. **appointmentService** - Consultas
|
||||
|
||||
```typescript
|
||||
// Listar consultas
|
||||
const appointments = await appointmentService.list()
|
||||
const appointments = await appointmentService.list();
|
||||
|
||||
// Criar consulta
|
||||
await appointmentService.create({
|
||||
patient_id,
|
||||
doctor_id,
|
||||
scheduled_at,
|
||||
reason
|
||||
})
|
||||
reason,
|
||||
});
|
||||
|
||||
// Atualizar status
|
||||
await appointmentService.updateStatus(id, status)
|
||||
await appointmentService.updateStatus(id, status);
|
||||
|
||||
// Cancelar
|
||||
await appointmentService.cancel(id, reason)
|
||||
await appointmentService.cancel(id, reason);
|
||||
```
|
||||
|
||||
#### 6. **availabilityService** - Disponibilidade
|
||||
|
||||
```typescript
|
||||
// Gerenciar disponibilidade do médico
|
||||
await availabilityService.create({
|
||||
doctor_id,
|
||||
day_of_week,
|
||||
start_time,
|
||||
end_time
|
||||
})
|
||||
end_time,
|
||||
});
|
||||
|
||||
// Listar disponibilidade
|
||||
const slots = await availabilityService.listByDoctor(doctorId)
|
||||
const slots = await availabilityService.listByDoctor(doctorId);
|
||||
```
|
||||
|
||||
---
|
||||
@ -296,61 +307,65 @@ const slots = await availabilityService.listByDoctor(doctorId)
|
||||
### Fluxo de Autenticação
|
||||
|
||||
1. **Login**
|
||||
|
||||
```typescript
|
||||
// 1. Usuário envia credenciais
|
||||
const response = await authService.login({ email, password })
|
||||
const response = await authService.login({ email, password });
|
||||
|
||||
// 2. Recebe tokens JWT
|
||||
localStorage.setItem('access_token', response.access_token)
|
||||
localStorage.setItem('refresh_token', response.refresh_token)
|
||||
localStorage.setItem("access_token", response.access_token);
|
||||
localStorage.setItem("refresh_token", response.refresh_token);
|
||||
|
||||
// 3. Busca informações completas
|
||||
const userInfo = await userService.getUserInfo()
|
||||
const userInfo = await userService.getUserInfo();
|
||||
|
||||
// 4. Valida roles
|
||||
if (userInfo.roles.includes('medico')) {
|
||||
navigate('/painel-medico')
|
||||
if (userInfo.roles.includes("medico")) {
|
||||
navigate("/painel-medico");
|
||||
}
|
||||
```
|
||||
|
||||
2. **Interceptor Automático**
|
||||
|
||||
```typescript
|
||||
// Todo request adiciona o token automaticamente
|
||||
axios.interceptors.request.use(config => {
|
||||
const token = localStorage.getItem('access_token')
|
||||
axios.interceptors.request.use((config) => {
|
||||
const token = localStorage.getItem("access_token");
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config
|
||||
})
|
||||
return config;
|
||||
});
|
||||
```
|
||||
|
||||
3. **Refresh Token Automático**
|
||||
|
||||
```typescript
|
||||
axios.interceptors.response.use(
|
||||
response => response,
|
||||
async error => {
|
||||
(response) => response,
|
||||
async (error) => {
|
||||
if (error.response?.status === 401) {
|
||||
// Token expirado, tenta refresh
|
||||
const refreshToken = localStorage.getItem('refresh_token')
|
||||
const newTokens = await authService.refreshToken(refreshToken)
|
||||
const refreshToken = localStorage.getItem("refresh_token");
|
||||
const newTokens = await authService.refreshToken(refreshToken);
|
||||
// Retry request original
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### Roles e Permissões
|
||||
|
||||
| Role | Acesso |
|
||||
|------|--------|
|
||||
| **admin** | Acesso total ao sistema |
|
||||
| **gestor** | Gestão de médicos, secretárias e relatórios |
|
||||
| **medico** | Painel médico, consultas, prontuários |
|
||||
| **secretaria** | Agendamento, gestão de pacientes |
|
||||
| **paciente** | Agendamento, visualização de consultas |
|
||||
| Role | Acesso |
|
||||
| -------------- | ------------------------------------------- |
|
||||
| **admin** | Acesso total ao sistema |
|
||||
| **gestor** | Gestão de médicos, secretárias e relatórios |
|
||||
| **medico** | Painel médico, consultas, prontuários |
|
||||
| **secretaria** | Agendamento, gestão de pacientes |
|
||||
| **paciente** | Agendamento, visualização de consultas |
|
||||
|
||||
**Hierarquia de Roles:**
|
||||
|
||||
```
|
||||
admin > gestor > medico/secretaria > paciente
|
||||
```
|
||||
@ -397,26 +412,26 @@ sequenceDiagram
|
||||
// LoginMedico.tsx
|
||||
const handleLogin = async () => {
|
||||
// 1. Login
|
||||
const loginResponse = await authService.login({ email, password })
|
||||
|
||||
const loginResponse = await authService.login({ email, password });
|
||||
|
||||
// 2. Buscar roles
|
||||
const userInfo = await userService.getUserInfo()
|
||||
const roles = userInfo.roles || []
|
||||
|
||||
const userInfo = await userService.getUserInfo();
|
||||
const roles = userInfo.roles || [];
|
||||
|
||||
// 3. Validar permissão
|
||||
const isAdmin = roles.includes('admin')
|
||||
const isGestor = roles.includes('gestor')
|
||||
const isMedico = roles.includes('medico')
|
||||
|
||||
const isAdmin = roles.includes("admin");
|
||||
const isGestor = roles.includes("gestor");
|
||||
const isMedico = roles.includes("medico");
|
||||
|
||||
if (!isAdmin && !isGestor && !isMedico) {
|
||||
toast.error("Você não tem permissão para acessar esta área")
|
||||
await authService.logout()
|
||||
return
|
||||
toast.error("Você não tem permissão para acessar esta área");
|
||||
await authService.logout();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 4. Redirecionar
|
||||
navigate('/painel-medico')
|
||||
}
|
||||
navigate("/painel-medico");
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
@ -462,7 +477,7 @@ npx wrangler pages deploy dist --project-name=mediconnect --commit-dirty=true
|
||||
|
||||
### Pré-requisitos
|
||||
|
||||
- Node.js 18+
|
||||
- Node.js 18+
|
||||
- pnpm 8+
|
||||
- Git
|
||||
|
||||
@ -522,6 +537,7 @@ VITE_APP_URL=http://localhost:5173
|
||||
### Tabelas Principais
|
||||
|
||||
#### `profiles`
|
||||
|
||||
```sql
|
||||
- id (uuid, PK)
|
||||
- email (text, unique)
|
||||
@ -532,6 +548,7 @@ VITE_APP_URL=http://localhost:5173
|
||||
```
|
||||
|
||||
#### `patients`
|
||||
|
||||
```sql
|
||||
- id (uuid, PK, FK -> profiles)
|
||||
- email (text, unique)
|
||||
@ -544,6 +561,7 @@ VITE_APP_URL=http://localhost:5173
|
||||
```
|
||||
|
||||
#### `doctors`
|
||||
|
||||
```sql
|
||||
- id (uuid, PK, FK -> profiles)
|
||||
- email (text, unique)
|
||||
@ -555,6 +573,7 @@ VITE_APP_URL=http://localhost:5173
|
||||
```
|
||||
|
||||
#### `appointments`
|
||||
|
||||
```sql
|
||||
- id (uuid, PK)
|
||||
- patient_id (uuid, FK -> patients)
|
||||
@ -567,6 +586,7 @@ VITE_APP_URL=http://localhost:5173
|
||||
```
|
||||
|
||||
#### `user_roles`
|
||||
|
||||
```sql
|
||||
- user_id (uuid, FK -> profiles)
|
||||
- role (text: admin, gestor, medico, secretaria, paciente)
|
||||
@ -621,9 +641,9 @@ node search-fernando.cjs
|
||||
|
||||
```typescript
|
||||
// Imports
|
||||
import React, { useState, useEffect } from "react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { serviceImport } from "../services"
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { serviceImport } from "../services";
|
||||
|
||||
// Types
|
||||
interface Props {
|
||||
@ -633,28 +653,24 @@ interface Props {
|
||||
// Component
|
||||
const ComponentName: React.FC<Props> = ({ ...props }) => {
|
||||
// Hooks
|
||||
const navigate = useNavigate()
|
||||
const [state, setState] = useState()
|
||||
|
||||
const navigate = useNavigate();
|
||||
const [state, setState] = useState();
|
||||
|
||||
// Effects
|
||||
useEffect(() => {
|
||||
// ...
|
||||
}, [])
|
||||
|
||||
}, []);
|
||||
|
||||
// Handlers
|
||||
const handleAction = async () => {
|
||||
// ...
|
||||
}
|
||||
|
||||
// Render
|
||||
return (
|
||||
<div>
|
||||
{/* JSX */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
export default ComponentName
|
||||
// Render
|
||||
return <div>{/* JSX */}</div>;
|
||||
};
|
||||
|
||||
export default ComponentName;
|
||||
```
|
||||
|
||||
---
|
||||
@ -670,6 +686,7 @@ export default ComponentName
|
||||
## 📝 Changelog
|
||||
|
||||
### v2.0.0 (Outubro 2024)
|
||||
|
||||
- ✅ Migração completa de Netlify Functions para Supabase
|
||||
- ✅ Implementação de recuperação de senha
|
||||
- ✅ Deploy no Cloudflare Pages
|
||||
@ -679,6 +696,7 @@ export default ComponentName
|
||||
- ✅ Interface responsiva e dark mode
|
||||
|
||||
### v1.0.0 (Setembro 2024)
|
||||
|
||||
- ✅ Lançamento inicial
|
||||
- ✅ Login de pacientes, médicos e secretárias
|
||||
- ✅ Agendamento de consultas
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user