Angular Ngrx redirect inside effect is causing weird error

58 views Asked by At

I am getting a really weird error after trying to redirect on loginSuccess. Basically, here is the flow I have :

  1. The user fills a login form, then dispatch a 'Login' action.
  2. Login effect call AuthService, which is responsible to log with Firebase
  3. If Firebase login is successful, a new action is dispatch: loginSuccess
  4. LoginSuccess effect should then call my backend ('query me'), in order to get profile infos for the user
  5. After the call, the effect dispatch UserLoaded action (for the reducer to update the state), then redirect to home page

I am using Apollo GraphQL to communicate with my backend ; everything is working fine if I don't use the router.navigate. But when I use it, I get this error which doesn't really make any sense to me :

ERROR Error: Uncaught (in promise): TypeError: Cannot add property 0, object is not extensible
TypeError: Cannot add property 0, object is not extensible

Here is the responsible code :

loginSuccess$ = createEffect(() =>
    this.actions$.pipe(
      ofType(AuthLoginActions.loginSuccess),
      switchMap(({ credentials }) =>
        this.authService.me().pipe(
          map((user: MeQuery['me']) => AuthActions.userLoaded({ user })),
          catchError((error) => {
            return of(AuthActions.error({ error }));
          })
        )
      ),
      tap(() => this.router.navigate(['/']))
    )
  );

Here is the AuthService me() :

me(): Observable<MeQuery['me']> {
    return this.meGql.watch().valueChanges.pipe(
      map((result) => {
        console.log('result:');
        console.log(result);

        return result.data.me;
      })
    );
  }

What I found is that these error could happen when you try to modify immutable objects, but here this is not the case. Really when I delete the router navigation inside the tap, no more error. I'm wondering if this could be a timing issue between the time AuthActions.userLoaded is dispatch and the router navigation.

I also tryed to navigate with an effet on userLoaded action, but had no more success.

EDIT : if I remove the guard on user routes, it works. So here's more code from routes and the guard in question (using angular/fire) :

app.routes.ts

export const appRoutes: Route[] = [
  {
    path: 'auth',
    loadChildren: () =>
      import('@booking/booking-frontend-auth-feature-shell').then(
        (m) => m.bookingFrontendAuthFeatureShellRoutes
      ),
  },

  {
    path: '',
    loadChildren: userSpaceRoutes,
    ...canActivate(userSpaceGuard),
  },
];

app.guards.ts

export const userSpaceGuard = () =>
  pipe(
    switchMap(async (user: User | null) => {
      console.log('switchMap');

      if (!user) {
        console.log('no user');
        return null;
      }

      console.log('return transformed user');
      // Transform user to get idTokenResult
      return {
        user: user,
        idTokenResult: await user.getIdTokenResult(),
      };
    }),
    map((userInfos: any) => {
      console.log('userInfos: ');
      console.log(userInfos);
      // No user, redirect to login
      if (!userInfos?.user) {
        console.log('no user');
        return [`auth/login`];
      }

      // If user is admin, redirect to admin space
      const claims = userInfos.idTokenResult.claims;
      console.log('claims:');
      console.log(claims);
      if (claims && claims.role === UserRole.Admin) {
        console.log('return admin');
        return ['admin'];
      }

      console.log('return true');
      return true;
    })
  );

Any idea ?

Thanks

1

There are 1 answers

0
Jérémy Dutheil On

I finally found the answer by myself, investing a bit more : it was Firebase Auth that was causing the issue. In fact, on loginSuccess I was storing UserCredentials (from Firebase) in my store. Looks like Firebase is trying then to update those credentials at some time, resulting in this immutability error.

I realized that I didn't need those credentials in my store, so I just removed them and now everything is working fine.