Skip to content

Commit f8830d1

Browse files
committed
fix(auth): patched various Zone.js issues
1 parent a5c1d5e commit f8830d1

File tree

3 files changed

+35
-30
lines changed

3 files changed

+35
-30
lines changed

sample/src/app/auth/auth.component.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { isPlatformServer } from '@angular/common';
1313
<p>
1414
Auth!
1515
{{ (auth.user | async)?.uid | json }}
16-
{{ (auth.credential | async)?.operationType | json }}
16+
{{ (auth.credential | async)?.additionalUserInfo.isNewUser | json }}
1717
<button (click)="login()" *ngIf="showLoginButton">Log in with Google</button>
1818
<button (click)="loginAnonymously()" *ngIf="showLoginButton">Log in anonymously</button>
1919
<button (click)="logout()" *ngIf="showLogoutButton">Log out</button>

src/analytics/user-tracking.service.ts

+21-22
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Inject, Injectable, OnDestroy, PLATFORM_ID } from '@angular/core';
33
import { AngularFireAnalytics } from './analytics';
44
import { AngularFireAuth } from '@angular/fire/auth';
55
import { Subscription } from 'rxjs';
6-
import { credential } from 'firebase-admin';
76

87
@Injectable()
98
export class UserTrackingService implements OnDestroy {
@@ -19,27 +18,27 @@ export class UserTrackingService implements OnDestroy {
1918
auth: AngularFireAuth,
2019
) {
2120

22-
this.initialized = new Promise(resolve => {
23-
if (!isPlatformServer(platformId)) {
24-
this.disposables = [
25-
auth.authState.subscribe(user => {
26-
analytics.setUserId(user?.uid);
27-
resolve();
28-
}),
29-
auth.credential.subscribe(credential => {
30-
if (credential) {
31-
const method = credential.user.isAnonymous ? 'anonymous' : credential.additionalUserInfo.providerId;
32-
if (credential.additionalUserInfo.isNewUser) {
33-
analytics.logEvent('sign_up', { method });
34-
}
35-
analytics.logEvent('login', { method });
36-
}
37-
})
38-
];
39-
} else {
40-
resolve();
41-
}
42-
});
21+
if (!isPlatformServer(platformId)) {
22+
let resolveInitialized;
23+
this.initialized = new Promise(resolve => resolveInitialized = resolve);
24+
this.disposables = [
25+
auth.authState.subscribe(user => {
26+
analytics.setUserId(user?.uid);
27+
resolveInitialized();
28+
}),
29+
auth.credential.subscribe(credential => {
30+
if (credential) {
31+
const method = credential.user.isAnonymous ? 'anonymous' : credential.additionalUserInfo.providerId;
32+
if (credential.additionalUserInfo.isNewUser) {
33+
analytics.logEvent('sign_up', { method });
34+
}
35+
analytics.logEvent('login', { method });
36+
}
37+
})
38+
];
39+
} else {
40+
this.initialized = Promise.resolve();
41+
}
4342

4443
}
4544

src/auth/auth.ts

+13-7
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export class AngularFireAuth {
7676
) {
7777
const schedulers = new ɵAngularFireSchedulers(zone);
7878
const keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(schedulers);
79-
const logins = new Subject<firebase.auth.UserCredential>();
79+
const logins = new Subject<Required<firebase.auth.UserCredential>>();
8080

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

134136
this.user = auth.pipe(
135137
// see comment on authState
136138
switchMap(auth => auth.getRedirectResult().then(() => auth, () => auth)),
137139
switchMap(auth => zone.runOutsideAngular(() => new Observable<firebase.User|null>(auth.onIdTokenChanged.bind(auth)))),
138-
keepUnstableUntilFirst
140+
keepUnstableUntilFirst,
141+
shareReplay(1) // see authState
139142
);
140143

141144
this.idToken = this.user.pipe(
@@ -152,10 +155,12 @@ export class AngularFireAuth {
152155
logins,
153156
// pipe in null authState to make credential zipable, just a weird devexp if
154157
// authState and user go null to still have a credential
155-
this.authState.pipe(filter(it => !it)))
156-
),
158+
this.authState.pipe(filter(it => !it))
159+
)),
157160
// handle the { user: { } } when a user is already logged in, rather have null
158161
map(credential => credential?.user ? credential : null),
162+
keepUnstableUntilFirst,
163+
shareReplay(1)
159164
);
160165

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

0 commit comments

Comments
 (0)