2020-11-13 03:26:53 +03:00
|
|
|
import React from 'react'
|
2020-11-13 03:33:01 +03:00
|
|
|
import { Link, withRouter } from 'react-router-dom'
|
2020-09-09 11:13:55 +03:00
|
|
|
import {formatDay, formatMonthYYYY, nowForSite, parseUTCDate} from './date'
|
2021-04-28 11:31:10 +03:00
|
|
|
import * as storage from './storage'
|
2019-11-19 07:30:42 +03:00
|
|
|
|
2020-09-09 11:13:55 +03:00
|
|
|
const PERIODS = ['realtime', 'day', 'month', '7d', '30d', '6mo', '12mo', 'custom']
|
2019-11-19 07:30:42 +03:00
|
|
|
|
|
|
|
export function parseQuery(querystring, site) {
|
2019-11-20 08:48:27 +03:00
|
|
|
const q = new URLSearchParams(querystring)
|
|
|
|
let period = q.get('period')
|
2021-01-07 16:24:59 +03:00
|
|
|
const periodKey = `period__${ site.domain}`
|
2019-11-19 07:30:42 +03:00
|
|
|
|
|
|
|
if (PERIODS.includes(period)) {
|
2021-04-28 11:31:10 +03:00
|
|
|
if (period !== 'custom' && period !== 'realtime') storage.setItem(periodKey, period)
|
|
|
|
} else if (storage.getItem(periodKey)) {
|
|
|
|
period = storage.getItem(periodKey)
|
2019-11-19 07:30:42 +03:00
|
|
|
} else {
|
2019-11-19 07:44:54 +03:00
|
|
|
period = '30d'
|
2019-11-19 07:30:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2021-01-07 16:24:59 +03:00
|
|
|
period,
|
2020-09-09 11:13:55 +03:00
|
|
|
date: q.get('date') ? parseUTCDate(q.get('date')) : nowForSite(site),
|
2020-03-04 18:24:18 +03:00
|
|
|
from: q.get('from') ? parseUTCDate(q.get('from')) : undefined,
|
|
|
|
to: q.get('to') ? parseUTCDate(q.get('to')) : undefined,
|
2020-07-30 11:18:28 +03:00
|
|
|
filters: {
|
|
|
|
'goal': q.get('goal'),
|
2020-10-30 11:49:41 +03:00
|
|
|
'props': JSON.parse(q.get('props')),
|
2020-07-30 11:18:28 +03:00
|
|
|
'source': q.get('source'),
|
2020-09-28 11:29:24 +03:00
|
|
|
'utm_medium': q.get('utm_medium'),
|
|
|
|
'utm_source': q.get('utm_source'),
|
|
|
|
'utm_campaign': q.get('utm_campaign'),
|
2020-08-10 16:16:12 +03:00
|
|
|
'referrer': q.get('referrer'),
|
2020-10-13 12:03:42 +03:00
|
|
|
'screen': q.get('screen'),
|
|
|
|
'browser': q.get('browser'),
|
2020-11-10 16:18:59 +03:00
|
|
|
'browser_version': q.get('browser_version'),
|
2020-10-13 12:03:42 +03:00
|
|
|
'os': q.get('os'),
|
2020-11-10 16:18:59 +03:00
|
|
|
'os_version': q.get('os_version'),
|
2020-10-13 12:03:42 +03:00
|
|
|
'country': q.get('country'),
|
Adds entry and exit pages to Top Pages module (#712)
* Initial Pass
* Adds support for page visits counting by referrer
* Includes goal selection in entry and exit computation
* Adds goal-based entry and exit page stats, formatting, code cleanup
* Changelog
* Format
* Exit rate, visit duration, updated tests
* I keep forgetting to format :/
* Tests, last time
* Fixes double counting, exit rate >100%, relevant tests
* Fixes exit pages on filter and goal states
* Adds entry and exit filters, fixes various bugs
* Fixes discussed issues
* Format
* Fixes impossible case in tests
Originally, there were only 2 pageviews for `test-site.com`,`/` on `2019-01-01`, but that doesn't make sense when there were 3 sessions that exited on the same site/date.
* Format
* Removes boolean function parameter in favor of separate function
* Adds support for queries that use `page` filter as `entry-page`
* Format
* Makes loader/title interaction in sources report consistent
2021-02-26 12:02:37 +03:00
|
|
|
'page': q.get('page'),
|
|
|
|
'entry_page': q.get('entry_page'),
|
|
|
|
'exit_page': q.get('exit_page')
|
2020-07-30 11:18:28 +03:00
|
|
|
}
|
2019-11-19 07:30:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-21 16:50:26 +03:00
|
|
|
export function appliedFilters(query) {
|
|
|
|
return Object.keys(query.filters)
|
|
|
|
.map((key) => [key, query.filters[key]])
|
2021-10-11 15:48:19 +03:00
|
|
|
.filter(([_key, value]) => !!value);
|
2020-12-29 12:00:41 +03:00
|
|
|
}
|
|
|
|
|
2020-11-13 03:26:53 +03:00
|
|
|
function generateQueryString(data) {
|
|
|
|
const query = new URLSearchParams(window.location.search)
|
|
|
|
Object.keys(data).forEach(key => {
|
|
|
|
if (!data[key]) {
|
|
|
|
query.delete(key)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
query.set(key, data[key])
|
|
|
|
})
|
|
|
|
return query.toString()
|
|
|
|
}
|
|
|
|
|
2020-11-11 13:23:42 +03:00
|
|
|
export function navigateToQuery(history, queryFrom, newData) {
|
2021-01-07 16:24:59 +03:00
|
|
|
// if we update any data that we store in localstorage, make sure going back in history will
|
|
|
|
// revert them
|
2020-11-11 13:23:42 +03:00
|
|
|
if (newData.period && newData.period !== queryFrom.period) {
|
|
|
|
const replaceQuery = new URLSearchParams(window.location.search)
|
|
|
|
replaceQuery.set('period', queryFrom.period)
|
|
|
|
history.replace({ search: replaceQuery.toString() })
|
|
|
|
}
|
|
|
|
|
|
|
|
// then push the new query to the history
|
2020-11-13 03:26:53 +03:00
|
|
|
history.push({ search: generateQueryString(newData) })
|
|
|
|
}
|
2020-11-11 13:23:42 +03:00
|
|
|
|
2020-11-13 03:33:01 +03:00
|
|
|
class QueryLink extends React.Component {
|
2021-03-31 15:13:58 +03:00
|
|
|
constructor(props) {
|
|
|
|
super(props)
|
2020-11-13 03:26:53 +03:00
|
|
|
this.onClick = this.onClick.bind(this)
|
|
|
|
}
|
|
|
|
|
|
|
|
onClick(e) {
|
|
|
|
e.preventDefault()
|
2020-11-13 03:35:09 +03:00
|
|
|
navigateToQuery(this.props.history, this.props.query, this.props.to)
|
2020-11-13 03:26:53 +03:00
|
|
|
if (this.props.onClick) this.props.onClick(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2021-10-11 15:48:19 +03:00
|
|
|
const { to, ...props } = this.props
|
2021-01-07 16:24:59 +03:00
|
|
|
return (
|
|
|
|
<Link
|
|
|
|
{...props}
|
|
|
|
to={{ pathname: window.location.pathname, search: generateQueryString(to) }}
|
|
|
|
onClick={this.onClick}
|
|
|
|
/>
|
|
|
|
)
|
2020-11-13 03:26:53 +03:00
|
|
|
}
|
2020-11-11 13:23:42 +03:00
|
|
|
}
|
2020-11-13 03:33:01 +03:00
|
|
|
const QueryLinkWithRouter = withRouter(QueryLink)
|
|
|
|
export { QueryLinkWithRouter as QueryLink };
|
2020-11-11 13:23:42 +03:00
|
|
|
|
2021-01-07 16:24:59 +03:00
|
|
|
class QueryButton extends React.Component {
|
|
|
|
render() {
|
|
|
|
const { history, query, to, disabled, className, children } = this.props
|
|
|
|
return (
|
|
|
|
<button
|
|
|
|
className={className}
|
|
|
|
onClick={(event) => {
|
|
|
|
event.preventDefault()
|
|
|
|
navigateToQuery(history, query, to)
|
|
|
|
if (this.props.onClick) this.props.onClick(event)
|
|
|
|
history.push({ pathname: window.location.pathname, search: generateQueryString(to) })
|
|
|
|
}}
|
|
|
|
type="button"
|
|
|
|
disabled={disabled}
|
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</button>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const QueryButtonWithRouter = withRouter(QueryButton)
|
|
|
|
export { QueryButtonWithRouter as QueryButton };
|
|
|
|
|
2019-11-19 07:30:42 +03:00
|
|
|
export function toHuman(query) {
|
|
|
|
if (query.period === 'day') {
|
|
|
|
return `on ${formatDay(query.date)}`
|
2021-01-07 16:24:59 +03:00
|
|
|
} if (query.period === 'month') {
|
2019-11-19 07:30:42 +03:00
|
|
|
return `in ${formatMonthYYYY(query.date)}`
|
2021-01-07 16:24:59 +03:00
|
|
|
} if (query.period === '7d') {
|
2019-11-19 07:30:42 +03:00
|
|
|
return 'in the last 7 days'
|
2021-01-07 16:24:59 +03:00
|
|
|
} if (query.period === '30d') {
|
2019-11-19 07:30:42 +03:00
|
|
|
return 'in the last 30 days'
|
2021-01-07 16:24:59 +03:00
|
|
|
} if (query.period === '6mo') {
|
2020-01-08 12:25:46 +03:00
|
|
|
return 'in the last 6 months'
|
2021-01-07 16:24:59 +03:00
|
|
|
} if (query.period === '12mo') {
|
2020-01-08 12:31:58 +03:00
|
|
|
return 'in the last 12 months'
|
2019-11-19 07:30:42 +03:00
|
|
|
}
|
|
|
|
}
|
2019-11-20 08:48:27 +03:00
|
|
|
|
|
|
|
export function eventName(query) {
|
|
|
|
if (query.filters.goal) {
|
|
|
|
if (query.filters.goal.startsWith('Visit ')) {
|
|
|
|
return 'pageviews'
|
|
|
|
}
|
|
|
|
return 'events'
|
|
|
|
}
|
2021-01-07 16:24:59 +03:00
|
|
|
return 'pageviews'
|
2019-11-20 08:48:27 +03:00
|
|
|
}
|
2021-06-21 14:42:16 +03:00
|
|
|
|
|
|
|
export const formattedFilters = {
|
|
|
|
'goal': 'Goal',
|
|
|
|
'props': 'Goal properties',
|
|
|
|
'source': 'Source',
|
|
|
|
'utm_medium': 'UTM Medium',
|
|
|
|
'utm_source': 'UTM Source',
|
|
|
|
'utm_campaign': 'UTM Campaign',
|
|
|
|
'referrer': 'Referrer URL',
|
|
|
|
'screen': 'Screen size',
|
|
|
|
'browser': 'Browser',
|
|
|
|
'browser_version': 'Browser Version',
|
|
|
|
'os': 'Operating System',
|
|
|
|
'os_version': 'Operating System Version',
|
|
|
|
'country': 'Country',
|
|
|
|
'page': 'Page',
|
|
|
|
'entry_page': 'Entry Page',
|
|
|
|
'exit_page': 'Exit Page'
|
|
|
|
}
|