Auth service

Let’s refactor the authentication mechanism.

Create a User model to store user settings and preference in /src/app/_models/user.model.ts

export interface User {
  uid: string;
  email: string;
  photoURL?: string;
  displayName?: string;
}

Then use the new implementation of the auth service with persistence of the user preference in Firestore and localstorage.

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, of } from 'rxjs';
import { switchMap, tap, startWith } from 'rxjs/operators';

import { User } from '../_models/user.model';

import { auth } from 'firebase';
import { AngularFireAuth } from '@angular/fire/auth';
import {
  AngularFirestore,
  AngularFirestoreDocument
} from '@angular/fire/firestore';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  user: Observable<User>;

  constructor(
    private afAuth: AngularFireAuth,
    private afs: AngularFirestore,
    private router: Router
  ) {
    // Get auth data, then get firestore user document || null
    this.user = this.afAuth.authState.pipe(
      switchMap(user => {
        if (user) {
          return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
        } else {
          return of(null);
        }
      }),
      // Set/read the user data to local storage
      // this avoids flickering on application startup
      tap(user => localStorage.setItem('user', JSON.stringify(user))),
      startWith(JSON.parse(localStorage.getItem('user')))
    );
  }

  googleLogin() {
    const provider = new auth.GoogleAuthProvider();
    return this.oAuthLogin(provider);
  }

  private oAuthLogin(provider) {
    this.afAuth.auth.signInWithPopup(provider).then(
      userCredential => {
        // Sets user data to firestore on login
        this.updateUserData(userCredential.user);
      },
      error => {
        console.log('Error during login');
        console.log(error);
      }
    );
  }

  logout() {
    this.afAuth.auth.signOut().then(() => {
      this.router.navigate(['/']);
    });
  }

  private updateUserData(fbUser: firebase.User) {
    const userRef: AngularFirestoreDocument<any> = this.afs.doc(
      `users/${fbUser.uid}`
    );

    const user: User = {
      uid: fbUser.uid,
      email: fbUser.email,
      displayName: fbUser.displayName,
      photoURL: fbUser.photoURL
    };

    return userRef.set(user, { merge: true });
  }
}