feat(auth): Creates user in patient registration
- Adds automatic user creation in the new patient registration flow. - To avoid merge conflicts, the user and profile APIs have been separated from the main lib/api.ts file.
This commit is contained in:
parent
ba89bc17f2
commit
b577a418e1
@ -26,8 +26,9 @@ import {
|
||||
listarAnexos,
|
||||
removerAnexo,
|
||||
buscarPacientePorId,
|
||||
listarPerfis,
|
||||
} from "@/lib/api";
|
||||
import { listarPerfis } from "@/lib/api/perfis";
|
||||
import { criarUsuario } from "@/lib/api/usuarios";
|
||||
|
||||
type Mode = "create" | "edit";
|
||||
|
||||
@ -232,22 +233,20 @@ export function PatientRegistrationForm({
|
||||
if (mode === "create") {
|
||||
saved = await criarPaciente(payload);
|
||||
|
||||
console.log("--- INÍCIO DO TESTE DE API ---");
|
||||
console.log("Paciente recém-criado:", saved);
|
||||
try {
|
||||
console.log("Buscando lista de perfis para verificar a criação...");
|
||||
const perfis = await listarPerfis();
|
||||
console.log("Lista de Perfis encontrada:", perfis);
|
||||
const perfilCorrespondente = perfis.find(p => p.email === saved.email);
|
||||
if (perfilCorrespondente) {
|
||||
console.log("SUCESSO: Perfil correspondente foi encontrado!", perfilCorrespondente);
|
||||
} else {
|
||||
console.log("FALHA: Nenhum perfil correspondente ao email do paciente foi encontrado na lista de perfis.");
|
||||
if (saved.email && saved.nome) {
|
||||
try {
|
||||
await criarUsuario({
|
||||
email: saved.email,
|
||||
full_name: saved.nome,
|
||||
phone: saved.telefone || undefined,
|
||||
role: 'paciente',
|
||||
});
|
||||
} catch (userError) {
|
||||
console.error("Falha ao criar usuário para o paciente:", userError);
|
||||
// TODO: O que fazer se a criação do usuário falhar?
|
||||
// Por enquanto, apenas logamos o erro.
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("ERRO AO BUSCAR PERFIS:", error);
|
||||
}
|
||||
console.log("--- FIM DO TESTE DE API ---");
|
||||
|
||||
} else {
|
||||
if (patientId == null) throw new Error("Paciente inexistente para edição");
|
||||
|
||||
@ -60,7 +60,7 @@ export type PacienteInput = {
|
||||
|
||||
|
||||
|
||||
const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "https://mock.apidog.com/m1/1053378-0-default";
|
||||
export const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "https://mock.apidog.com/m1/1053378-0-default";
|
||||
const MEDICOS_BASE = process.env.NEXT_PUBLIC_MEDICOS_BASE_PATH ?? "/medicos";
|
||||
|
||||
export const PATHS = {
|
||||
@ -88,7 +88,7 @@ function getAuthToken(): string | null {
|
||||
return localStorage.getItem('auth_token');
|
||||
}
|
||||
|
||||
function headers(kind: "json" | "form" = "json"): Record<string, string> {
|
||||
export function headers(kind: "json" | "form" = "json"): Record<string, string> {
|
||||
const h: Record<string, string> = {};
|
||||
|
||||
// API Key da Supabase sempre necessária
|
||||
@ -104,7 +104,7 @@ function headers(kind: "json" | "form" = "json"): Record<string, string> {
|
||||
return h;
|
||||
}
|
||||
|
||||
function logAPI(title: string, info: { url?: string; payload?: any; result?: any } = {}) {
|
||||
export function logAPI(title: string, info: { url?: string; payload?: any; result?: any } = {}) {
|
||||
try {
|
||||
console.group(`[API] ${title}`);
|
||||
if (info.url) console.log("url:", info.url);
|
||||
@ -114,7 +114,7 @@ function logAPI(title: string, info: { url?: string; payload?: any; result?: any
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function parse<T>(res: Response): Promise<T> {
|
||||
export async function parse<T>(res: Response): Promise<T> {
|
||||
let json: any = null;
|
||||
try {
|
||||
json = await res.json();
|
||||
@ -344,135 +344,6 @@ export type MedicoInput = {
|
||||
valor_consulta?: number | string | null;
|
||||
};
|
||||
|
||||
//
|
||||
// Perfis de Usuário (Profiles)
|
||||
//
|
||||
|
||||
export type UserProfile = {
|
||||
id: string;
|
||||
full_name?: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
avatar_url?: string;
|
||||
disabled?: boolean;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
};
|
||||
|
||||
export type UserProfileInput = {
|
||||
full_name?: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
avatar_url?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export async function listarPerfis(params?: { page?: number; limit?: number; q?: string }): Promise<UserProfile[]> {
|
||||
const query = new URLSearchParams();
|
||||
if (params?.page) query.set("page", String(params.page));
|
||||
if (params?.limit) query.set("limit", String(params.limit));
|
||||
if (params?.q) query.set("q", params.q);
|
||||
const url = `${API_BASE}/rest/v1/profiles${query.toString() ? `?${query.toString()}` : ""}`;
|
||||
|
||||
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||
const data = await parse<ApiOk<UserProfile[]>>(res);
|
||||
logAPI("listarPerfis", { url, result: data });
|
||||
return data?.data ?? (data as any);
|
||||
}
|
||||
|
||||
export async function buscarPerfilPorId(id: string | number): Promise<UserProfile> {
|
||||
const url = `${API_BASE}/rest/v1/profiles?id=eq.${id}`;
|
||||
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||
// A API da Supabase/PostgREST retorna um array mesmo pedindo um ID, então pegamos o primeiro.
|
||||
const data = await parse<UserProfile[]>(res);
|
||||
const profile = data[0];
|
||||
logAPI("buscarPerfilPorId", { url, result: profile });
|
||||
return profile;
|
||||
}
|
||||
|
||||
export async function atualizarPerfil(id: string | number, input: UserProfileInput): Promise<UserProfile> {
|
||||
const url = `${API_BASE}/rest/v1/profiles?id=eq.${id}`;
|
||||
const res = await fetch(url, { method: "PATCH", headers: headers("json"), body: JSON.stringify(input) });
|
||||
// O método PATCH no PostgREST retorna um array vazio por padrão. Para retornar os dados, precisa de um header `Prefer: return=representation`
|
||||
// Por simplicidade, vamos assumir que se não deu erro, a operação foi um sucesso.
|
||||
// Se a API estiver configurada para retornar o objeto, o parse vai funcionar.
|
||||
const data = await parse<ApiOk<UserProfile>>(res);
|
||||
logAPI("atualizarPerfil", { url, payload: input, result: data });
|
||||
return data?.data ?? (data as any);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// User Management APIs
|
||||
//
|
||||
|
||||
export type UserRole = {
|
||||
id: string;
|
||||
user_id: string;
|
||||
role: 'admin' | 'medico' | 'paciente';
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
export type CreateUserInput = {
|
||||
email: string;
|
||||
password?: string;
|
||||
full_name: string;
|
||||
phone?: string;
|
||||
role: 'admin' | 'medico' | 'paciente';
|
||||
};
|
||||
|
||||
export type CreatedUser = {
|
||||
id: string;
|
||||
email: string;
|
||||
full_name: string;
|
||||
phone?: string;
|
||||
role: string;
|
||||
};
|
||||
|
||||
export type CompleteUserInfo = {
|
||||
user: {
|
||||
id: string;
|
||||
email: string;
|
||||
email_confirmed_at: string;
|
||||
created_at: string;
|
||||
last_sign_in_at: string;
|
||||
};
|
||||
profile: UserProfile;
|
||||
roles: string[];
|
||||
permissions: {
|
||||
isAdmin: boolean;
|
||||
isManager: boolean;
|
||||
isDoctor: boolean;
|
||||
isSecretary: boolean;
|
||||
isAdminOrManager: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export async function criarUsuario(input: CreateUserInput): Promise<{ success: boolean; user: CreatedUser }> {
|
||||
const url = `${API_BASE}/functions/v1/create-user`;
|
||||
const res = await fetch(url, { method: "POST", headers: headers("json"), body: JSON.stringify(input) });
|
||||
const data = await parse<any>(res);
|
||||
logAPI("criarUsuario", { url, payload: input, result: data });
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function listarUserRoles(): Promise<UserRole[]> {
|
||||
const url = `${API_BASE}/rest/v1/user_roles`;
|
||||
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||
const data = await parse<UserRole[]>(res);
|
||||
logAPI("listarUserRoles", { url, result: data });
|
||||
return data ?? [];
|
||||
}
|
||||
|
||||
export async function getCompleteUserInfo(userId: string): Promise<CompleteUserInfo> {
|
||||
const url = `${API_BASE}/functions/v1/user-info`;
|
||||
// Assuming the function takes the user ID in the body of a POST request
|
||||
const res = await fetch(url, { method: "POST", headers: headers("json"), body: JSON.stringify({ id: userId }) });
|
||||
const data = await parse<CompleteUserInfo>(res);
|
||||
logAPI("getCompleteUserInfo", { url, payload: { id: userId }, result: data });
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MÉDICOS (CRUD)
|
||||
|
||||
1
susconecta/lib/api/medicos.ts
Normal file
1
susconecta/lib/api/medicos.ts
Normal file
@ -0,0 +1 @@
|
||||
// Arquivo reservado para as APIs de Médicos
|
||||
1
susconecta/lib/api/pacientes.ts
Normal file
1
susconecta/lib/api/pacientes.ts
Normal file
@ -0,0 +1 @@
|
||||
// Arquivo reservado para as APIs de Pacientes
|
||||
64
susconecta/lib/api/perfis.ts
Normal file
64
susconecta/lib/api/perfis.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import {
|
||||
API_BASE,
|
||||
headers,
|
||||
logAPI,
|
||||
parse,
|
||||
} from "../api";
|
||||
import type { ApiOk } from "../api";
|
||||
|
||||
//
|
||||
// Perfis de Usuário (Profiles)
|
||||
//
|
||||
|
||||
export type UserProfile = {
|
||||
id: string;
|
||||
full_name?: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
avatar_url?: string;
|
||||
disabled?: boolean;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
};
|
||||
|
||||
export type UserProfileInput = {
|
||||
full_name?: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
avatar_url?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export async function listarPerfis(params?: { page?: number; limit?: number; q?: string }): Promise<UserProfile[]> {
|
||||
const query = new URLSearchParams();
|
||||
if (params?.page) query.set("page", String(params.page));
|
||||
if (params?.limit) query.set("limit", String(params.limit));
|
||||
if (params?.q) query.set("q", params.q);
|
||||
const url = `${API_BASE}/rest/v1/profiles${query.toString() ? `?${query.toString()}` : ""}`;
|
||||
|
||||
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||
const data = await parse<ApiOk<UserProfile[]>>(res);
|
||||
logAPI("listarPerfis", { url, result: data });
|
||||
return data?.data ?? (data as any);
|
||||
}
|
||||
|
||||
export async function buscarPerfilPorId(id: string | number): Promise<UserProfile> {
|
||||
const url = `${API_BASE}/rest/v1/profiles?id=eq.${id}`;
|
||||
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||
// A API da Supabase/PostgREST retorna um array mesmo pedindo um ID, então pegamos o primeiro.
|
||||
const data = await parse<UserProfile[]>(res);
|
||||
const profile = data[0];
|
||||
logAPI("buscarPerfilPorId", { url, result: profile });
|
||||
return profile;
|
||||
}
|
||||
|
||||
export async function atualizarPerfil(id: string | number, input: UserProfileInput): Promise<UserProfile> {
|
||||
const url = `${API_BASE}/rest/v1/profiles?id=eq.${id}`;
|
||||
const res = await fetch(url, { method: "PATCH", headers: headers("json"), body: JSON.stringify(input) });
|
||||
// O método PATCH no PostgREST retorna um array vazio por padrão. Para retornar os dados, precisa de um header `Prefer: return=representation`
|
||||
// Por simplicidade, vamos assumir que se não deu erro, a operação foi um sucesso.
|
||||
// Se a API estiver configurada para retornar o objeto, o parse vai funcionar.
|
||||
const data = await parse<ApiOk<UserProfile>>(res);
|
||||
logAPI("atualizarPerfil", { url, payload: input, result: data });
|
||||
return data?.data ?? (data as any);
|
||||
}
|
||||
79
susconecta/lib/api/usuarios.ts
Normal file
79
susconecta/lib/api/usuarios.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import {
|
||||
API_BASE,
|
||||
headers,
|
||||
logAPI,
|
||||
parse,
|
||||
} from "../api";
|
||||
import type { ApiOk } from "../api";
|
||||
import type { UserProfile } from "./perfis";
|
||||
|
||||
//
|
||||
// User Management APIs
|
||||
//
|
||||
|
||||
export type UserRole = {
|
||||
id: string;
|
||||
user_id: string;
|
||||
role: 'admin' | 'medico' | 'paciente';
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
export type CreateUserInput = {
|
||||
email: string;
|
||||
password?: string;
|
||||
full_name: string;
|
||||
phone?: string;
|
||||
role: 'admin' | 'medico' | 'paciente';
|
||||
};
|
||||
|
||||
export type CreatedUser = {
|
||||
id: string;
|
||||
email: string;
|
||||
full_name: string;
|
||||
phone?: string;
|
||||
role: string;
|
||||
};
|
||||
|
||||
export type CompleteUserInfo = {
|
||||
user: {
|
||||
id: string;
|
||||
email: string;
|
||||
email_confirmed_at: string;
|
||||
created_at: string;
|
||||
last_sign_in_at: string;
|
||||
};
|
||||
profile: UserProfile;
|
||||
roles: string[];
|
||||
permissions: {
|
||||
isAdmin: boolean;
|
||||
isManager: boolean;
|
||||
isDoctor: boolean;
|
||||
isSecretary: boolean;
|
||||
isAdminOrManager: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export async function criarUsuario(input: CreateUserInput): Promise<{ success: boolean; user: CreatedUser }> {
|
||||
const url = `${API_BASE}/functions/v1/create-user`;
|
||||
const res = await fetch(url, { method: "POST", headers: headers("json"), body: JSON.stringify(input) });
|
||||
const data = await parse<any>(res);
|
||||
logAPI("criarUsuario", { url, payload: input, result: data });
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function listarUserRoles(): Promise<UserRole[]> {
|
||||
const url = `${API_BASE}/rest/v1/user_roles`;
|
||||
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||
const data = await parse<UserRole[]>(res);
|
||||
logAPI("listarUserRoles", { url, result: data });
|
||||
return data ?? [];
|
||||
}
|
||||
|
||||
export async function getCompleteUserInfo(userId: string): Promise<CompleteUserInfo> {
|
||||
const url = `${API_BASE}/functions/v1/user-info`;
|
||||
// Assuming the function takes the user ID in the body of a POST request
|
||||
const res = await fetch(url, { method: "POST", headers: headers("json"), body: JSON.stringify({ id: userId }) });
|
||||
const data = await parse<CompleteUserInfo>(res);
|
||||
logAPI("getCompleteUserInfo", { url, payload: { id: userId }, result: data });
|
||||
return data;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user