Expanding the capabilities of an Angular Firestore application by linking specific data to individual users

I developed an application using Angular 7 with Firestore for crud operations. Everything is functioning well with a single user. However, I am now looking to expand it and link data to each individual logged-in user. Unfortunately, I am struggling to find detailed resources online.

Currently, I have users stored in a collection. My goal is to set up a 'vacations' collection nested under each user, specifically for their vacation details. I believe the initial step involves retrieving the unique id of the currently logged-in user and then updating the necessary functions to modify the collection by using `.doc('current user id')`.

Below is the code snippet I utilized to fetch the current user's uid:

this.userID = this.firestore.collection('users').doc(this.auth().user.uid);

Errors encountered during pre-compilation:

1- Type 'AngularFirestoreDocument<{}>' is not assignable to type 'string'

2- Cannot invoke an expression whose type lacks a call signature. Type 'AuthService' has no compatible call signatures.

This is how the data organization looks currently:

https://i.sstatic.net/e1V51.png

The authentication service code snippet is provided below:

export class AuthService {
    
    user$: Observable<User>;
    
    constructor(
        public afAuth: AngularFireAuth,
        public afs: AngularFirestore,
        public router: Router
    ) { 
        // Fetch the auth state and retrieve the Firestore user document or return null
        this.user$ = this.afAuth.authState.pipe(
            switchMap(user => {
                // User is logged in
                if (user) {
                    return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
                } else {
                    // User is logged out
                    return of(null);
                }
            })
        )
    }
    
    googleLogin() {
        const provider = new auth.GoogleAuthProvider()
        return this.oAuthLogin(provider);
    }
    
    public oAuthLogin(provider) {
        return this.afAuth.auth.signInWithPopup(provider)
            .then((credential) => {
                this.updateUserData(credential.user)
            })
    }
    
    public updateUserData(user) {
        // Store user data in firestore upon login
        const userRef: AngularFirestoreDocument<User> = this.afs.doc(`users/${user.uid}`);
        
        const data = { 
            uid: user.uid, 
            email: user.email, 
            displayName: user.displayName, 
            photoURL: user.photoURL
        } 
        return userRef.set(data, { merge: true })
    }
}

Your assistance is greatly appreciated.

Answer №1

For the official answer from Google, please refer to this link - Get the currently signed-in user - Firebase

Presented below is a function that provides a promise of type string. This promise resolves with the user's uid acquired from onAuthStateChangedwhich(), alongside other details of the user's firebase auth object (displayName and more).

getCurrentUser(): Promise<string> {
  var promise = new Promise<string>((resolve, reject) => {
    this.afAuth.auth.onAuthStateChanged(returnedUser => {
      if (returnedUser) {
        resolve(returnedUser.uid);
      } else {
        reject(null);
      }
    });
  })
  return promise
}

To invoke it, simply use it in the constructor or ngOninit:

userDoc: User = null;

constructor() {
  this.getCurrentUser().then((userID: string) => {
    // Utilize the id to access the user's firestore doc 
    this.afs.collection('users').doc(userID).valueChanges()
    .subscribe(userFirestoreDoc => { // don't forget to subscribe
      this.userDoc = userFirestoreDoc;
    })
  }).catch(nullID => {
    // In case there is no current user
    this.userDoc = null
  }) 
}

If you want to include a collection for 'vacations' within the user's document, you need to add a subcollection to that specific firestore doc. It is advisable to do so once the user initiates or adds their first vacation. The code snippet provided below allows you to effortlessly set up the new collection and add a new vacation inside it.

this.afs.collection('users').doc(this.userDoc.uid).collection('vacations').add(vacationObject).then(returnedVacation => {

}).catch(error => {

})

Answer №2

active_users ==> last login timestamp

The 'last login' property in the google authentication user profile is automatically refreshed each time a successful login occurs, capturing the timestamp of the most recent login event.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating HTML tables from JSON arrays dynamically in Angular using headers auto-detection

Is there a way in Angular to convert a JSON array into an HTML table? I came across an old answer for AngularJS, but I'm looking for a solution that works in Angular: <table> <thead> <tr> <th ng-repeat="(ke ...

Dilemma between Observable and Promise-driven Methodology

Currently, I am in the process of transitioning some promised-based implementations to use observables in my Ionic/Angular app. I have encountered a particular issue with one function. The original code, which worked successfully and was promised-based, ha ...

Encountering a problem with npm install due to git not being found

