feat: add user authentication UI to header component

Add login and register dialogs, user dropdown menu with profile link and logout option, and integrate with session management hook. Prevent hydration mismatches by conditionally rendering auth elements after mount. Update package-lock.json with new @esbuild dependencies for build tooling.
This commit is contained in:
Evandro Fonseca Junior committed 2025-11-04 02:33:29 -03:00
1 parent e641138887
commit 55eebde0ba
55 files changed
+7353 -7

No files matched your search

+136
View File
@@ -0,0 +1,136 @@
import { NextRequest, NextResponse } from "next/server";
import { cookies } from "next/headers";
import { secureLogger } from "@/lib/secure-logger";
import { getSession, refreshSession, deleteSession } from "@/lib/redis/session";
import { verifyAccessToken } from "@/lib/auth/jwt";
/**
* GET /api/auth/session
* Verifica e retorna dados da sessão atual
*/
export async function GET(request: NextRequest) {
try {
// Buscar sessionId do cookie
const cookieStore = await cookies();
const sessionId = cookieStore.get("sessionId")?.value;
if (!sessionId) {
return NextResponse.json(
{
success: false,
authenticated: false,
error: "Nenhuma sessão encontrada",
},
{ status: 401 }
);
}
// Buscar sessão no Redis
const session = await getSession(sessionId);
if (!session) {
// Limpar cookie se sessão não existe
const response = NextResponse.json(
{
success: false,
authenticated: false,
error: "Sessão expirada ou inválida",
},
{ status: 401 }
);
response.cookies.delete("sessionId");
return response;
}
// Verificar se o access token ainda é válido
const tokenPayload = verifyAccessToken(session.accessToken);
if (!tokenPayload) {
// Token expirado - remover sessão
await deleteSession(sessionId);
const response = NextResponse.json(
{
success: false,
authenticated: false,
error: "Token expirado",
},
{ status: 401 }
);
response.cookies.delete("sessionId");
return response;
}
// Atualizar TTL da sessão
await refreshSession(sessionId);
return NextResponse.json(
{
success: true,
authenticated: true,
user: {
userId: session.userId,
username: session.username,
email: session.email,
},
},
{ status: 200 }
);
} catch (error) {
secureLogger.error("❌ Erro ao verificar sessão", {
error: error instanceof Error ? error.message : "Erro desconhecido",
stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(),
});
return NextResponse.json(
{
success: false,
authenticated: false,
error: error instanceof Error ? error.message : "Erro interno",
},
{ status: 500 }
);
}
}
/**
* DELETE /api/auth/session
* Encerra a sessão atual
*/
export async function DELETE(request: NextRequest) {
try {
const cookieStore = await cookies();
const sessionId = cookieStore.get("sessionId")?.value;
if (sessionId) {
await deleteSession(sessionId);
}
const response = NextResponse.json(
{
success: true,
message: "Sessão encerrada",
},
{ status: 200 }
);
response.cookies.delete("sessionId");
return response;
} catch (error) {
secureLogger.error("❌ Erro ao encerrar sessão", {
error: error instanceof Error ? error.message : "Erro desconhecido",
timestamp: new Date().toISOString(),
});
return NextResponse.json(
{
success: false,
error: error instanceof Error ? error.message : "Erro interno",
},
{ status: 500 }
);
}
}