1
1
import { Injectable , Inject , Optional , NgZone , InjectionToken } from '@angular/core' ;
2
- import { Observable , from } from 'rxjs' ;
3
- import { map , tap , filter , withLatestFrom , shareReplay } from 'rxjs/operators' ;
4
- import { Router , NavigationEnd , ActivationEnd } from '@angular/router' ;
2
+ import { of } from 'rxjs' ;
3
+ import { map , tap , shareReplay , switchMap } from 'rxjs/operators' ;
5
4
import { FirebaseAppConfig , FirebaseOptions , runOutsideAngular , _lazySDKProxy , FirebaseAnalytics , FIREBASE_OPTIONS , FIREBASE_APP_NAME , _firebaseAppFactory } from '@angular/fire' ;
6
5
import { analytics , app } from 'firebase' ;
7
6
8
- export const AUTOMATICALLY_SET_CURRENT_SCREEN = new InjectionToken < boolean > ( 'angularfire2.analytics.setCurrentScreen' ) ;
9
- export const AUTOMATICALLY_LOG_SCREEN_VIEWS = new InjectionToken < boolean > ( 'angularfire2.analytics.logScreenViews' ) ;
10
7
export const ANALYTICS_COLLECTION_ENABLED = new InjectionToken < boolean > ( 'angularfire2.analytics.analyticsCollectionEnabled' ) ;
11
- export const AUTOMATICALLY_TRACK_USER_IDENTIFIER = new InjectionToken < boolean > ( 'angularfire2.analytics.trackUserIdentifier' ) ;
12
- export const APP_VERSION = new InjectionToken < string > ( 'angularfire2.analytics.appVersion' ) ;
13
- export const APP_NAME = new InjectionToken < string > ( 'angularfire2.analytics.appName' ) ;
14
-
15
- export const DEFAULT_APP_VERSION = '?' ;
16
- export const DEFAULT_APP_NAME = 'Angular App' ;
17
8
18
9
// SEMVER: once we move to Typescript 3.6 use `PromiseProxy<analytics.Analytics>`
19
10
type AnalyticsProxy = {
@@ -29,74 +20,30 @@ type AnalyticsProxy = {
29
20
30
21
export interface AngularFireAnalytics extends AnalyticsProxy { } ;
31
22
32
- @Injectable ( )
23
+ @Injectable ( {
24
+ providedIn : "root"
25
+ } )
33
26
export class AngularFireAnalytics {
34
27
35
- /**
36
- * Firebase Analytics instance
37
- */
38
- private readonly analytics$ : Observable < FirebaseAnalytics > ;
39
- private get analytics ( ) { return this . analytics$ . toPromise ( ) ; }
40
-
41
28
constructor (
42
29
@Inject ( FIREBASE_OPTIONS ) options :FirebaseOptions ,
43
30
@Optional ( ) @Inject ( FIREBASE_APP_NAME ) nameOrConfig :string | FirebaseAppConfig | null | undefined ,
44
- @Optional ( ) router :Router ,
45
- @Optional ( ) @Inject ( AUTOMATICALLY_SET_CURRENT_SCREEN ) automaticallySetCurrentScreen :boolean | null ,
46
- @Optional ( ) @Inject ( AUTOMATICALLY_LOG_SCREEN_VIEWS ) automaticallyLogScreenViews :boolean | null ,
47
31
@Optional ( ) @Inject ( ANALYTICS_COLLECTION_ENABLED ) analyticsCollectionEnabled :boolean | null ,
48
- @Optional ( ) @Inject ( AUTOMATICALLY_TRACK_USER_IDENTIFIER ) automaticallyTrackUserIdentifier :boolean | null ,
49
- @Optional ( ) @Inject ( APP_VERSION ) providedAppVersion :string | null ,
50
- @Optional ( ) @Inject ( APP_NAME ) providedAppName :string | null ,
51
32
zone : NgZone
52
33
) {
53
- // @ts -ignore zapping in the UMD in the build script
54
- const requireAnalytics = from ( import ( 'firebase/analytics' ) ) ;
55
- const app = _firebaseAppFactory ( options , zone , nameOrConfig ) ;
56
-
57
- this . analytics$ = requireAnalytics . pipe (
58
- map ( ( ) => app . analytics ( ) ) ,
34
+ const analytics = of ( undefined ) . pipe (
35
+ // @ts -ignore zapping in the UMD in the build script
36
+ switchMap ( ( ) => zone . runOutsideAngular ( ( ) => import ( 'firebase/analytics' ) ) ) ,
37
+ map ( ( ) => _firebaseAppFactory ( options , zone , nameOrConfig ) ) ,
38
+ map ( app => app . analytics ( ) ) ,
59
39
tap ( analytics => {
60
40
if ( analyticsCollectionEnabled === false ) { analytics . setAnalyticsCollectionEnabled ( false ) }
61
41
} ) ,
62
42
runOutsideAngular ( zone ) ,
63
43
shareReplay ( 1 )
64
44
) ;
65
45
66
- if ( router && ( automaticallySetCurrentScreen !== false || automaticallyLogScreenViews !== false ) ) {
67
- const app_name = providedAppName || DEFAULT_APP_NAME ;
68
- const app_version = providedAppVersion || DEFAULT_APP_VERSION ;
69
- const activationEndEvents = router . events . pipe ( filter < ActivationEnd > ( e => e instanceof ActivationEnd ) ) ;
70
- const navigationEndEvents = router . events . pipe ( filter < NavigationEnd > ( e => e instanceof NavigationEnd ) ) ;
71
- navigationEndEvents . pipe (
72
- withLatestFrom ( activationEndEvents , this . analytics$ ) ,
73
- tap ( ( [ navigationEnd , activationEnd , analytics ] ) => {
74
- const url = navigationEnd . url ;
75
- const screen_name = activationEnd . snapshot . routeConfig && activationEnd . snapshot . routeConfig . path || undefined ;
76
- const outlet = activationEnd . snapshot . outlet ;
77
- if ( automaticallyLogScreenViews !== false ) {
78
- analytics . logEvent ( "screen_view" , { app_name, app_version, screen_name, outlet, url } ) ;
79
- }
80
- if ( automaticallySetCurrentScreen !== false ) {
81
- // TODO when is screen_name undefined?
82
- analytics . setCurrentScreen ( screen_name || url , { global : outlet == "primary" } ) ;
83
- }
84
- } ) ,
85
- runOutsideAngular ( zone )
86
- ) . subscribe ( ) ;
87
- }
88
-
89
- // TODO do something other than just check auth presence, what if it's lazy loaded?
90
- if ( app . auth && automaticallyTrackUserIdentifier !== false ) {
91
- new Observable < firebase . User | null > ( app . auth ( ) . onAuthStateChanged . bind ( app . auth ( ) ) ) . pipe (
92
- withLatestFrom ( this . analytics$ ) ,
93
- tap ( ( [ user , analytics ] ) => analytics . setUserId ( user ? user . uid : null ! , { global : true } ) ) ,
94
- runOutsideAngular ( zone )
95
- ) . subscribe ( )
96
- }
97
-
98
- return _lazySDKProxy ( this , this . analytics , zone ) ;
99
-
46
+ return _lazySDKProxy ( this , analytics , zone ) ;
100
47
}
101
48
102
- }
49
+ }
0 commit comments