import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject, Observable, tap } from 'rxjs'; import { Router, ActivatedRoute } from '@angular/router'; import { LoginRequest } from '../model/auth/LoginRequest'; import { RegisterRequest } from '../model/auth/RegisterRequest'; import { AuthResponse } from '../model/auth/AuthResponse'; import { User } from '../model/User'; import { environment } from '@environments/environment'; const TOKEN_KEY = 'token'; const USER_KEY = 'user'; @Injectable({ providedIn: 'root', }) export class AuthService { private authUrl = `${environment.apiUrl}/auth`; private userUrl = `${environment.apiUrl}/users`; private oauthUrl = `${environment.apiUrl}/oauth2`; private http = inject(HttpClient); private router = inject(Router); private route = inject(ActivatedRoute); userSubject: BehaviorSubject; constructor() { this.userSubject = new BehaviorSubject(this.getUserFromStorage()); // Check for token in URL (OAuth callback) on initialization this.route.queryParams.subscribe((params) => { const token = params['token']; if (token) { this.handleOAuthCallback(token); } }); if (this.getToken()) { this.loadCurrentUser(); } } private handleOAuthCallback(token: string): void { this.setToken(token); this.loadCurrentUser(); // Clean up the URL by removing the token this.router.navigate([], { relativeTo: this.route, queryParams: {}, replaceUrl: true, }); } public get currentUserValue(): User | null { return this.userSubject.value; } login(loginRequest: LoginRequest): Observable { return this.http.post(`${this.authUrl}/login`, loginRequest).pipe( tap((response) => { this.setToken(response.token); this.loadCurrentUser(); }) ); } register(registerRequest: RegisterRequest): Observable { return this.http.post(`${this.authUrl}/register`, registerRequest); } githubAuth(code: string): Observable { return this.http.post(`${this.oauthUrl}/github/callback`, { code }).pipe( tap((response) => { console.log(response.token); this.setToken(response.token); this.loadCurrentUser(); }) ); } googleAuth(code: string): Observable { return this.http.post(`${this.oauthUrl}/google/callback`, { code }).pipe( tap((response) => { this.setToken(response.token); this.loadCurrentUser(); }) ); } logout(): void { localStorage.removeItem(TOKEN_KEY); localStorage.removeItem(USER_KEY); this.userSubject.next(null); this.router.navigate(['/']); } isLoggedIn(): boolean { return !!this.getToken(); } getToken(): string | null { return localStorage.getItem(TOKEN_KEY); } public loadCurrentUser(): void { this.http.get(`${this.userUrl}/me`).subscribe({ next: (user) => { this.setUser(user); }, error: () => { this.logout(); }, }); } public verifyEmail(token: string): Observable { return this.http.post(`${this.authUrl}/verify?token=${token}`, null); } public recoverPassword(email: string): Observable { return this.http.post(`${this.authUrl}/recover-password?email=${email}`, null); } public resetPassword(token: string, password: string): Observable { return this.http.post(`${this.authUrl}/reset-password`, { token, password }); } private setToken(token: string): void { localStorage.setItem(TOKEN_KEY, token); } private setUser(user: User): void { localStorage.setItem(USER_KEY, JSON.stringify(user)); this.userSubject.next(user); } private getUserFromStorage(): User | null { const user = localStorage.getItem(USER_KEY); return user ? JSON.parse(user) : null; } getUser(): User | null { return this.currentUserValue; } }