feat(auth): Implements user API and fixes login flows.

- Adds new API functions for user management (createUser, etc.).    - Fixes multiple bugs that prevented administrator login and broke the project build.
This commit is contained in:
M-Gabrielly 2025-09-30 01:14:41 -03:00
parent 576c0d53b4
commit ba89bc17f2
5 changed files with 116 additions and 52 deletions

View File

@ -76,7 +76,7 @@ export default function DoutoresPage() {
} }
return ( return (
<ProtectedRoute requiredUserType={['administrador']}> // <-- REGRA APLICADA <>
{showForm ? ( {showForm ? (
<div className="space-y-6 p-6"> <div className="space-y-6 p-6">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
@ -233,6 +233,6 @@ export default function DoutoresPage() {
</div> </div>
</div> </div>
)} )}
</ProtectedRoute> </>
); );
} }

View File

@ -16,31 +16,36 @@ export default function LoginAdminPage() {
const router = useRouter() const router = useRouter()
const { login } = useAuth() const { login } = useAuth()
const handleLogin = async (e: React.FormEvent) => { const handleLogin = async (e: React.MouseEvent) => {
e.preventDefault() e.preventDefault();
setLoading(true) console.log('[LOGIN-DEBUG] 1. handleLogin iniciado.');
setError('') setLoading(true);
setError('');
try { try {
// Tentar fazer login usando o contexto com tipo administrador console.log('[LOGIN-DEBUG] 2. Chamando a função de login do useAuth...');
const success = await login(credentials.email, credentials.password, 'administrador') const success = await login(credentials.email, credentials.password, 'administrador');
console.log('[LOGIN-DEBUG] 3. A função de login retornou:', success);
if (success) { if (success) {
console.log('[LOGIN-ADMIN] Login bem-sucedido, redirecionando...') console.log('[LOGIN-DEBUG] 4. Sucesso! Redirecionando para /dashboard...');
window.location.href = '/dashboard';
// Redirecionamento direto - solução que funcionou } else {
window.location.href = '/dashboard' console.log('[LOGIN-DEBUG] 4b. A função de login retornou um valor falso, mas não lançou erro.');
setError('Ocorreu uma falha inesperada no login.');
} }
} catch (err) { } catch (err) {
console.error('[LOGIN-ADMIN] Erro no login:', err) console.log('[LOGIN-DEBUG] 5. Ocorreu um erro (catch).');
console.error('[LOGIN-ADMIN] Erro no login:', err);
if (err instanceof AuthenticationError) { if (err instanceof AuthenticationError) {
setError(err.message) setError(err.message);
} else { } else {
setError('Erro inesperado. Tente novamente.') setError('Erro inesperado. Tente novamente.');
} }
} finally { } finally {
setLoading(false) console.log('[LOGIN-DEBUG] 6. Bloco finally executado.');
setLoading(false);
} }
} }
@ -61,7 +66,7 @@ export default function LoginAdminPage() {
<CardTitle className="text-center">Acesso Administrativo</CardTitle> <CardTitle className="text-center">Acesso Administrativo</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<form onSubmit={handleLogin} className="space-y-6"> <form onSubmit={(e) => e.preventDefault()} className="space-y-6">
<div> <div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700"> <label htmlFor="email" className="block text-sm font-medium text-gray-700">
Email Email
@ -101,7 +106,8 @@ export default function LoginAdminPage() {
)} )}
<Button <Button
type="submit" type="button"
onClick={handleLogin}
className="w-full cursor-pointer" className="w-full cursor-pointer"
disabled={loading} disabled={loading}
> >

View File

@ -26,6 +26,7 @@ import {
listarAnexos, listarAnexos,
removerAnexo, removerAnexo,
buscarPacientePorId, buscarPacientePorId,
listarPerfis,
} from "@/lib/api"; } from "@/lib/api";
type Mode = "create" | "edit"; type Mode = "create" | "edit";
@ -230,11 +231,28 @@ export function PatientRegistrationForm({
let saved: Paciente; let saved: Paciente;
if (mode === "create") { if (mode === "create") {
saved = await criarPaciente(payload); 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.");
}
} catch (error) {
console.error("ERRO AO BUSCAR PERFIS:", error);
}
console.log("--- FIM DO TESTE DE API ---");
} else { } else {
if (patientId == null) throw new Error("Paciente inexistente para edição"); if (patientId == null) throw new Error("Paciente inexistente para edição");
saved = await atualizarPaciente(String(patientId), payload); saved = await atualizarPaciente(String(patientId), payload);
} }
if (form.photo && saved?.id) { if (form.photo && saved?.id) {
try { try {
await uploadFotoPaciente(saved.id, form.photo); await uploadFotoPaciente(saved.id, form.photo);

View File

@ -402,6 +402,78 @@ export async function atualizarPerfil(id: string | number, input: UserProfileInp
} }
//
// 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) // MÉDICOS (CRUD)
// //

View File

@ -119,39 +119,7 @@ export async function loginUser(
body: JSON.stringify(payload), body: JSON.stringify(payload),
}); });
// Se login falhar com 400, tentar criar usuário automaticamente
if (!response.ok && response.status === 400) {
console.log('[AUTH-API] Login falhou (400), tentando criar usuário...');
const signupUrl = `${ENV_CONFIG.SUPABASE_URL}/auth/v1/signup`;
const signupPayload = {
email,
password,
data: {
userType: userType,
name: email.split('@')[0],
}
};
debugRequest('POST', signupUrl, getLoginHeaders(), signupPayload);
const signupResponse = await fetch(signupUrl, {
method: 'POST',
headers: getLoginHeaders(),
body: JSON.stringify(signupPayload),
});
if (signupResponse.ok) {
console.log('[AUTH-API] Usuário criado, tentando login novamente...');
await new Promise(resolve => setTimeout(resolve, 100));
response = await fetch(url, {
method: 'POST',
headers: getLoginHeaders(),
body: JSON.stringify(payload),
});
}
}
console.log(`[AUTH-API] Login response: ${response.status} ${response.statusText}`, { console.log(`[AUTH-API] Login response: ${response.status} ${response.statusText}`, {
url: response.url, url: response.url,