Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't use localStorage when the browser doesn't support it #971

Merged
merged 2 commits into from
Apr 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.

### Fixed
- Fix weekly report time range plausible/analytics#951
- Make sure embedded dashboards can run when user has blocked third-party cookies plausible/analytics#971

### Removed
- Removes AppSignal monitoring package
Expand Down
7 changes: 4 additions & 3 deletions assets/js/dashboard/query.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import { Link, withRouter } from 'react-router-dom'
import {formatDay, formatMonthYYYY, nowForSite, parseUTCDate} from './date'
import * as storage from './storage'

const PERIODS = ['realtime', 'day', 'month', '7d', '30d', '6mo', '12mo', 'custom']

Expand All @@ -10,9 +11,9 @@ export function parseQuery(querystring, site) {
const periodKey = `period__${ site.domain}`

if (PERIODS.includes(period)) {
if (period !== 'custom' && period !== 'realtime') window.localStorage[periodKey] = period
} else if (window.localStorage[periodKey]) {
period = window.localStorage[periodKey]
if (period !== 'custom' && period !== 'realtime') storage.setItem(periodKey, period)
} else if (storage.getItem(periodKey)) {
period = storage.getItem(periodKey)
} else {
period = '30d'
}
Expand Down
5 changes: 3 additions & 2 deletions assets/js/dashboard/stats/conversions/prop-breakdown.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom'

import * as storage from '../../storage'
import Bar from '../bar'
import numberFormatter from '../../number-formatter'
import * as api from '../../api'
Expand All @@ -10,7 +11,7 @@ export default class PropertyBreakdown extends React.Component {
super(props)
let propKey = props.goal.prop_names[0]
this.storageKey = 'goalPropTab__' + props.site.domain + props.goal.name
const storedKey = window.localStorage[this.storageKey]
const storedKey = storage.getItem(this.storageKey)
if (props.goal.prop_names.includes(storedKey)) {
propKey = storedKey
}
Expand Down Expand Up @@ -70,7 +71,7 @@ export default class PropertyBreakdown extends React.Component {
}

changePropKey(newKey) {
window.localStorage[this.storageKey] = newKey
storage.setItem(this.storageKey, newKey)
this.setState({propKey: newKey, loading: true}, this.fetchPropBreakdown)
}

Expand Down
5 changes: 3 additions & 2 deletions assets/js/dashboard/stats/devices/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom'

import * as storage from '../../storage'
import LazyLoader from '../../lazy-loader'
import Browsers from './browsers'
import OperatingSystems from './operating-systems'
Expand Down Expand Up @@ -117,7 +118,7 @@ export default class Devices extends React.Component {
constructor(props) {
super(props)
this.tabKey = 'deviceTab__' + props.site.domain
const storedTab = window.localStorage[this.tabKey]
const storedTab = storage.getItem(this.tabKey)
this.state = {
mode: storedTab || 'size'
}
Expand All @@ -135,7 +136,7 @@ export default class Devices extends React.Component {

setMode(mode) {
return () => {
window.localStorage[this.tabKey] = mode
storage.setItem(this.tabKey, mode)
this.setState({mode})
}
}
Expand Down
5 changes: 3 additions & 2 deletions assets/js/dashboard/stats/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom'

import * as storage from '../../storage'
import Visits from './pages'
import EntryPages from './entry-pages'
import ExitPages from './exit-pages'
Expand All @@ -16,7 +17,7 @@ export default class Pages extends React.Component {
constructor(props) {
super(props)
this.tabKey = 'pageTab__' + props.site.domain
const storedTab = window.localStorage[this.tabKey]
const storedTab = storage.getItem(this.tabKey)
this.state = {
mode: storedTab || 'pages'
}
Expand All @@ -34,7 +35,7 @@ export default class Pages extends React.Component {

setMode(mode) {
return () => {
window.localStorage[this.tabKey] = mode
storage.setItem(this.tabKey, mode)
this.setState({mode})
}
}
Expand Down
5 changes: 3 additions & 2 deletions assets/js/dashboard/stats/sources/source-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { Link } from 'react-router-dom'
import FlipMove from 'react-flip-move';

import * as storage from '../../storage'
import FadeIn from '../../fade-in'
import Bar from '../bar'
import MoreLink from '../more-link'
Expand Down Expand Up @@ -210,15 +211,15 @@ export default class SourceList extends React.Component {
constructor(props) {
super(props)
this.tabKey = 'sourceTab__' + props.site.domain
const storedTab = window.localStorage[this.tabKey]
const storedTab = storage.getItem(this.tabKey)
this.state = {
tab: storedTab || 'all'
}
}

setTab(tab) {
return () => {
window.localStorage[this.tabKey] = tab
storage.setItem(this.tabKey, tab)
this.setState({tab})
}
}
Expand Down
35 changes: 35 additions & 0 deletions assets/js/dashboard/storage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// This module checks if localStorage is available and uses it for persistent frontend storage
// if possible. Localstorage can be blocked by browsers when people block third-party cookies and
// the dashboard is running in embedded mode. In those cases, store stuff in a regular object instead.

const memStore = {}

// https://stackoverflow.com/a/16427747
function testLocalStorageAvailability(){
try {
const testItem = 'test';
localStorage.setItem(testItem, testItem);
localStorage.removeItem(testItem);
return true;
} catch(e) {
return false;
}
}

const isLocalStorageAvailable = testLocalStorageAvailability()

export function setItem(key, value) {
if (isLocalStorageAvailable) {
window.localStorage.setItem(key, value)
} else {
memStore[key] = value
}
}

export function getItem(key) {
if (isLocalStorageAvailable) {
return window.localStorage.getItem(key)
} else {
return memStore[key]
}
}