I recently updated my package JSON file with new dependencies and attempted to install npm, but encountered errors indicating that git could not be found: npm ERR! path git npm ERR! code ENOENT npm ERR! errno ENOENT npm ERR! syscall spawn git npm ...

Exploring Angular Route Configurations: Utilizing Multiple Outlets with Path as an Array of

In my Angular9 application, I have configured hundreds of routes paths. Is there a way to use multiple outlets with a single array of string paths? Current Code: const routes: Routes = [ { path: 'Data/:EntityID/:Date', compon ...

Designing personalized plugins with Typescript in Nuxt

In my Nuxt project, I have implemented a custom plugin file that contains an object with settings called /helpers/settings: export const settings = { baseURL: 'https://my-site.com', ... }; This file is then imported and registered in /plugi ...

Unable to locate the main source for loading

I am facing an issue with my app where I am unable to load a basic component. It seems like a simple problem, but I just can't seem to figure it out. Here is the code for my component: import { Component, OnInit } from '@angular/core'; imp ...

Challenge with validating reactive forms

*ngIf not behaving as expected Although my form's primary condition is working flawlessly, I am facing issues with displaying a specific error message. For example, the code *ngIf="PopupForm.get('startdate').errors?.required is not fun ...

Creating a custom draggable modal with Angular Bootstrap

Currently, I am working on an Angular application and using ng-bootstrap to showcase modal windows. Unfortunately, the ngb team does not currently support making these modals draggable, with no immediate plans to implement this feature in the near future a ...

Removing fields when extending an interface in TypeScript

Attempting to extend the ISampleB interface and exclude certain values, like in the code snippet below. Not sure if there is an error in this implementation export interface ISampleA extends Omit<ISampleB, 'fieldA' | 'fieldB' | &apos ...

Is there a way for me to subscribe specifically to JSON data with the "category" value set to 2?

If I want to subscribe to these specific JSON objects: [ { "id": 667, "image": "https://ae0g", "description": "GRE", "price&q ...

What is the best way to navigate between multiple pages in an Angular 7 application using ngIf?

In my Angular 7 app, I am facing an issue with switching between three different pages. While I have managed to switch between two of them successfully, the messages page loads in the documents section whenever I click on it. Even though I have attempted ...

Issues with responsiveness and calculated attributes in Vue 3 using the Composition API

Within this menu, there are different items: Item 1 (marked as number 1 in orange) with the path: http://localhost:8080/#/documents Item 2 (marked as number 2 in orange) with the path: http://localhost:8080/#/documents/1 Item 3 (marked as number 3 in or ...

Scoped variable in Typescript producing a generated Javascript file

I'm currently learning TypeScript through an online course, and I've encountered a problem that seems to be related to a VSCode setting. Whenever I compile app.ts, it generates the app.js file, but I immediately encounter a TypeScript error. It& ...

Including a CSS link in a .css file is an essential step in styling

Can someone guide me on how to reference the Bootstrap link (https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css) in a .css file within an Angular project? ...

Understanding the infer keyword in Typescript when working with generic type constraints

Exploring a scenario where I have a generic interface that requires a type argument extending another generic type. export interface IPoint<TX, TY> { x: TX; y: TY; } export interface ISeries<TPoint extends IPoint> { points: Array& ...

Loop through an entity to identify the corresponding active days for each id

Review the following array of objects: const resource = [ { id: 'tony', shiftday: [ {active: '1', code: 'Sun'}, {active: '1', code: 'Mon'}, {active: & ...

Encountering a 401 error when trying to access OneNote resource in Angular 5 with Microsoft Graph

I have encountered an issue while trying to request resources from Microsoft graph (for OneNote API). My concern revolves around the correct method of obtaining an access token. I am utilizing the implicit flow for my Angular 5 frontend application. The p ...

What is the best way to showcase nested array information within a form array in Angular2?

I recently incorporated FormGroup into my Angular 2 project to facilitate form rendering. For handling nested array data, I opted for formArray. form.component.html <div class="col-md-12" formArrayName="social_profiles"> <div *ngFor="let socia ...

What are the benefits of reverting back to an Angular 1 directive instead of using an Angular 2 application

Our team has created numerous Angular 1 components and is eager to incorporate them into our Angular 2 application. However, the documentation suggests that we must downgrade the Angular 2 application in order to integrate and utilize the Angular 1 direc ...

Expanding functionality: Incorporating new pages into app.module.ts in Ionic with CLI

I recently started using Ionic and found that when generating pages in Ionic, we need to manually add the pages to the app.module.ts file. Is there a more efficient way to add pages to the app.module.ts file using CLI in Ionic? This is what I have attemp ...