feat(auth): implement Google OAuth login flow and handle session clearing on 401

This commit is contained in:
2026-07-22 17:01:11 -03:00
parent c662c27fc7
commit 20c8b04638
4 changed files with 92 additions and 13 deletions

View File

@@ -81,7 +81,8 @@
variant="neutral-outline"
hostClass="w-100 d-block"
buttonClass="w-100 d-inline-flex align-items-center justify-content-center gap-2 py-2 fw-semibold"
[disabled]="true"
[disabled]="isSubmitting()"
(click)="loginWithGoogle()"
>
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@@ -1,7 +1,7 @@
import { DOCUMENT } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject, PLATFORM_ID, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../../../../core/services/auth/auth.service';
import { ButtonComponent } from '../../../../shared/components/button/button.component';
@@ -20,8 +20,10 @@ const EMAIL_MAX_LENGTH = 255;
export class LoginPageComponent {
private readonly formBuilder = inject(FormBuilder);
private readonly router = inject(Router);
private readonly route = inject(ActivatedRoute);
private readonly authService = inject(AuthService);
private readonly document = inject(DOCUMENT);
private readonly platformId = inject(PLATFORM_ID);
private readonly submittedState = signal(false);
private readonly serverErrorState = signal<string | null>(null);
@@ -35,6 +37,18 @@ export class LoginPageComponent {
protected readonly serverError = this.serverErrorState.asReadonly();
protected readonly isSubmitting = this.isSubmittingState.asReadonly();
ngOnInit(): void {
if (!isPlatformBrowser(this.platformId)) {
return;
}
const oauthCode = this.route.snapshot.queryParamMap.get('oauth_code');
if (oauthCode) {
this.completeGoogleLogin(oauthCode);
}
}
goToRegister(): void {
void this.router.navigate(['/register']);
}
@@ -62,6 +76,16 @@ export class LoginPageComponent {
});
}
loginWithGoogle(): void {
this.serverErrorState.set(null);
try {
this.authService.loginWithGoogle();
} catch (error: unknown) {
this.serverErrorState.set(this.resolveErrorMessage(error));
}
}
protected updateEmail(value: string | number): void {
this.form.controls.email.setValue(String(value));
}
@@ -107,6 +131,22 @@ export class LoginPageComponent {
this.document.location.assign(homeUrl);
}
private completeGoogleLogin(oauthCode: string): void {
this.isSubmittingState.set(true);
this.serverErrorState.set(null);
this.authService.completeGoogleLogin(oauthCode).subscribe({
next: () => {
this.isSubmittingState.set(false);
this.redirectToHome();
},
error: (error: unknown) => {
this.isSubmittingState.set(false);
this.serverErrorState.set(this.resolveErrorMessage(error));
}
});
}
private resolveErrorMessage(error: unknown): string {
const errorPayload =
typeof error === 'object' && error !== null && 'error' in error