Skip to content

Commit

Permalink
fix(auth): patched various Zone.js issues
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesdaniels committed Nov 18, 2020
1 parent a5c1d5e commit f8830d1
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 30 deletions.
2 changes: 1 addition & 1 deletion sample/src/app/auth/auth.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { isPlatformServer } from '@angular/common';
<p>
Auth!
{{ (auth.user | async)?.uid | json }}
{{ (auth.credential | async)?.operationType | json }}
{{ (auth.credential | async)?.additionalUserInfo.isNewUser | json }}
<button (click)="login()" *ngIf="showLoginButton">Log in with Google</button>
<button (click)="loginAnonymously()" *ngIf="showLoginButton">Log in anonymously</button>
<button (click)="logout()" *ngIf="showLogoutButton">Log out</button>
Expand Down
43 changes: 21 additions & 22 deletions src/analytics/user-tracking.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Inject, Injectable, OnDestroy, PLATFORM_ID } from '@angular/core';
import { AngularFireAnalytics } from './analytics';
import { AngularFireAuth } from '@angular/fire/auth';
import { Subscription } from 'rxjs';
import { credential } from 'firebase-admin';

@Injectable()
export class UserTrackingService implements OnDestroy {
Expand All @@ -19,27 +18,27 @@ export class UserTrackingService implements OnDestroy {
auth: AngularFireAuth,
) {

this.initialized = new Promise(resolve => {
if (!isPlatformServer(platformId)) {
this.disposables = [
auth.authState.subscribe(user => {
analytics.setUserId(user?.uid);
resolve();
}),
auth.credential.subscribe(credential => {
if (credential) {
const method = credential.user.isAnonymous ? 'anonymous' : credential.additionalUserInfo.providerId;
if (credential.additionalUserInfo.isNewUser) {
analytics.logEvent('sign_up', { method });
}
analytics.logEvent('login', { method });
}
})
];
} else {
resolve();
}
});
if (!isPlatformServer(platformId)) {
let resolveInitialized;
this.initialized = new Promise(resolve => resolveInitialized = resolve);
this.disposables = [
auth.authState.subscribe(user => {
analytics.setUserId(user?.uid);
resolveInitialized();
}),
auth.credential.subscribe(credential => {
if (credential) {
const method = credential.user.isAnonymous ? 'anonymous' : credential.additionalUserInfo.providerId;
if (credential.additionalUserInfo.isNewUser) {
analytics.logEvent('sign_up', { method });
}
analytics.logEvent('login', { method });
}
})
];
} else {
this.initialized = Promise.resolve();
}

}

Expand Down
20 changes: 13 additions & 7 deletions src/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class AngularFireAuth {
) {
const schedulers = new ɵAngularFireSchedulers(zone);
const keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(schedulers);
const logins = new Subject<firebase.auth.UserCredential>();
const logins = new Subject<Required<firebase.auth.UserCredential>>();

const auth = of(undefined).pipe(
observeOn(schedulers.outsideAngular),
Expand All @@ -86,7 +86,7 @@ export class AngularFireAuth {
const useEmulator: UseEmulatorArguments | null = _useEmulator;
const settings: firebase.auth.AuthSettings | null = _settings;
return ɵfetchInstance(`${app.name}.auth`, 'AngularFireAuth', app, () => {
const auth = app.auth();
const auth = zone.runOutsideAngular(() => app.auth());
if (useEmulator) {
// Firebase Auth doesn't conform to the useEmulator convention, let's smooth that over
auth.useEmulator(`http://${useEmulator.join(':')}`);
Expand Down Expand Up @@ -128,14 +128,17 @@ export class AngularFireAuth {
// a user is signed in
switchMap(auth => auth.getRedirectResult().then(() => auth, () => auth)),
switchMap(auth => zone.runOutsideAngular(() => new Observable<firebase.User|null>(auth.onAuthStateChanged.bind(auth)))),
keepUnstableUntilFirst
keepUnstableUntilFirst,
// TODO figure out why I needed share, perhaps it's the observable construction?
shareReplay(1)
);

this.user = auth.pipe(
// see comment on authState
switchMap(auth => auth.getRedirectResult().then(() => auth, () => auth)),
switchMap(auth => zone.runOutsideAngular(() => new Observable<firebase.User|null>(auth.onIdTokenChanged.bind(auth)))),
keepUnstableUntilFirst
keepUnstableUntilFirst,
shareReplay(1) // see authState
);

this.idToken = this.user.pipe(
Expand All @@ -152,10 +155,12 @@ export class AngularFireAuth {
logins,
// pipe in null authState to make credential zipable, just a weird devexp if
// authState and user go null to still have a credential
this.authState.pipe(filter(it => !it)))
),
this.authState.pipe(filter(it => !it))
)),
// handle the { user: { } } when a user is already logged in, rather have null
map(credential => credential?.user ? credential : null),
keepUnstableUntilFirst,
shareReplay(1)
);

}
Expand All @@ -166,7 +171,8 @@ export class AngularFireAuth {
// this will give us the user credential, push onto the logins Subject
// to be consumed in .credential
if (name.startsWith('signIn') || name.startsWith('createUser')) {
val.then((user: firebase.auth.UserCredential) => logins.next(user));
// TODO fix the types, the trouble is UserCredential has everything optional
val.then((user: firebase.auth.UserCredential) => logins.next(user as any));
}
}
}});
Expand Down

0 comments on commit f8830d1

Please sign in to comment.