import { Injectable, OnDestroy, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, BehaviorSubject, ReplaySubject, Subscription } from 'rxjs'; import { distinctUntilChanged, take, tap } from 'rxjs/operators'; import { User } from '@models'; import { JwtService } from '@services'; @Injectable({ providedIn: 'root' }) export class UserService implements OnDestroy { private readonly http = inject(HttpClient); private readonly jwtService = inject(JwtService); private _subcriptions: Array = new Array(); private _user: Subscription = new Subscription(); private currentUserSubject = new BehaviorSubject({} as User); public currentUser = this.currentUserSubject.asObservable().pipe(distinctUntilChanged()); private isAuthenticatedSubject = new ReplaySubject(1); public isAuthenticated = this.isAuthenticatedSubject.asObservable(); private _apiDomain = '/cms'; ngOnDestroy() { this._subcriptions.forEach((subscription: Subscription) => subscription.unsubscribe()); } // Verify JWT in localstorage with server & load user's info. // This runs once on application startup. populate() { // If JWT detected, attempt to get & store user's info if (this.jwtService.getToken()) { const user$: Observable<{ user: User }> = this.http .get<{ user: User }>(`${this._apiDomain}/user`) .pipe(take(1)); this._user = user$.subscribe({ next: (data) => this.setAuth(data.user), error: () => this.purgeAuth(), }); this._subcriptions.push(this._user); } else { // Remove any potential remnants of previous auth states this.purgeAuth(); } } setAuth(user: User) { // Save JWT sent from server in localstorage this.jwtService.saveToken(user.token); // Set current user data into observable this.currentUserSubject.next(user); // Set isAuthenticated to true this.isAuthenticatedSubject.next(true); } purgeAuth() { // Remove JWT from localstorage this.jwtService.destroyToken(); // Set current user to an empty object this.currentUserSubject.next({} as User); // Set auth status to false this.isAuthenticatedSubject.next(false); } attemptAuth(type: string, credentials?: { email: string; password: string }): Observable<{ user: User }> { const route = type === 'login' ? '/login' : ''; const user$: Observable<{ user: User }> = this.http.post<{ user: User }>(`${this._apiDomain}/user${route}`, { user: credentials, }); /*return user$.pipe(map( (data: any) => { this.setAuth(data.user); return data; } ));*/ return user$.pipe(tap(({ user }) => this.setAuth(user))); } getCurrentUser(): User { return this.currentUserSubject.value; } canAdministrate(): boolean { return this.currentUserSubject.value.role == 'Admin' ? true : false; } // Update the user on the server (email, pass, etc) update(user: Partial): Observable<{ user: User }> { return this.http.put<{ user: User }>(`${this._apiDomain}/user`, { user }).pipe( tap(({ user }) => { this.currentUserSubject.next(user); }), ); } }