Skip to content

Commit

Permalink
feat: save consent in localStorage for browsers
Browse files Browse the repository at this point in the history
  • Loading branch information
SgtPooki committed Jan 19, 2023
1 parent 0026429 commit f25e892
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 6 deletions.
7 changes: 6 additions & 1 deletion src/BrowserMetrics.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import Countly from 'countly-sdk-web'

import MetricsProvider, { MetricsProviderConstructorOptions } from './MetricsProvider.js'
import { BrowserStorageProvider } from './BrowserStorageProvider.js'

export class BrowserMetricsProvider extends MetricsProvider<typeof Countly> {
constructor (args: Omit<MetricsProviderConstructorOptions<typeof Countly>, 'metricsService'>) {
super({ ...args, metricsService: Countly })
super({
metricsService: Countly,
storageProvider: BrowserStorageProvider,
...args
})
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/BrowserStorageProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { StorageProvider } from './types/index.js'

export const BrowserStorageProvider: StorageProvider = {
setStore: (consentArray) => {
try {
const jsonString = JSON.stringify(consentArray)
window.localStorage.setItem('@ipfs-shipyard/ignite-metrics:consent', jsonString)
} catch (err) {
// eslint-disable-next-line no-console
console.error(err)
}
},
getStore: () => {
try {
const jsonString = window.localStorage.getItem('@ipfs-shipyard/ignite-metrics:consent')
if (jsonString != null) {
return JSON.parse(jsonString)
}
} catch (err) {
// eslint-disable-next-line no-console
console.error(err)
}
return []
}
}
34 changes: 30 additions & 4 deletions src/MetricsProvider.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { COUNTLY_API_URL } from './config.js'
import type { metricFeatures, CountlyWebSdk } from 'countly-sdk-web'
import type { CountlyNodeSdk } from 'countly-sdk-nodejs'
import type { consentTypes, consentTypesExceptAll } from './types/index.js'
import type { consentTypes, consentTypesExceptAll, StorageProvider } from './types/index.js'

export interface MetricsProviderConstructorOptions<T> {
appKey: string
url?: string
autoTrack?: boolean
metricsService: T
storageProvider?: StorageProvider | null
}

export default class MetricsProvider<T extends CountlyWebSdk & CountlyNodeSdk> {
export default class MetricsProvider<T extends CountlyWebSdk | CountlyNodeSdk> {
private readonly groupedFeatures: Record<consentTypes, metricFeatures[]> = this.mapAllEvents({
minimal: ['sessions', 'views', 'events'],
performance: ['crashes', 'apm'],
Expand All @@ -22,9 +23,17 @@ export default class MetricsProvider<T extends CountlyWebSdk & CountlyNodeSdk> {
private sessionStarted: boolean = false
private readonly _consentGranted: Set<consentTypes> = new Set()
private readonly metricsService: T

constructor ({ autoTrack = true, url = COUNTLY_API_URL, appKey, metricsService }: MetricsProviderConstructorOptions<T>) {
private readonly storageProvider: StorageProvider | null

constructor ({
autoTrack = true,
url = COUNTLY_API_URL,
appKey,
metricsService,
storageProvider
}: MetricsProviderConstructorOptions<T>) {
this.metricsService = metricsService
this.storageProvider = storageProvider ?? null
this.metricsService.init({
app_key: appKey,
url,
Expand All @@ -36,6 +45,8 @@ export default class MetricsProvider<T extends CountlyWebSdk & CountlyNodeSdk> {
if (autoTrack) {
this.setupAutoTrack()
}

this.getConsentStore().forEach(this.addConsent.bind(this))
}

mapAllEvents (eventMap: Record<consentTypesExceptAll, metricFeatures[]>): Record<consentTypes, metricFeatures[]> {
Expand Down Expand Up @@ -66,6 +77,7 @@ export default class MetricsProvider<T extends CountlyWebSdk & CountlyNodeSdk> {
}
consent.forEach(c => this._consentGranted.add(c))
this.metricsService.add_consent(consent)
this.setConsentStore()
}

removeConsent (consent: consentTypes | consentTypes[]): void {
Expand All @@ -74,6 +86,20 @@ export default class MetricsProvider<T extends CountlyWebSdk & CountlyNodeSdk> {
}
consent.forEach(c => this._consentGranted.delete(c))
this.metricsService.remove_consent(consent, true)
this.setConsentStore()
}

private setConsentStore (): void {
if (this.storageProvider != null) {
this.storageProvider.setStore(Array.from(this._consentGranted))
}
}

private getConsentStore (): consentTypes[] {
if (this.storageProvider != null) {
return this.storageProvider.getStore()
}
return []
}

checkConsent (consent: consentTypes | metricFeatures): boolean {
Expand Down
5 changes: 4 additions & 1 deletion src/NodeMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import MetricsProvider, { MetricsProviderConstructorOptions } from './MetricsPro

export class NodeMetricsProvider extends MetricsProvider<typeof Countly> {
constructor (args: Omit<MetricsProviderConstructorOptions<typeof Countly>, 'metricsService'>) {
super({ ...args, metricsService: Countly })
super({
metricsService: Countly,
...args
})
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@

export type consentTypesExceptAll = 'minimal' | 'performance' | 'ux' | 'feedback' | 'location'
export type consentTypes = 'all' | consentTypesExceptAll

export interface StorageProvider {
setStore: (values: consentTypes[]) => void
getStore: () => consentTypes[]
}

0 comments on commit f25e892

Please sign in to comment.