I'm still quite new to Angular, and the project that I'm currently working on is using Firebase for database, hosting, and authorization purposes. I have been following some tutorials from the web and I am stuck. The Sign-up and Sign-In functions are not working as intended because my userModel must be different than in the found tutorial. My model needs to have more fields and here is where the problem lies.
Below are the snippets of my code:
user.model.ts
export interface UserModel {
uid: string;
email: string;
firstName: string;
lastName: string;
photoURL: string;
emailVerified: boolean;
}
auth-service.service.ts
import { Injectable, NgZone } from '@angular/core';
import { UserModel } from 'src/app/models/user.model'
import * as auth from 'firebase/auth';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import {
AngularFirestore,
AngularFirestoreDocument,
} from '@angular/fire/compat/firestore';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class AuthService {
userData: any; // Save logged in user data
constructor(
public afs: AngularFirestore, // Inject Firestore service
public afAuth: AngularFireAuth, // Inject Firebase auth service
public router: Router,
public ngZone: NgZone // NgZone service to remove outside scope warning
) {
/* Saving user data in localstorage when
logged in and setting up null when logged out */
this.afAuth.authState.subscribe((user) => {
if (user) {
this.userData = user;
localStorage.setItem('user', JSON.stringify(this.userData));
JSON.parse(localStorage.getItem('user')!);
} else {
localStorage.setItem('user', 'null');
JSON.parse(localStorage.getItem('user')!);
}
});
}
// Sign in with email/password
SignIn(email: string, password: string) {
return this.afAuth
.signInWithEmailAndPassword(email, password)
.then((result) => {
this.ngZone.run(() => {
this.router.navigate(['dashboard']);
});
this.SetUserData(result.user);
})
.catch((error) => {
window.alert(error.message);
});
}
// Sign up with email/password
SignUp(email: string, password: string) {
return this.afAuth
.createUserWithEmailAndPassword(email, password)
.then((result) => {
/* Call the SendVerificaitonMail() function when new user sign
up and returns promise */
this.SendVerificationMail();
this.SetUserData(result.user);
})
.catch((error) => {
window.alert(error.message);
});
}
// Send email verfificaiton when new user sign up
SendVerificationMail() {
return this.afAuth.currentUser
.then((u: any) => u.sendEmailVerification())
.then(() => {
this.router.navigate(['verify-email-address']);
});
}
// Reset Forggot password
ForgotPassword(passwordResetEmail: string) {
return this.afAuth
.sendPasswordResetEmail(passwordResetEmail)
.then(() => {
window.alert('Password reset email sent, check your inbox.');
})
.catch((error) => {
window.alert(error);
});
}
// Returns true when user is looged in and email is verified
get isLoggedIn(): boolean {
const user = JSON.parse(localStorage.getItem('user')!);
return user !== null && user.emailVerified !== false;
}
// Sign in with Google
GoogleAuth() {
return this.AuthLogin(new auth.GoogleAuthProvider()).then((res: any) => {
if (res) {
this.router.navigate(['dashboard']);
}
});
}
// Auth logic to run auth providers
AuthLogin(provider: any) {
return this.afAuth
.signInWithPopup(provider)
.then((result) => {
this.ngZone.run(() => {
this.router.navigate(['dashboard']);
});
this.SetUserData(result.user);
})
.catch((error) => {
window.alert(error);
});
}
/* Setting up user data when sign in with username/password,
sign up with username/password and sign in with social auth
provider in Firestore database using AngularFirestore + AngularFirestoreDocument service */
SetUserData(user: UserModel) {
const userRef: AngularFirestoreDocument<UserModel> = this.afs.doc(
`users/${user.uid}`
);
const userData: UserModel = {
uid: user.uid,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
photoURL: user.photoURL,
emailVerified: user.emailVerified,
};
return userRef.set(Object.assign({},userData) , {
merge: true,
});
}
// Sign out
SignOut() {
return this.afAuth.signOut().then(() => {
localStorage.removeItem('user');
this.router.navigate(['sign-in']);
});
}
}
I am getting such an error in SetUpUserMethod : TS2345: Argument of type 'User | null' is not assignable to parameter of type 'UserModel'. Type 'null' is not assignable to type 'UserModel'.
If I revert the service code to the original version as in the tutorial I get issues from Firebase instead: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field firstName in document users/.......
All in all, new credentials are added in the Auth section in the Firebase but not added in the Firestore. So I cannot use them to Sign-in as I am getting a similar error from Firebase: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field firstName in document users/x
sign-up.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthService} from "../../services/auth-service.service";
import {AbstractControl, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
@Component({
selector: 'app-sign-up',
templateUrl: './sign-up.component.html',
styleUrls: ['./sign-up.component.css']
})
export class SignUpComponent implements OnInit {
form: FormGroup = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
email: new FormControl(''),
password: new FormControl(''),
});
submitted = false;
constructor(public authService: AuthService, private formBuilder: FormBuilder) { }
ngOnInit() {
this.form = this.formBuilder.group({
firstName: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(20)]],
lastName: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(20)]],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(40)]],
},
);
}
get f(): { [key: string]: AbstractControl } {
return this.form.controls;
}
onSubmit(): void {
this.submitted = true;
if (this.form.invalid) {
return;
}
this.authService.SignUp(this.form.value.email, this.form.value.password);
console.log(JSON.stringify(this.form.value, null, 2));
}
onReset(): void {
this.submitted = false;
this.form.reset();
}
}
Is anyone willing to point in the right direction? Later I plan to add an additional collection(to mark the progress - the language studying app) and connect it to each user using UID. That is why I need to have the details of the User in the Firestore as well.