1+ // Copyright The Linux Foundation and each contributor to CommunityBridge.
2+ // SPDX-License-Identifier: MIT
3+
4+ import { Injectable } from '@angular/core' ;
5+ import { Router , NavigationEnd } from '@angular/router' ;
6+ import { filter } from 'rxjs/operators' ;
7+ import { environment } from '../../../environments/environment' ;
8+
9+ declare global {
10+ interface Window {
11+ LfxAnalytics ?: {
12+ LfxSegmentsAnalytics ?: any ;
13+ } ;
14+ }
15+ }
16+
17+ @Injectable ( {
18+ providedIn : 'root'
19+ } )
20+ export class LfxAnalyticsService {
21+ private analytics : any ;
22+ private isInitialized = false ;
23+ private isScriptLoaded = false ;
24+ private initializationPromise : Promise < void > | null = null ;
25+
26+ constructor ( private router : Router ) {
27+ this . initializeService ( ) ;
28+ }
29+
30+ async trackPageView ( pageName : string , properties ?: Record < string , any > ) : Promise < void > {
31+ if ( ! this . isInitialized || ! this . analytics ) {
32+ await this . initializeService ( ) ;
33+ }
34+
35+ if ( this . isInitialized && this . analytics ) {
36+ try {
37+ const pageProperties = {
38+ path : pageName ,
39+ url : window . location . href ,
40+ title : document . title ,
41+ referrer : document . referrer ,
42+ ...properties
43+ } ;
44+
45+ await this . analytics . page ( pageName , pageProperties ) ;
46+ } catch ( error ) {
47+ console . error ( 'Failed to track page view:' , error ) ;
48+ }
49+ }
50+ }
51+
52+ async trackEvent ( eventName : string , properties ?: Record < string , any > ) : Promise < void > {
53+ if ( ! this . isInitialized || ! this . analytics ) {
54+ await this . initializeService ( ) ;
55+ }
56+
57+ if ( this . isInitialized && this . analytics ) {
58+ try {
59+ const eventProperties = {
60+ url : window . location . href ,
61+ path : window . location . pathname ,
62+ ...properties
63+ } ;
64+
65+ await this . analytics . track ( eventName , eventProperties ) ;
66+ } catch ( error ) {
67+ console . error ( 'Failed to track event:' , error ) ;
68+ }
69+ }
70+ }
71+
72+ async identifyAuth0User ( auth0User : any ) : Promise < void > {
73+ if ( ! this . isInitialized || ! this . analytics ) {
74+ await this . initializeService ( ) ;
75+ }
76+
77+ if ( this . isInitialized && this . analytics && auth0User ) {
78+ try {
79+ await this . analytics . identifyAuth0User ( auth0User ) ;
80+ } catch ( error ) {
81+ console . error ( 'Failed to identify Auth0 user:' , error ) ;
82+ }
83+ }
84+ }
85+
86+ async reset ( ) : Promise < void > {
87+ if ( this . isInitialized && this . analytics ) {
88+ try {
89+ await this . analytics . reset ( ) ;
90+ } catch ( error ) {
91+ console . error ( 'Failed to reset analytics:' , error ) ;
92+ }
93+ }
94+ }
95+
96+ isAnalyticsInitialized ( ) : boolean {
97+ return this . isInitialized ;
98+ }
99+
100+ private async initializeService ( ) : Promise < void > {
101+ if ( this . initializationPromise ) {
102+ return this . initializationPromise ;
103+ }
104+
105+ this . initializationPromise = this . performInitialization ( ) ;
106+ return this . initializationPromise ;
107+ }
108+
109+ private async performInitialization ( ) : Promise < void > {
110+ try {
111+ if ( ! this . isScriptLoaded ) {
112+ await this . loadAnalyticsScript ( ) ;
113+ this . isScriptLoaded = true ;
114+ }
115+
116+ await this . waitForAnalytics ( ) ;
117+
118+ this . analytics = window . LfxAnalytics . LfxSegmentsAnalytics . getInstance ( ) ;
119+ await this . analytics . init ( ) ;
120+ this . isInitialized = true ;
121+
122+ this . setupRouteTracking ( ) ;
123+
124+ } catch ( error ) {
125+ console . error ( 'Failed to initialize LFX Segments Analytics:' , error ) ;
126+ }
127+ }
128+
129+ private loadAnalyticsScript ( ) : Promise < void > {
130+ return new Promise ( ( resolve , reject ) => {
131+ if ( window . LfxAnalytics ?. LfxSegmentsAnalytics ) {
132+ resolve ( ) ;
133+ return ;
134+ }
135+
136+ const script = document . createElement ( 'script' ) ;
137+ script . src = environment . lfxSegmentAnalyticsUrl ;
138+ script . async = true ;
139+ script . defer = true ;
140+
141+ script . onload = ( ) => {
142+ resolve ( ) ;
143+ } ;
144+
145+ script . onerror = ( error ) => {
146+ console . error ( 'Failed to load LFX Segments Analytics script:' , error ) ;
147+ reject ( new Error ( 'Failed to load analytics script' ) ) ;
148+ } ;
149+
150+ document . head . appendChild ( script ) ;
151+ } ) ;
152+ }
153+
154+ private async waitForAnalytics ( ) : Promise < void > {
155+ const maxAttempts = 50 ; // 5 seconds max wait time
156+ let attempts = 0 ;
157+
158+ while ( ! window . LfxAnalytics ?. LfxSegmentsAnalytics && attempts < maxAttempts ) {
159+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
160+ attempts ++ ;
161+ }
162+
163+ if ( ! window . LfxAnalytics ?. LfxSegmentsAnalytics ) {
164+ throw new Error ( 'LFX Segments Analytics library not available after timeout' ) ;
165+ }
166+ }
167+
168+ private setupRouteTracking ( ) : void {
169+ this . router . events
170+ . pipe (
171+ filter ( event => event instanceof NavigationEnd )
172+ )
173+ . subscribe ( ( event : NavigationEnd ) => {
174+ this . trackPageView ( event . urlAfterRedirects || event . url ) ;
175+ } ) ;
176+
177+ this . trackPageView ( this . router . url ) ;
178+ }
179+ }
0 commit comments