feat(auth):refaz fluxo de cadastro
This commit is contained in:
parent
2161a9c210
commit
535f400f2d
@ -940,4 +940,251 @@ security:
|
||||
- bearer: []
|
||||
|
||||
```
|
||||
# Fazer login e obter token JWT
|
||||
|
||||
## OpenAPI Specification
|
||||
|
||||
```yaml
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: ''
|
||||
description: ''
|
||||
version: 1.0.0
|
||||
paths:
|
||||
/auth/v1/token:
|
||||
post:
|
||||
summary: Fazer login e obter token JWT
|
||||
deprecated: false
|
||||
description: >-
|
||||
Autentica o usuário e retorna um token JWT para usar em outras
|
||||
requisições.
|
||||
tags:
|
||||
- Authentication
|
||||
parameters:
|
||||
- name: grant_type
|
||||
in: query
|
||||
description: ''
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- password
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LoginRequest'
|
||||
examples: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Login realizado com sucesso
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LoginResponse'
|
||||
headers: {}
|
||||
x-apidog-name: OK
|
||||
'400':
|
||||
description: Credenciais inválidas
|
||||
content:
|
||||
application/json:
|
||||
schema: &ref_0
|
||||
$ref: '#/components/schemas/Error'
|
||||
headers: {}
|
||||
x-apidog-name: Bad Request
|
||||
'401':
|
||||
description: Email ou senha incorretos
|
||||
content:
|
||||
application/json:
|
||||
schema: *ref_0
|
||||
headers: {}
|
||||
x-apidog-name: Unauthorized
|
||||
security:
|
||||
- bearer: []
|
||||
x-apidog-folder: Authentication
|
||||
x-apidog-status: released
|
||||
x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940510-run
|
||||
components:
|
||||
schemas:
|
||||
LoginRequest:
|
||||
type: object
|
||||
required:
|
||||
- email
|
||||
- password
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
examples:
|
||||
- usuario@exemplo.com
|
||||
password:
|
||||
type: string
|
||||
minLength: 6
|
||||
examples:
|
||||
- senha123
|
||||
x-apidog-orders:
|
||||
- email
|
||||
- password
|
||||
x-apidog-ignore-properties: []
|
||||
x-apidog-folder: ''
|
||||
LoginResponse:
|
||||
type: object
|
||||
properties:
|
||||
access_token:
|
||||
type: string
|
||||
description: Token JWT para autenticação
|
||||
examples:
|
||||
- eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
token_type:
|
||||
type: string
|
||||
examples:
|
||||
- bearer
|
||||
expires_in:
|
||||
type: integer
|
||||
description: Tempo de expiração do token em segundos
|
||||
examples:
|
||||
- 3600
|
||||
refresh_token:
|
||||
type: string
|
||||
description: Token para renovar o access_token
|
||||
user:
|
||||
$ref: '#/components/schemas/AuthUser'
|
||||
x-apidog-orders:
|
||||
- access_token
|
||||
- token_type
|
||||
- expires_in
|
||||
- refresh_token
|
||||
- user
|
||||
x-apidog-ignore-properties: []
|
||||
x-apidog-folder: ''
|
||||
AuthUser:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
email_confirmed_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
x-apidog-orders:
|
||||
- id
|
||||
- email
|
||||
- email_confirmed_at
|
||||
- created_at
|
||||
x-apidog-ignore-properties: []
|
||||
x-apidog-folder: ''
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
code:
|
||||
type: string
|
||||
x-apidog-orders:
|
||||
- error
|
||||
- message
|
||||
- code
|
||||
x-apidog-ignore-properties: []
|
||||
x-apidog-folder: ''
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: jwt
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: Token JWT obtido no login
|
||||
bearer:
|
||||
type: http
|
||||
scheme: bearer
|
||||
servers:
|
||||
- url: https://yuanqfswhberkoevtmfr.supabase.co
|
||||
description: Prod Env
|
||||
- url: ''
|
||||
description: Cloud Mock
|
||||
security:
|
||||
- bearer: []
|
||||
|
||||
```
|
||||
|
||||
# Logout do usuário
|
||||
|
||||
## OpenAPI Specification
|
||||
|
||||
```yaml
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: ''
|
||||
description: ''
|
||||
version: 1.0.0
|
||||
paths:
|
||||
/auth/v1/logout:
|
||||
post:
|
||||
summary: Logout do usuário
|
||||
deprecated: false
|
||||
description: Encerrar sessão do usuário
|
||||
tags:
|
||||
- Authentication
|
||||
- Authentication
|
||||
parameters: []
|
||||
responses:
|
||||
'204':
|
||||
description: Logout realizado com sucesso
|
||||
headers: {}
|
||||
x-apidog-name: No Content
|
||||
'401':
|
||||
description: Token inválido
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
headers: {}
|
||||
x-apidog-name: Unauthorized
|
||||
security:
|
||||
- bearer: []
|
||||
x-apidog-folder: Authentication
|
||||
x-apidog-status: released
|
||||
x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940511-run
|
||||
components:
|
||||
schemas:
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
code:
|
||||
type: string
|
||||
x-apidog-orders:
|
||||
- error
|
||||
- message
|
||||
- code
|
||||
x-apidog-ignore-properties: []
|
||||
x-apidog-folder: ''
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: jwt
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: Token JWT obtido no login
|
||||
bearer:
|
||||
type: http
|
||||
scheme: bearer
|
||||
servers:
|
||||
- url: https://yuanqfswhberkoevtmfr.supabase.co
|
||||
description: Prod Env
|
||||
- url: ''
|
||||
description: Cloud Mock
|
||||
security:
|
||||
- bearer: []
|
||||
|
||||
```
|
||||
|
||||
|
||||
182
susconecta/ERRO_BACKEND_EDGE_FUNCTION.md
Normal file
182
susconecta/ERRO_BACKEND_EDGE_FUNCTION.md
Normal file
@ -0,0 +1,182 @@
|
||||
# 🚨 ERRO CRÍTICO NA EDGE FUNCTION - BACKEND
|
||||
|
||||
## Resumo do Problema
|
||||
|
||||
A Edge Function `/functions/v1/create-user` está retornando **erro 500** com mensagem:
|
||||
```json
|
||||
{ "error": "Failed to assign user role" }
|
||||
```
|
||||
|
||||
## Evidências
|
||||
|
||||
### Console do Frontend
|
||||
```
|
||||
XHRPOST https://yuanqfswhberkoevtmfr.supabase.co/functions/v1/create-user
|
||||
[HTTP/3 500 1065ms]
|
||||
|
||||
[API ERROR] https://yuanqfswhberkoevtmfr.supabase.co/functions/v1/create-user 500
|
||||
Object { error: "Failed to assign user role" }
|
||||
```
|
||||
|
||||
### Request Enviado (CORRETO)
|
||||
```json
|
||||
{
|
||||
"email": "dipar64745@fanlvr.com",
|
||||
"password": "senha789!",
|
||||
"full_name": "Jonas Francisco Nascimento Bonfim",
|
||||
"phone": "(79) 99649-8907",
|
||||
"role": "medico"
|
||||
}
|
||||
```
|
||||
|
||||
### Response Recebido (ERRO)
|
||||
```json
|
||||
{
|
||||
"error": "Failed to assign user role"
|
||||
}
|
||||
```
|
||||
|
||||
## Fluxo Atual (Correto segundo documentação)
|
||||
|
||||
1. ✅ Frontend cria perfil na tabela `doctors`
|
||||
2. ✅ Frontend gera senha aleatória
|
||||
3. ✅ Frontend chama `/functions/v1/create-user` com dados corretos
|
||||
4. ❌ **Edge Function falha ao atribuir role na tabela `user_roles`**
|
||||
|
||||
## O Que a Edge Function DEVE Fazer
|
||||
|
||||
Segundo a documentação da API (`Documentação API.md`), a Edge Function `/functions/v1/create-user` deve:
|
||||
|
||||
1. ✅ Criar usuário no Supabase Auth (isso está funcionando)
|
||||
2. ❌ **Inserir registro na tabela `user_roles`** (isso está falhando)
|
||||
3. ✅ Retornar `{ success: true, user: {...} }`
|
||||
|
||||
## Possíveis Causas do Erro
|
||||
|
||||
### 1. SUPABASE_SERVICE_ROLE_KEY não configurada
|
||||
A Edge Function precisa da `SUPABASE_SERVICE_ROLE_KEY` para ter permissão de:
|
||||
- Inserir na tabela `user_roles`
|
||||
- Fazer operações administrativas
|
||||
|
||||
**Como verificar:**
|
||||
1. Acesse o Supabase Dashboard
|
||||
2. Vá em **Edge Functions** > `create-user`
|
||||
3. Verifique se a variável de ambiente `SUPABASE_SERVICE_ROLE_KEY` está configurada
|
||||
4. Copie a chave de: **Settings** > **API** > **service_role key (secret)**
|
||||
|
||||
### 2. Tabela `user_roles` sem permissões corretas
|
||||
A tabela pode estar bloqueando inserções da Edge Function.
|
||||
|
||||
**Como verificar:**
|
||||
1. Acesse o Supabase Dashboard
|
||||
2. Vá em **Database** > **user_roles**
|
||||
3. Clique em **RLS Policies**
|
||||
4. Verifique se existe uma policy permitindo:
|
||||
- Service role pode inserir
|
||||
- OU Edge Function pode inserir usando service key
|
||||
|
||||
**Policy esperada:**
|
||||
```sql
|
||||
-- Permitir que service role insira roles
|
||||
CREATE POLICY "service_role_insert_user_roles"
|
||||
ON user_roles FOR INSERT
|
||||
TO service_role
|
||||
WITH CHECK (true);
|
||||
```
|
||||
|
||||
### 3. Código da Edge Function com bug
|
||||
O código da Edge Function pode ter erro de lógica ao tentar inserir na tabela.
|
||||
|
||||
**Onde encontrar:**
|
||||
- Supabase Dashboard > **Edge Functions** > `create-user` > **Editor**
|
||||
|
||||
**O que verificar:**
|
||||
```typescript
|
||||
// A Edge Function deve ter algo assim:
|
||||
const { data, error } = await supabaseAdmin
|
||||
.from('user_roles')
|
||||
.insert({
|
||||
user_id: newUser.id,
|
||||
role: role
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error('Erro ao inserir role:', error);
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Failed to assign user role' }),
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Como Testar Cada Possibilidade
|
||||
|
||||
### Teste 1: Verificar se service key está funcionando
|
||||
Execute no SQL Editor do Supabase:
|
||||
```sql
|
||||
-- Teste de inserção manual
|
||||
INSERT INTO user_roles (user_id, role)
|
||||
VALUES ('00000000-0000-0000-0000-000000000000', 'medico');
|
||||
|
||||
-- Se der erro, mostrará a mensagem de permissão
|
||||
```
|
||||
|
||||
### Teste 2: Verificar logs da Edge Function
|
||||
1. Acesse **Edge Functions** > `create-user`
|
||||
2. Clique em **Logs**
|
||||
3. Procure por erros detalhados quando o frontend faz a chamada
|
||||
|
||||
### Teste 3: Verificar estrutura da tabela
|
||||
```sql
|
||||
-- Verificar estrutura da tabela user_roles
|
||||
SELECT column_name, data_type, is_nullable
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'user_roles';
|
||||
```
|
||||
|
||||
Campos esperados:
|
||||
- `id` (uuid, primary key)
|
||||
- `user_id` (uuid, not null, foreign key para auth.users)
|
||||
- `role` (text ou enum, not null)
|
||||
- `created_at` (timestamp, default now())
|
||||
|
||||
## Solução Esperada do Backend
|
||||
|
||||
A equipe de backend precisa:
|
||||
|
||||
1. **URGENTE**: Configurar `SUPABASE_SERVICE_ROLE_KEY` na Edge Function
|
||||
2. **URGENTE**: Adicionar RLS policy para permitir inserções via service role
|
||||
3. **Recomendado**: Adicionar logs detalhados na Edge Function para debug
|
||||
4. **Recomendado**: Retornar erro mais específico (ex: "Permission denied to insert into user_roles")
|
||||
|
||||
## Status do Frontend
|
||||
|
||||
✅ **O código do frontend está 100% correto e seguindo a documentação!**
|
||||
|
||||
Não há nada a fazer no frontend. O erro está exclusivamente no backend.
|
||||
|
||||
## Workaround Temporário (NÃO RECOMENDADO)
|
||||
|
||||
Se o backend não puder resolver urgentemente, podemos:
|
||||
1. Criar usuários sem role (ou role padrão)
|
||||
2. Administrador atribui roles manualmente depois
|
||||
|
||||
Mas isso **NÃO É RECOMENDADO** porque:
|
||||
- Usuários não terão permissões corretas
|
||||
- Aumenta trabalho manual
|
||||
- Pode gerar problemas de segurança
|
||||
|
||||
## Contato
|
||||
|
||||
Frontend: ✅ Implementação completa e correta
|
||||
Backend: ❌ Precisa corrigir Edge Function `create-user`
|
||||
|
||||
**Prioridade:** 🔴 CRÍTICA - Sistema não consegue criar novos usuários
|
||||
|
||||
---
|
||||
|
||||
**Data do erro:** 10/10/2025
|
||||
**Ambiente:** https://yuanqfswhberkoevtmfr.supabase.co
|
||||
**Edge Function:** `/functions/v1/create-user`
|
||||
**Status Code:** 500
|
||||
**Mensagem:** "Failed to assign user role"
|
||||
158
susconecta/app/api/assign-role/route.ts
Normal file
158
susconecta/app/api/assign-role/route.ts
Normal file
@ -0,0 +1,158 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
|
||||
/**
|
||||
* Endpoint server-side para atribuir roles aos usuários
|
||||
* Usa SUPABASE_SERVICE_ROLE_KEY para realizar operações administrativas
|
||||
*
|
||||
* POST /api/assign-role
|
||||
* Body: { user_id: string, role: string }
|
||||
*/
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// 1. Verificar autenticação do requisitante
|
||||
const authHeader = request.headers.get('authorization');
|
||||
if (!authHeader) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Unauthorized', message: 'Token de autenticação não fornecido' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
// 2. Extrair dados do body
|
||||
const body = await request.json();
|
||||
const { user_id, role } = body;
|
||||
|
||||
if (!user_id || !role) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Bad Request', message: 'user_id e role são obrigatórios' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Validar role
|
||||
const validRoles = ['admin', 'gestor', 'medico', 'secretaria', 'user'];
|
||||
if (!validRoles.includes(role)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Bad Request', message: `Role inválido. Valores aceitos: ${validRoles.join(', ')}` },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 4. Obter service role key do ambiente
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
|
||||
if (!supabaseUrl || !serviceRoleKey) {
|
||||
console.error('❌ [ASSIGN-ROLE] SUPABASE_SERVICE_ROLE_KEY não configurada');
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Server Configuration Error',
|
||||
message: 'Service role key não configurada no servidor. Entre em contato com o administrador do sistema.',
|
||||
hint: 'Configure SUPABASE_SERVICE_ROLE_KEY nas variáveis de ambiente do servidor'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// 5. Criar cliente Supabase com service role key
|
||||
const supabaseAdmin = createClient(supabaseUrl, serviceRoleKey, {
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false,
|
||||
},
|
||||
});
|
||||
|
||||
// 6. Verificar se o usuário existe
|
||||
const { data: userData, error: userError } = await supabaseAdmin.auth.admin.getUserById(user_id);
|
||||
|
||||
if (userError || !userData) {
|
||||
console.error('❌ [ASSIGN-ROLE] Usuário não encontrado:', userError);
|
||||
return NextResponse.json(
|
||||
{ error: 'Not Found', message: 'Usuário não encontrado no sistema de autenticação' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`🔐 [ASSIGN-ROLE] Atribuindo role "${role}" ao usuário ${user_id}`);
|
||||
|
||||
// 7. Inserir role na tabela user_roles
|
||||
const { data: roleData, error: roleError } = await supabaseAdmin
|
||||
.from('user_roles')
|
||||
.insert({
|
||||
user_id: user_id,
|
||||
role: role,
|
||||
created_at: new Date().toISOString(),
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (roleError) {
|
||||
// Verificar se é erro de duplicação (usuário já tem esse role)
|
||||
if (roleError.code === '23505') {
|
||||
console.log(`⚠️ [ASSIGN-ROLE] Usuário já possui o role "${role}"`);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: true,
|
||||
message: `Usuário já possui o role "${role}"`,
|
||||
user_id,
|
||||
role,
|
||||
already_exists: true
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
console.error('❌ [ASSIGN-ROLE] Erro ao inserir role:', roleError);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Database Error',
|
||||
message: `Erro ao atribuir role: ${roleError.message}`,
|
||||
code: roleError.code,
|
||||
details: roleError.details
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`✅ [ASSIGN-ROLE] Role "${role}" atribuído com sucesso ao usuário ${user_id}`);
|
||||
|
||||
// 8. Retornar sucesso
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: true,
|
||||
message: `Role "${role}" atribuído com sucesso`,
|
||||
data: roleData,
|
||||
user_id,
|
||||
role,
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ [ASSIGN-ROLE] Erro inesperado:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Internal Server Error',
|
||||
message: 'Erro inesperado ao atribuir role',
|
||||
details: error?.message || String(error)
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Método OPTIONS para CORS (se necessário)
|
||||
export async function OPTIONS(request: NextRequest) {
|
||||
return NextResponse.json(
|
||||
{},
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -24,9 +24,7 @@ import {
|
||||
removerAnexoMedico,
|
||||
MedicoInput,
|
||||
Medico,
|
||||
criarUsuario,
|
||||
criarUsuarioDirectAuth,
|
||||
assignRoleServerSide,
|
||||
criarUsuarioMedico,
|
||||
gerarSenhaAleatoria,
|
||||
} from "@/lib/api";
|
||||
;
|
||||
@ -157,8 +155,13 @@ export function DoctorRegistrationForm({
|
||||
const [serverAnexos, setServerAnexos] = useState<any[]>([]);
|
||||
|
||||
// Estados para o dialog de credenciais
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [tempCredentials, setTempCredentials] = useState<{ email: string; password: string } | null>(null);
|
||||
const [showCredentialsDialog, setShowCredentialsDialog] = useState(false);
|
||||
const [credentials, setCredentials] = useState<{
|
||||
email: string;
|
||||
password: string;
|
||||
userName: string;
|
||||
userType: 'médico' | 'paciente';
|
||||
} | null>(null);
|
||||
|
||||
const title = useMemo(() => (mode === "create" ? "Cadastro de Médico" : "Editar Médico"), [mode]);
|
||||
|
||||
@ -395,38 +398,84 @@ async function handleSubmit(ev: React.FormEvent) {
|
||||
else onOpenChange?.(false);
|
||||
|
||||
} else {
|
||||
// --- NOVA LÓGICA DE CRIAÇÃO ---
|
||||
// --- FLUXO DE CRIAÇÃO DE MÉDICO ---
|
||||
console.log('🏥 [CRIAR MÉDICO] Iniciando processo completo...');
|
||||
|
||||
const medicoPayload = toPayload();
|
||||
console.log("Enviando os dados para a API:", medicoPayload);
|
||||
|
||||
// 1. Cria o perfil do médico na tabela doctors
|
||||
const savedDoctorProfile = await criarMedico(medicoPayload);
|
||||
console.log("✅ Perfil do médico criado:", savedDoctorProfile);
|
||||
|
||||
// ⚠️ IMPORTANTE: A criação de usuário de autenticação foi DESABILITADA temporariamente
|
||||
// porque a Edge Function /functions/v1/create-user está retornando erro 500 ao
|
||||
// tentar atribuir o role "medico" ao usuário.
|
||||
//
|
||||
// Para habilitar novamente, o backend precisa corrigir a Edge Function ou
|
||||
// configurar as permissões corretas na tabela user_roles.
|
||||
//
|
||||
// Por ora, apenas o perfil do médico será salvo na tabela "doctors".
|
||||
// O acesso ao sistema precisa ser criado manualmente pelo administrador.
|
||||
// 2. Cria usuário no Supabase Auth (direto via /auth/v1/signup)
|
||||
console.log('🔐 Criando usuário de autenticação...');
|
||||
|
||||
console.log("⚠️ Criação de usuário Auth desabilitada - salvando apenas perfil do médico");
|
||||
|
||||
alert(
|
||||
`✅ Médico cadastrado com sucesso!\n\n` +
|
||||
`📋 Perfil salvo na base de dados.\n\n` +
|
||||
`⚠️ IMPORTANTE: O acesso ao sistema (login) precisa ser criado manualmente.\n\n` +
|
||||
`Motivo: A função de criação automática de usuários está com problema no backend.\n` +
|
||||
`Entre em contato com o administrador do sistema para criar o acesso.`
|
||||
);
|
||||
|
||||
// Limpa formulário e fecha
|
||||
setForm(initial);
|
||||
setPhotoPreview(null);
|
||||
setServerAnexos([]);
|
||||
onSaved?.(savedDoctorProfile);
|
||||
if (inline) onClose?.();
|
||||
else onOpenChange?.(false);
|
||||
try {
|
||||
const authResponse = await criarUsuarioMedico({
|
||||
email: form.email,
|
||||
full_name: form.full_name,
|
||||
phone_mobile: form.celular || '',
|
||||
});
|
||||
|
||||
if (authResponse.success && authResponse.user) {
|
||||
console.log('✅ Usuário Auth criado:', authResponse.user.id);
|
||||
|
||||
// 3. Exibe popup com credenciais
|
||||
setCredentials({
|
||||
email: authResponse.email,
|
||||
password: authResponse.password,
|
||||
userName: form.full_name,
|
||||
userType: 'médico',
|
||||
});
|
||||
setShowCredentialsDialog(true);
|
||||
|
||||
// 4. Limpa formulário
|
||||
setForm(initial);
|
||||
setPhotoPreview(null);
|
||||
setServerAnexos([]);
|
||||
|
||||
// 5. Notifica componente pai
|
||||
onSaved?.(savedDoctorProfile);
|
||||
} else {
|
||||
throw new Error('Falha ao criar usuário de autenticação');
|
||||
}
|
||||
|
||||
} catch (authError: any) {
|
||||
console.error('❌ Erro ao criar usuário Auth:', authError);
|
||||
|
||||
const errorMsg = authError?.message || String(authError);
|
||||
|
||||
// Mensagens específicas de erro
|
||||
if (errorMsg.toLowerCase().includes('already registered') ||
|
||||
errorMsg.toLowerCase().includes('already been registered') ||
|
||||
errorMsg.toLowerCase().includes('já está cadastrado')) {
|
||||
alert(
|
||||
`⚠️ EMAIL JÁ CADASTRADO\n\n` +
|
||||
`O email "${form.email}" já possui uma conta no sistema.\n\n` +
|
||||
`✅ O perfil do médico "${form.full_name}" foi salvo com sucesso.\n\n` +
|
||||
`❌ Porém, não foi possível criar o login porque este email já está em uso.\n\n` +
|
||||
`SOLUÇÃO:\n` +
|
||||
`• Use um email diferente para este médico, OU\n` +
|
||||
`• Se o médico já tem conta, edite o perfil e vincule ao usuário existente`
|
||||
);
|
||||
} else {
|
||||
alert(
|
||||
`⚠️ Médico cadastrado com sucesso, mas houve um problema ao criar o acesso ao sistema.\n\n` +
|
||||
`✅ Perfil do médico salvo: ${form.full_name}\n\n` +
|
||||
`❌ Erro ao criar login: ${errorMsg}\n\n` +
|
||||
`Por favor, entre em contato com o administrador para criar o acesso manualmente.`
|
||||
);
|
||||
}
|
||||
|
||||
// Limpa formulário mesmo com erro
|
||||
setForm(initial);
|
||||
setPhotoPreview(null);
|
||||
setServerAnexos([]);
|
||||
onSaved?.(savedDoctorProfile);
|
||||
if (inline) onClose?.();
|
||||
else onOpenChange?.(false);
|
||||
}
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error("❌ Erro no handleSubmit:", err);
|
||||
@ -990,14 +1039,14 @@ async function handleSubmit(ev: React.FormEvent) {
|
||||
<div className="space-y-6">{content}</div>
|
||||
|
||||
{/* Dialog de credenciais */}
|
||||
{tempCredentials && (
|
||||
{credentials && (
|
||||
<CredentialsDialog
|
||||
open={dialogOpen}
|
||||
open={showCredentialsDialog}
|
||||
onOpenChange={(open) => {
|
||||
setDialogOpen(open);
|
||||
setShowCredentialsDialog(open);
|
||||
if (!open) {
|
||||
// Quando o dialog de credenciais fecha, fecha o formulário também
|
||||
setTempCredentials(null);
|
||||
setCredentials(null);
|
||||
if (inline) {
|
||||
onClose?.();
|
||||
} else {
|
||||
@ -1005,10 +1054,10 @@ async function handleSubmit(ev: React.FormEvent) {
|
||||
}
|
||||
}
|
||||
}}
|
||||
email={tempCredentials.email}
|
||||
password={tempCredentials.password}
|
||||
userName={form.full_name}
|
||||
userType="médico"
|
||||
email={credentials.email}
|
||||
password={credentials.password}
|
||||
userName={credentials.userName}
|
||||
userType={credentials.userType}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
@ -1029,20 +1078,20 @@ async function handleSubmit(ev: React.FormEvent) {
|
||||
</Dialog>
|
||||
|
||||
{/* Dialog de credenciais */}
|
||||
{tempCredentials && (
|
||||
{credentials && (
|
||||
<CredentialsDialog
|
||||
open={dialogOpen}
|
||||
open={showCredentialsDialog}
|
||||
onOpenChange={(open) => {
|
||||
setDialogOpen(open);
|
||||
setShowCredentialsDialog(open);
|
||||
if (!open) {
|
||||
setTempCredentials(null);
|
||||
setCredentials(null);
|
||||
onOpenChange?.(false);
|
||||
}
|
||||
}}
|
||||
email={tempCredentials.email}
|
||||
password={tempCredentials.password}
|
||||
userName={form.full_name}
|
||||
userType="médico"
|
||||
email={credentials.email}
|
||||
password={credentials.password}
|
||||
userName={credentials.userName}
|
||||
userType={credentials.userType}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -24,9 +24,7 @@ import {
|
||||
listarAnexos,
|
||||
removerAnexo,
|
||||
buscarPacientePorId,
|
||||
criarUsuario,
|
||||
gerarSenhaAleatoria,
|
||||
CreateUserResponse,
|
||||
criarUsuarioPaciente,
|
||||
criarPaciente,
|
||||
} from "@/lib/api";
|
||||
|
||||
@ -106,8 +104,13 @@ export function PatientRegistrationForm({
|
||||
const [serverAnexos, setServerAnexos] = useState<any[]>([]);
|
||||
|
||||
// Estados para o dialog de credenciais
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [tempCredentials, setTempCredentials] = useState<{ email: string; password: string } | null>(null);
|
||||
const [showCredentialsDialog, setShowCredentialsDialog] = useState(false);
|
||||
const [credentials, setCredentials] = useState<{
|
||||
email: string;
|
||||
password: string;
|
||||
userName: string;
|
||||
userType: 'médico' | 'paciente';
|
||||
} | null>(null);
|
||||
|
||||
const title = useMemo(() => (mode === "create" ? "Cadastro de Paciente" : "Editar Paciente"), [mode]);
|
||||
|
||||
@ -273,43 +276,41 @@ export function PatientRegistrationForm({
|
||||
console.log("✅ Perfil do paciente criado:", savedPatientProfile);
|
||||
|
||||
if (form.email && form.email.includes('@')) {
|
||||
const tempPassword = gerarSenhaAleatoria();
|
||||
const userInput = {
|
||||
email: form.email,
|
||||
password: tempPassword,
|
||||
full_name: form.nome,
|
||||
phone: form.telefone,
|
||||
role: 'user' as const,
|
||||
};
|
||||
|
||||
console.log("🔐 Criando usuário de autenticação com payload:", userInput);
|
||||
|
||||
console.log("🔐 Criando usuário de autenticação (paciente)...");
|
||||
try {
|
||||
const userResponse = await criarUsuario(userInput);
|
||||
const userResponse = await criarUsuarioPaciente({
|
||||
email: form.email,
|
||||
full_name: form.nome,
|
||||
phone_mobile: form.telefone,
|
||||
});
|
||||
|
||||
if (userResponse.success && userResponse.user) {
|
||||
console.log("✅ Usuário de autenticação criado:", userResponse.user);
|
||||
|
||||
// Mostra credenciais (NÃO fecha o formulário ainda)
|
||||
setTempCredentials({ email: form.email, password: tempPassword });
|
||||
setDialogOpen(true);
|
||||
|
||||
|
||||
// Mostra credenciais no dialog usando as credenciais retornadas
|
||||
setCredentials({
|
||||
email: userResponse.email ?? form.email,
|
||||
password: userResponse.password ?? '',
|
||||
userName: form.nome,
|
||||
userType: 'paciente',
|
||||
});
|
||||
setShowCredentialsDialog(true);
|
||||
|
||||
// Limpa formulário mas NÃO fecha ainda - fechará quando o dialog de credenciais fechar
|
||||
setForm(initial);
|
||||
setPhotoPreview(null);
|
||||
setServerAnexos([]);
|
||||
onSaved?.(savedPatientProfile);
|
||||
// NÃO chama onClose ou onOpenChange aqui - deixa o dialog de credenciais fazer isso
|
||||
return;
|
||||
return;
|
||||
} else {
|
||||
throw new Error((userResponse as any).message || "Falhou ao criar o usuário de acesso.");
|
||||
}
|
||||
} catch (userError: any) {
|
||||
console.error("❌ Erro ao criar usuário via função server-side:", userError);
|
||||
|
||||
console.error("❌ Erro ao criar usuário via signup:", userError);
|
||||
|
||||
// Mensagem de erro específica para email duplicado
|
||||
const errorMsg = userError?.message || String(userError);
|
||||
|
||||
|
||||
if (errorMsg.toLowerCase().includes('already registered') ||
|
||||
errorMsg.toLowerCase().includes('já está cadastrado') ||
|
||||
errorMsg.toLowerCase().includes('já existe')) {
|
||||
@ -318,18 +319,6 @@ export function PatientRegistrationForm({
|
||||
`✅ O perfil do paciente foi salvo com sucesso.\n\n` +
|
||||
`Para criar acesso ao sistema, use um email diferente ou recupere a senha do email existente.`
|
||||
);
|
||||
} else if (errorMsg.toLowerCase().includes('failed to assign user role') ||
|
||||
errorMsg.toLowerCase().includes('atribuir permissões')) {
|
||||
alert(
|
||||
`⚠️ PROBLEMA NA CONFIGURAÇÃO DO SISTEMA\n\n` +
|
||||
`✅ O perfil do paciente foi salvo com sucesso.\n\n` +
|
||||
`❌ Porém, houve falha ao atribuir permissões de acesso.\n\n` +
|
||||
`Esse erro indica que a Edge Function do Supabase não está configurada corretamente.\n\n` +
|
||||
`Entre em contato com o administrador do sistema para:\n` +
|
||||
`1. Verificar se a service role key está configurada\n` +
|
||||
`2. Verificar as permissões da tabela user_roles\n` +
|
||||
`3. Revisar o código da Edge Function create-user`
|
||||
);
|
||||
} else {
|
||||
alert(
|
||||
`✅ Paciente cadastrado com sucesso!\n\n` +
|
||||
@ -337,7 +326,7 @@ export function PatientRegistrationForm({
|
||||
`O cadastro do paciente foi salvo, mas será necessário criar o acesso manualmente.`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Limpa formulário e fecha
|
||||
setForm(initial);
|
||||
setPhotoPreview(null);
|
||||
@ -715,14 +704,14 @@ export function PatientRegistrationForm({
|
||||
<div className="space-y-6">{content}</div>
|
||||
|
||||
{/* Dialog de credenciais */}
|
||||
{tempCredentials && (
|
||||
{credentials && (
|
||||
<CredentialsDialog
|
||||
open={dialogOpen}
|
||||
open={showCredentialsDialog}
|
||||
onOpenChange={(open) => {
|
||||
setDialogOpen(open);
|
||||
setShowCredentialsDialog(open);
|
||||
if (!open) {
|
||||
// Quando o dialog de credenciais fecha, fecha o formulário também
|
||||
setTempCredentials(null);
|
||||
setCredentials(null);
|
||||
if (inline) {
|
||||
onClose?.();
|
||||
} else {
|
||||
@ -730,10 +719,10 @@ export function PatientRegistrationForm({
|
||||
}
|
||||
}
|
||||
}}
|
||||
email={tempCredentials.email}
|
||||
password={tempCredentials.password}
|
||||
userName={form.nome}
|
||||
userType="paciente"
|
||||
email={credentials.email}
|
||||
password={credentials.password}
|
||||
userName={credentials.userName}
|
||||
userType={credentials.userType}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
@ -754,20 +743,20 @@ export function PatientRegistrationForm({
|
||||
</Dialog>
|
||||
|
||||
{/* Dialog de credenciais */}
|
||||
{tempCredentials && (
|
||||
{credentials && (
|
||||
<CredentialsDialog
|
||||
open={dialogOpen}
|
||||
open={showCredentialsDialog}
|
||||
onOpenChange={(open) => {
|
||||
setDialogOpen(open);
|
||||
setShowCredentialsDialog(open);
|
||||
if (!open) {
|
||||
setTempCredentials(null);
|
||||
setCredentials(null);
|
||||
onOpenChange?.(false);
|
||||
}
|
||||
}}
|
||||
email={tempCredentials.email}
|
||||
password={tempCredentials.password}
|
||||
userName={form.nome}
|
||||
userType="paciente"
|
||||
email={credentials.email}
|
||||
password={credentials.password}
|
||||
userName={credentials.userName}
|
||||
userType={credentials.userType}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user