Skip to content

Commit 8c2dc24

Browse files
author
Andrea Barbasso
committed
[DURACOM-367] fix matomo SSR error on bitstream download page
(cherry picked from commit 37cef0f) # Conflicts: # src/app/shared/cookies/klaro.service.ts # src/app/statistics/matomo.service.spec.ts # src/app/statistics/matomo.service.ts
1 parent 1187ec9 commit 8c2dc24

4 files changed

Lines changed: 74 additions & 22 deletions

File tree

src/app/footer/footer.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export class FooterComponent implements OnInit {
6161
}
6262

6363
showCookieSettings() {
64-
if (hasValue(this.cookies)) {
64+
if (hasValue(this.cookies) && this.cookies.showSettings instanceof Function) {
6565
this.cookies.showSettings();
6666
}
6767
return false;

src/app/shared/cookies/klaro.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Observable } from 'rxjs';
44
/**
55
* Abstract class representing a service for handling Klaro consent preferences and UI
66
*/
7-
@Injectable()
7+
@Injectable({ providedIn: 'root' })
88
export abstract class KlaroService {
99
/**
1010
* Initializes the service

src/app/statistics/matomo.service.spec.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import {
2+
Injector,
3+
runInInjectionContext,
4+
} from '@angular/core';
15
import {
26
fakeAsync,
37
TestBed,
@@ -53,6 +57,7 @@ describe('MatomoService', () => {
5357
{ provide: KlaroService, useValue: klaroService },
5458
{ provide: NativeWindowService, useValue: nativeWindowService },
5559
{ provide: ConfigurationDataService, useValue: configService },
60+
{ provide: Injector, useValue: TestBed },
5661
],
5762
});
5863

@@ -70,11 +75,13 @@ describe('MatomoService', () => {
7075
});
7176

7277
it('should call setConsentGiven when consent is true', () => {
78+
service.matomoTracker = matomoTracker;
7379
service.changeMatomoConsent(true);
7480
expect(matomoTracker.setConsentGiven).toHaveBeenCalled();
7581
});
7682

7783
it('should call forgetConsentGiven when consent is false', () => {
84+
service.matomoTracker = matomoTracker;
7885
service.changeMatomoConsent(false);
7986
expect(matomoTracker.forgetConsentGiven).toHaveBeenCalled();
8087
});
@@ -91,7 +98,10 @@ describe('MatomoService', () => {
9198
configService.findByPropertyName.withArgs(MATOMO_SITE_ID).and.returnValue(
9299
createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), { values: ['1'] })));
93100
klaroService.getSavedPreferences.and.returnValue(of({ matomo: true }));
94-
service.init();
101+
102+
runInInjectionContext(TestBed, () => {
103+
service.init();
104+
});
95105

96106
expect(matomoTracker.setConsentGiven).toHaveBeenCalled();
97107
expect(matomoInitializer.initializeTracker).toHaveBeenCalledWith({
@@ -100,7 +110,7 @@ describe('MatomoService', () => {
100110
});
101111
});
102112

103-
it('should initialize tracker with REST configuration correct parameters in production', () => {
113+
it('should initialize tracker with REST configuration correct parameters in production', fakeAsync(() => {
104114
environment.production = true;
105115
environment.matomo = { trackerUrl: '' };
106116
configService.findByPropertyName.withArgs(MATOMO_TRACKER_URL).and.returnValue(
@@ -113,19 +123,25 @@ describe('MatomoService', () => {
113123
createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), { values: ['1'] })));
114124
klaroService.getSavedPreferences.and.returnValue(of({ matomo: true }));
115125

116-
service.init();
126+
runInInjectionContext(TestBed, () => {
127+
service.init();
128+
});
129+
130+
tick();
117131

118132
expect(matomoTracker.setConsentGiven).toHaveBeenCalled();
119133
expect(matomoInitializer.initializeTracker).toHaveBeenCalledWith({
120134
siteId: '1',
121135
trackerUrl: 'http://matomo',
122136
});
123-
});
137+
}));
124138

125139
it('should not initialize tracker if not in production', () => {
126140
environment.production = false;
127141

128-
service.init();
142+
runInInjectionContext(TestBed, () => {
143+
service.init();
144+
});
129145

130146
expect(matomoInitializer.initializeTracker).not.toHaveBeenCalled();
131147
});
@@ -141,16 +157,19 @@ describe('MatomoService', () => {
141157
);
142158
configService.findByPropertyName.withArgs(MATOMO_SITE_ID).and.returnValue(
143159
createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), { values: ['1'] })));
144-
orejimeService.getSavedPreferences.and.returnValue(of({ matomo: true }));
160+
klaroService.getSavedPreferences.and.returnValue(of({ matomo: true }));
145161

146-
service.init();
162+
runInInjectionContext(TestBed, () => {
163+
service.init();
164+
});
147165

148166
expect(matomoInitializer.initializeTracker).not.toHaveBeenCalled();
149167
});
150168

151169
describe('with visitorId set', () => {
152170
beforeEach(() => {
153171
matomoTracker.getVisitorId.and.returnValue(Promise.resolve('12345'));
172+
service.matomoTracker = matomoTracker;
154173
});
155174

156175
it('should add trackerId parameter', fakeAsync(() => {

src/app/statistics/matomo.service.ts

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import {
2+
EnvironmentInjector,
23
inject,
34
Injectable,
5+
runInInjectionContext,
46
} from '@angular/core';
57
import {
68
MatomoInitializerService,
@@ -11,12 +13,10 @@ import {
1113
from as fromPromise,
1214
Observable,
1315
of,
14-
switchMap,
1516
} from 'rxjs';
1617
import {
1718
map,
1819
take,
19-
tap,
2020
} from 'rxjs/operators';
2121

2222
import { environment } from '../../environments/environment';
@@ -31,6 +31,12 @@ import { isNotEmpty } from '../shared/empty.util';
3131
export const MATOMO_TRACKER_URL = 'matomo.tracker.url';
3232
export const MATOMO_SITE_ID = 'matomo.request.siteid';
3333

34+
export const MATOMO_ENABLED = 'matomo.enabled';
35+
36+
/**
37+
* Service to manage Matomo analytics integration.
38+
* Handles initialization and consent management for Matomo tracking.
39+
*/
3440
@Injectable({
3541
providedIn: 'root',
3642
})
@@ -40,14 +46,21 @@ export const MATOMO_SITE_ID = 'matomo.request.siteid';
4046
*/
4147
export class MatomoService {
4248

43-
matomoInitializer = inject(MatomoInitializerService);
44-
matomoTracker = inject(MatomoTracker);
49+
/** Injects the MatomoInitializerService to initialize the Matomo tracker. */
50+
matomoInitializer: MatomoInitializerService;
51+
52+
/** Injects the MatomoTracker to manage Matomo tracking operations. */
53+
matomoTracker: MatomoTracker;
4554
klaroService = inject(KlaroService);
4655
_window = inject(NativeWindowService);
4756

4857
/** Injects the ConfigurationService. */
4958
configService = inject(ConfigurationDataService);
5059

60+
constructor(private injector: EnvironmentInjector) {
61+
62+
}
63+
5164
/**
5265
* Initializes the Matomo tracker if in production environment.
5366
* Sets up the changeMatomoConsent function on the native window object.
@@ -61,24 +74,29 @@ export class MatomoService {
6174
if (environment.production) {
6275
const preferences$ = this.klaroService.getSavedPreferences();
6376

64-
preferences$
65-
.pipe(
66-
tap(preferences => this.changeMatomoConsent(preferences?.matomo)),
67-
switchMap(_ => combineLatest([this.isMatomoEnabled$(), this.getSiteId$(), this.getTrackerUrl$()])),
68-
)
69-
.subscribe(([isMatomoEnabled, siteId, trackerUrl]) => {
77+
combineLatest([preferences$, this.isMatomoEnabled$(), this.getSiteId$(), this.getTrackerUrl$()])
78+
.subscribe(([preferences, isMatomoEnabled, siteId, trackerUrl]) => {
7079
if (isMatomoEnabled && siteId && trackerUrl) {
80+
runInInjectionContext(this.injector, () => {
81+
this.matomoTracker = inject(MatomoTracker);
82+
this.matomoInitializer = inject(MatomoInitializerService);
83+
});
7184
this.matomoInitializer.initializeTracker({ siteId, trackerUrl });
85+
this.changeMatomoConsent(preferences?.matomo);
7286
}
7387
});
7488
}
7589
}
7690

91+
/**
92+
* Changes the Matomo consent status based on the given consent value.
93+
* @param consent - A boolean indicating whether consent is given for Matomo tracking.
94+
*/
7795
changeMatomoConsent = (consent: boolean) => {
7896
if (consent) {
79-
this.matomoTracker.setConsentGiven();
97+
this.matomoTracker?.setConsentGiven();
8098
} else {
81-
this.matomoTracker.forgetConsentGiven();
99+
this.matomoTracker?.forgetConsentGiven();
82100
}
83101
};
84102

@@ -88,7 +106,7 @@ export class MatomoService {
88106
* @returns An Observable that emits the URL with the visitor ID appended.
89107
*/
90108
appendVisitorId(url: string): Observable<string> {
91-
return fromPromise(this.matomoTracker.getVisitorId())
109+
return fromPromise(this.matomoTracker?.getVisitorId())
92110
.pipe(
93111
map(visitorId => this.appendTrackerId(url, visitorId)),
94112
take(1),
@@ -128,6 +146,21 @@ export class MatomoService {
128146
);
129147
}
130148

149+
/**
150+
* Checks if Matomo tracking is enabled by retrieving the configuration property.
151+
* @returns An Observable that emits a boolean indicating whether Matomo tracking is enabled.
152+
*/
153+
isMatomoEnabled$(): Observable<boolean> {
154+
return this.configService.findByPropertyName(MATOMO_ENABLED)
155+
.pipe(
156+
getFirstCompletedRemoteData(),
157+
map((res: RemoteData<ConfigurationProperty>) => {
158+
return res.hasSucceeded && res.payload && isNotEmpty(res.payload.values) &&
159+
res.payload.values[0]?.toLowerCase() === 'true';
160+
}),
161+
);
162+
}
163+
131164
/**
132165
* Appends the visitor ID as a query parameter to the given URL.
133166
* @param url - The original URL to modify

0 commit comments

Comments
 (0)