diff --git a/lib/static/app/logger.js b/lib/static/app/logger.js index 4ba5ad5..76eb53d 100644 --- a/lib/static/app/logger.js +++ b/lib/static/app/logger.js @@ -1,4 +1,8 @@ class Logger { + constructor() { + this._remote = false + } + log({ message, level, service }) { console.info( `%c${level}\n%c${service}\n%c${message}`, @@ -7,9 +11,17 @@ class Logger { 'color: black' ) + if (!this._remote) { + return + } + this._log({ message, level, service }) } + setRemoteLogging(value) { + this._remote = value + } + _log({ message, level, service }) { return new Promise((resolve, reject) => { fetch('/track', { diff --git a/lib/static/app/storage.js b/lib/static/app/storage.js index 3988a18..bb60519 100644 --- a/lib/static/app/storage.js +++ b/lib/static/app/storage.js @@ -27,6 +27,21 @@ const getStorage = () => { return storage } +const getConfigStorage = () => { + if (!useStorage()) { + return null + } + + const storage = localStorage.getItem('fb-to-ical-config') + + if (!storage) { + localStorage.setItem('fb-to-ical-config', JSON.stringify({})) + return "{}" + } + + return storage +} + const getStorageContents = (storage) => { return JSON.parse(storage) } @@ -37,6 +52,15 @@ const updateStorage = (storageContents) => { localStorage.setItem('fb-to-ical-events', encodedStorage) } +const updateConfigStorage = (storageContents, key, value) => { + const encodedStorage = JSON.stringify({ + ...storageContents, + [key]: value, + }) + + localStorage.setItem('fb-to-ical-config', encodedStorage) +} + const saveRecord = ({ id, link, createdAt, startTime, title }) => { if (!useStorage()) { return @@ -80,8 +104,10 @@ const deleteRecord = (id) => { export { migrateRecord, getStorage, + getConfigStorage, getStorageContents, updateStorage, + updateConfigStorage, saveRecord, deleteRecord, } diff --git a/lib/static/index.js b/lib/static/index.js index bd0a4f5..8ee6608 100644 --- a/lib/static/index.js +++ b/lib/static/index.js @@ -2,8 +2,10 @@ import { uuidv4, parseStartTimeFromiCalString, useStorage } from './app/utils' import { migrateRecord, getStorage, + getConfigStorage, getStorageContents, updateStorage, + updateConfigStorage, saveRecord, deleteRecord, } from './app/storage' @@ -31,6 +33,40 @@ import generateICS from '../../lib/services/ics-generator' row.remove() } + const renderTrackingPanel = (storageContents) => { + const trackingPanel = document.createElement('div') + trackingPanel.id = 'tracking-panel' + + const text = document.createElement('p') + text.innerText = `Can we store anonymous logs? This data is only saved to \ +our internal database and is used to debug the parsing of the web pages.\n\ +We'll ask you only this time and won't bother you again.` + + const yesButton = document.createElement('button') + yesButton.id = 'tracking-panel__yes-button' + yesButton.innerText = 'Ok' + yesButton.addEventListener('click', () => { + updateConfigStorage(storageContents, 'track', true) + logger.setRemoteLogging(true) + trackingPanel.remove() + }) + + const noButton = document.createElement('button') + noButton.id = 'tracking-panel__no-button' + noButton.innerText = 'Nope' + noButton.addEventListener('click', () => { + updateConfigStorage(storageContents, 'track', false) + logger.setRemoteLogging(false) + trackingPanel.remove() + }) + + trackingPanel.appendChild(text) + trackingPanel.appendChild(yesButton) + trackingPanel.appendChild(noButton) + + document.body.appendChild(trackingPanel) + } + const insertTableRow = ({ id, link, createdAt, startTime, title }) => { showTable() @@ -122,6 +158,34 @@ import generateICS from '../../lib/services/ics-generator' }) } + const hydrateConfig = () => { + if (!useStorage()) { + return + } + + const prevStorage = getConfigStorage() + const storageContents = getStorageContents(prevStorage) + + const useTrackingSet = storageContents.track !== undefined + + if (!useTrackingSet) { + renderTrackingPanel(storageContents) + } + } + + const configureLogger = (logger) => { + if (!logger || !useStorage()) { + return + } + + const prevStorage = getConfigStorage() + const storageContents = getStorageContents(prevStorage) + + const shouldTrack = Boolean(storageContents.track) + + logger.setRemoteLogging(shouldTrack) + } + const clearStatuses = () => { document.querySelectorAll('.status-item').forEach((item) => { item.classList.remove('show') @@ -235,6 +299,8 @@ import generateICS from '../../lib/services/ics-generator' } hydrateList() + hydrateConfig() + configureLogger(logger) const handleHTMLResponse = (html, url) => { try { diff --git a/lib/static/style.css b/lib/static/style.css index 0aee628..7d51b37 100644 --- a/lib/static/style.css +++ b/lib/static/style.css @@ -166,3 +166,23 @@ a.delete-record { #nojs { margin: 5px 0; } + +#tracking-panel { + position: fixed; + bottom: 0; + border: 3px solid navy; + background-color: lightyellow; + max-width: 600px; + margin: 5px; + padding: 5px; +} + +#tracking-panel__yes-button, +#tracking-panel__no-button { + font-size: 1.2rem; +} + +#tracking-panel__yes-button { + font-weight: 600; + margin-right: 5px; +}