From 809b127e4e9d5c9b003ae14d58fab93dbcd24960 Mon Sep 17 00:00:00 2001 From: Mewis Date: Wed, 2 Nov 2022 15:45:13 +0000 Subject: [PATCH] feat: Add incendium provider (#458) --- src/app/providers/providers.component.ts | 9 +- src/assets/svg/incendium.svg | 30 ++++++ src/lib/providers/incendium/README.md | 100 ++++++++++++++++++ src/lib/providers/incendium/incendium.spec.ts | 74 +++++++++++++ src/lib/providers/incendium/incendium.ts | 86 +++++++++++++++ 5 files changed, 296 insertions(+), 3 deletions(-) create mode 100644 src/assets/svg/incendium.svg create mode 100644 src/lib/providers/incendium/README.md create mode 100644 src/lib/providers/incendium/incendium.spec.ts create mode 100644 src/lib/providers/incendium/incendium.ts diff --git a/src/app/providers/providers.component.ts b/src/app/providers/providers.component.ts index d463261..59d5dfa 100644 --- a/src/app/providers/providers.component.ts +++ b/src/app/providers/providers.component.ts @@ -64,6 +64,11 @@ export class ProvidersComponent { display: 'HubSpot', type: 'Analytics', }, + { + name: 'incendium', + display: 'Incendium', + type: 'Analytics', + }, { name: 'intercom', display: 'Intercom', @@ -114,9 +119,7 @@ export class ProvidersComponent { for (const provider of this.providers) { iconRegistry.addSvgIcon( provider.name, - sanitizer.bypassSecurityTrustResourceUrl( - `/assets/svg/${provider.name}.svg`, - ), + sanitizer.bypassSecurityTrustResourceUrl(`/assets/svg/${provider.name}.svg`), ); } } diff --git a/src/assets/svg/incendium.svg b/src/assets/svg/incendium.svg new file mode 100644 index 0000000..1412492 --- /dev/null +++ b/src/assets/svg/incendium.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + diff --git a/src/lib/providers/incendium/README.md b/src/lib/providers/incendium/README.md new file mode 100644 index 0000000..43ce30b --- /dev/null +++ b/src/lib/providers/incendium/README.md @@ -0,0 +1,100 @@ +Incendium analytics logo + +**homepage**: [incendium.ai](https://www.incendium.ai/) +**import**: `import { Angulartics2Incendium } from 'angulartics2';` + +## Setup + +1. Add tracking code provided by Incendium inside the header tag. + +2. [Setup Angulartics](https://github.com/angulartics/angulartics2/tree/master#installation) using `Angulartics2Incendium` + + ```typescript + constructor(Angulartics2Incendium: Angulartics2Incendium) { + Angulartics2Incendium.startTracking(); + } + ``` + +3. Track Conversions, You can track conversions using Angulartics2 event tracking. + this can be done by adding the following to you html + + ```html + + ``` + + Note that eIncendiumEventNames is a reference to IncendiumEventNames expoted from Angulartics2Incendium + + Or you can fire the conversion in code for example + + ```typescript + this.angulartics2.eventTrack.next({ + action: IncendiumEventNames.ADD_CONVERION, + properties: { + key: 'my_trigger_as_assigned_in_incendium', + }, + }); + ``` + +4. Incendium allows for offline tracking, to do this you must record the conversion key provided when firing a conversion. + A example of this would be a contact form which you later convert on the phone, incendium allows you to assign revenue next to this original conversion using this key + + to do this fire a conversion off as above. + you can then subscribe to incendiumResponse. once the conversion has been tracked and response is returned you can use this response how ever you like. + + **_Dont forget to unsubscribe_** + + An Example workflow of this would be + + ```typescript + export class Example implements OnInit { + private incSubscription; + + constructor( + private angulartics2: Angulartics2, + private angulartics2Incendium: Angulartics2Incendium, + ) {} + + ngOnInit(): void { + this.incSubscription = this.angulartics2Incendium.incendiumResponse.subscribe({ + next: v => { + if (v.type === IncendiumEventNames.ADD_CONVERION) { + this.submit(v.value); + } + }, + error: e => { + console.error(e); + // submit without key or handle how you like + this.submit(); + }, + }); + } + + ngOnDestroy(): void { + // Dont forget to unsubscribe + this.incSubscription.unsubscribe(); + } + + onSubmit() { + this.angulartics2.eventTrack.next({ + action: IncendiumEventNames.ADD_CONVERION, + properties: { + key: 'my_trigger_as_assigned_in_incendium', + }, + }); + } + + submit(incendiumKey?: string) { + alert(`form submitted with ${incendiumKey ? `key ${incendiumKey}` : `no key`}`); + } + } + ``` diff --git a/src/lib/providers/incendium/incendium.spec.ts b/src/lib/providers/incendium/incendium.spec.ts new file mode 100644 index 0000000..c01caa3 --- /dev/null +++ b/src/lib/providers/incendium/incendium.spec.ts @@ -0,0 +1,74 @@ +import { fakeAsync, inject, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { Angulartics2 } from '../../angulartics2-core'; +import { advance, createRoot, RootCmp, TestModule } from '../../test.mocks'; +import { Angulartics2Incendium, IncendiumEventNames } from './incendium'; + +jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; +declare var window: any; + +describe('Angulartics2Incendium', () => { + let inc: any; + let fixture: ComponentFixture; + let service: Angulartics2Incendium; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TestModule], + providers: [Angulartics2Incendium], + }); + window.inc = inc = jasmine.createSpy('inc').and.returnValue('test'); + + service = TestBed.inject(Angulartics2Incendium); + service.startTracking(); + }); + + it('should track pages', fakeAsync( + inject( + [Angulartics2, Angulartics2Incendium], + (angulartics2: Angulartics2, Angulartics2Incendium: Angulartics2Incendium) => { + fixture = createRoot(RootCmp); + angulartics2.pageTrack.next({ path: '/abc' }); + advance(fixture); + expect(inc).toHaveBeenCalledWith('run', false, true); + }, + ), + )); + + it('should track conversions', fakeAsync( + inject( + [Angulartics2, Angulartics2Incendium], + (angulartics2: Angulartics2, Angulartics2Incendium: Angulartics2Incendium) => { + fixture = createRoot(RootCmp); + angulartics2.eventTrack.next({ + action: IncendiumEventNames.ADD_CONVERION, + properties: { key: 'test' }, + }); + advance(fixture); + expect(inc).toHaveBeenCalledTimes(2); + expect(inc).toHaveBeenCalledWith(IncendiumEventNames.ADD_CONVERION, 'test'); + expect(inc).toHaveBeenCalledWith('go'); + }, + ), + )); + + it('should track conversion and emit conversion key', fakeAsync( + inject( + [Angulartics2, Angulartics2Incendium], + (angulartics2: Angulartics2, Angulartics2Incendium: Angulartics2Incendium) => { + service.incendiumResponse.subscribe(message => { + expect(message).toEqual({ + type: IncendiumEventNames.ADD_CONVERION, + value: 'test', + }); + }); + fixture = createRoot(RootCmp); + angulartics2.eventTrack.next({ + action: IncendiumEventNames.ADD_CONVERION, + properties: { key: 'test' }, + }); + advance(fixture); + }, + ), + )); +}); diff --git a/src/lib/providers/incendium/incendium.ts b/src/lib/providers/incendium/incendium.ts new file mode 100644 index 0000000..4ab1e0b --- /dev/null +++ b/src/lib/providers/incendium/incendium.ts @@ -0,0 +1,86 @@ +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs'; +import { Angulartics2 } from '../../angulartics2-core'; + +enum EventNames { + RUN = 'run', + GO = 'go', +} + +export enum IncendiumEventNames { + ADD_CONVERION = 'add_conversion', +} + +interface IIncendiumResponse { + value: string; + type: IncendiumEventNames; +} + +type TIncendiumParams = + | { + key: string; + } + | boolean; + +declare var inc: (e: EventNames | IncendiumEventNames, v?: TIncendiumParams, g?: boolean) => string; +declare global { + interface Window { + INCENDIUM: any; + } +} + +@Injectable({ providedIn: 'root' }) +export class Angulartics2Incendium { + incendiumResponse = new Subject>(); + + constructor(private angulartics2: Angulartics2) { + if (typeof inc === 'undefined') { + console.warn('Angulartics 2 Incendium Plugin: incendium global not found'); + } + } + + startTracking(): void { + this.angulartics2.pageTrack + .pipe(this.angulartics2.filterDeveloperMode()) + .subscribe(x => this.pageTrack(x.path)); + + this.angulartics2.eventTrack + .pipe(this.angulartics2.filterDeveloperMode()) + .subscribe(({ action, properties }) => this.trackAction(action, properties)); + } + + /** + * Track Page in Incendium + * + * @param path location + */ + pageTrack(path: string) { + inc(EventNames.RUN, false, true); + } + + /** + * Track Action + * + * @param action Action name + * @param properties params + */ + async trackAction(action: string, properties: any) { + try { + switch (action as IncendiumEventNames) { + case IncendiumEventNames.ADD_CONVERION: + inc(IncendiumEventNames.ADD_CONVERION, properties.key); + break; + + default: + break; + } + const res = await inc(EventNames.GO); + this.incendiumResponse.next({ + value: res, + type: IncendiumEventNames.ADD_CONVERION, + }); + } catch (error) { + this.incendiumResponse.error(error); + } + } +}