Skip to content

Instantly share code, notes, and snippets.

@dtarnawsky
Last active September 28, 2021 18:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dtarnawsky/7bdb4df4692501c826b828246761e57c to your computer and use it in GitHub Desktop.
Save dtarnawsky/7bdb4df4692501c826b828246761e57c to your computer and use it in GitHub Desktop.
Google Analytics Service
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { NavigationEnd } from '@angular/router';
import { isDefined } from 'lib/util';
let singletonInstance: AnalyticsService;
export const analyticsServiceSingleton: Function = (): AnalyticsService => singletonInstance;
export interface EventParams {
action: string;
label?: string;
newSession?: boolean;
value?: number;
}
// tslint:disable:no-console
@Injectable()
export class AnalyticsService {
private active: boolean = false;
private currentUser: string;
private gaCode: string;
private appVersion: string;
private clientid: string;
public constructor(private http: HttpClient) {
singletonInstance = this;
}
/**
* @param {string} gaCode - Google Analytics code
* @param {string} user - Username
* @param {string} uniqueId - Unique Id for the device
* @returns void
*/
public SetupGoogleAnalytics(gaCode: string, user: string, uniqueId: string): void {
this.clientid = uniqueId;
this.currentUser = user;
this.gaCode = gaCode;
this.active = true;
}
public async view(title: string, path?: string): Promise<boolean> {
return await this.write({ t: 'pageview', dp: path, dt: title, dl: location.pathname });
}
public setAppVersion(version?: string): void {
if (isDefined(version)) {
this.appVersion = version;
}
}
public async event(
category: string,
action: string,
label?: string,
value?: number,
newSession?: boolean
): Promise<boolean> {
return await this.write({ t: 'event', ec: category, ea: action, el: label, ev: value });
}
public error(description: string): void {
this.write({ t: 'exception', exd: description, exf: 0 });
console.log(`Analytics Error: ${description}`);
}
/**
* Tracks the page view based on Angular route taken. Formats the route title better for tracking
* @param {NavigationEnd} route
*/
public viewRoute(route: NavigationEnd): string {
try {
const tabIdx: number = route.url.indexOf(':') + 1;
let title: string = route.url.substring(tabIdx).replace(')', '');
title = decodeURIComponent(title);
title = this.toTitleCase(title);
return title;
} catch {
// Analytics are not important enough to break the app. So catch all
}
}
/**
* Set the user for Analytics
* @param {string} user
* @returns void
*/
public setUser(user: string): void {
this.currentUser = user || 'guest';
}
private toTitleCase(input: string): string {
return input.length === 0
? ''
: input.replace(/\w\S*/g, (txt: string) => txt[0].toUpperCase() + txt.substr(1).toLowerCase());
}
private async write(ob: any): Promise<boolean> {
if (!this.active) {
console.log('analytics is disabled');
return false;
}
const standard: object = {
v: '1',
tid: this.gaCode,
cid: this.clientid,
uid: this.currentUser,
an: 'MyApplication',
av: this.appVersion
};
const data: string = `${this.serialize(standard)}&${this.serialize(ob)}`;
const options: any = { headers: new HttpHeaders({ 'Content-Type': 'text/plain' }), responseType: 'text' };
try {
await this.http.post('https://www.google-analytics.com/collect', data, options).toPromise();
} finally {
return true;
}
}
private serialize(obj: object): string {
const str: Array<string> = [];
for (const p in obj) {
if (obj.hasOwnProperty(p)) {
if (obj[p] !== undefined) {
str.push(`${encodeURIComponent(p)}=${encodeURIComponent(obj[p])}`);
}
}
}
return str.join('&');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment