@bemit/consent-ui
Version:
© 2022 [bemit](https://bemit.eu)
130 lines • 3.99 kB
JavaScript
import { EventAware } from '@bemit/consent-ui/EventAware';
const consentState = {
current: undefined
};
export class ConsentUiState extends EventAware {
initialized = false;
hasChosen = false;
acceptedVersion = undefined;
tag = undefined;
userPrefers = undefined;
trackersState = {};
trackersActivatedHistory = {};
trackers = undefined;
constructor(settings) {
super();
this.version = settings.version;
this.localKey = settings.localKey;
this.trackers = settings.trackers;
}
init() {
const tag = this.readTag();
if (tag) {
this.hasChosen = Boolean(tag.prefers);
this.acceptedVersion = tag.version;
this.tag = tag.tag;
this.userPrefers = tag.prefers;
this.dispatchPreferences();
}
this.initialized = true;
}
dispatchPreferences() {
const userPrefers = this.userPrefers;
if (userPrefers) {
const trackerInfoRaw = this.trackers?.map((tracker, id) => {
const trackerShouldBeActive = tracker.shouldBe(userPrefers);
const currentStatus = this.trackersState[id];
return {
status: trackerShouldBeActive ? currentStatus ? 'still-active' : 'to-activate' : !currentStatus ? 'still-inactive' : 'was-active',
id,
tracker
};
}) || [];
const trackerInfo = trackerInfoRaw.filter(ti => ti.status !== 'still-active' && ti.status !== 'still-inactive');
const trackerInfoToDestroy = trackerInfo.filter(ti => ti.status === 'was-active');
const trackerInfoToActivate = trackerInfo.filter(ti => ti.status === 'to-activate');
const needsRefresh = trackerInfoToDestroy.reduce((needsRefresh, ti) => {
const destroyed = ti.tracker.destroy();
delete this.trackersState[ti.id];
return Boolean(needsRefresh || destroyed?.requiresRefresh);
}, false);
if (needsRefresh) {
window.location.reload(true);
return;
}
trackerInfoToActivate.forEach(ti => {
ti.tracker.create(Boolean(this.trackersActivatedHistory[ti.id]));
this.trackersState[ti.id] = true;
this.trackersActivatedHistory[ti.id] = true;
});
}
}
readTag() {
const tagRaw = window.localStorage.getItem(this.localKey);
if (!tagRaw) return undefined;
let tag = window.localStorage.getItem(this.localKey);
try {
tag = JSON.parse(tagRaw);
} catch (_e) {}
return {
version: tag?.version || undefined,
tag: tag?.tag || undefined,
prefers: tag?.version === this.version ? tag.prefers || undefined : undefined
};
}
giveConsent(preferences = {}) {
this.hasChosen = true;
this.acceptedVersion = this.version;
this.userPrefers = preferences;
this.persistConsent();
this.call('consent', this.version);
this.dispatchPreferences();
}
updateConsent(type, id, prefer) {
if (!this.hasChosen || !this.userPrefers) return;
const p = {
...this.userPrefers
};
p[type] = {
...(p[type] || {}),
[id]: prefer
};
this.userPrefers = p;
this.persistConsent();
this.call('consent', this.version);
this.dispatchPreferences();
}
persistConsent() {
window.localStorage.setItem(this.localKey, JSON.stringify({
version: this.acceptedVersion,
tag: this.tag,
prefers: this.userPrefers
}));
}
onConsent(cb) {
const evtId = this.on('consent', cb);
return () => this.off('consent', evtId);
}
toState() {
return {
ready: this.initialized,
hasChosen: this.hasChosen,
consent: this.acceptedVersion,
tag: this.tag,
userPrefers: this.userPrefers
};
}
}
export const defineConsent = options => {
const ui = new ConsentUiState({
version: options.version,
localKey: options.localKey,
trackers: options.trackers
});
consentState.current = ui;
return ui.init();
};
export const prepareConsent = defineConsent;
export const consentUi = () => {
return consentState.current;
};