diff --git a/components/pages/TestConsole.js b/components/pages/TestConsole.js index 8a2afa88..e4fa5a52 100644 --- a/components/pages/TestConsole.js +++ b/components/pages/TestConsole.js @@ -1,4 +1,3 @@ -import React, { useState } from 'react'; import classNames from 'classnames'; import Head from 'next/head'; import Link from 'next/link'; @@ -9,36 +8,37 @@ import DropDown from 'components/common/DropDown'; import WebsiteChart from 'components/metrics/WebsiteChart'; import EventsChart from 'components/metrics/EventsChart'; import Button from 'components/common/Button'; -import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; -import Icon from 'components/common/Icon'; import useFetch from 'hooks/useFetch'; -import useUser from 'hooks/useUser'; -import ChevronDown from 'assets/chevron-down.svg'; import styles from './TestConsole.module.css'; export default function TestConsole() { - const { user } = useUser(); - const [website, setWebsite] = useState(); - const [show, setShow] = useState(true); - const { basePath } = useRouter(); const { data } = useFetch('/websites'); + const router = useRouter(); + const { + basePath, + query: { id }, + } = router; + const websiteId = id?.[0]; - if (!data || !user?.is_admin) { + if (!data) { return null; } const options = data.map(({ name, website_id }) => ({ label: name, value: website_id })); + const website = data.find(({ website_id }) => website_id === +websiteId); const selectedValue = options.find(({ value }) => value === website?.website_id)?.value; + console.log({ websiteId, data, options, website }); + function handleSelect(value) { - setWebsite(data.find(({ website_id }) => website_id === value)); + router.push(`/console/${value}`); } function handleClick() { - window.umami('event (default)'); + window.umami('umami-default'); window.umami.trackView('/page-view', 'https://www.google.com'); - window.umami.trackEvent('event (custom)', null, 'custom-type'); - window.umami.trackEvent('event (custom)', { test: 'test-data' }, 'custom-data-type'); + window.umami.trackEvent('track-event-no-data'); + window.umami.trackEvent('track-event-with-data', { test: 'test-data', time: Date.now() }); } return ( @@ -62,54 +62,47 @@ export default function TestConsole() { onChange={handleSelect} /> - {!selectedValue && } - {selectedValue && ( + {website && ( <> -
- } - className={classNames({ [styles.hidden]: !show })} - onClick={() => setShow(!show)} - /> -
- {show && ( -
-
- Page links -
- - page one - -
-
- - page two - -
-
- - external link - -
+
+
+ Page links +
+ + page one +
-
- CSS events - +
+ + page two +
-
- Javascript events - + +
- )} +
+ CSS events + +
+
+ Javascript events + +
+
); } + +export async function getServerSideProps() { + return { + props: { enabled: !!process.env.ENABLE_TEST_CONSOLE }, + }; +} diff --git a/tracker/index.js b/tracker/index.js index f0584288..17ee467d 100644 --- a/tracker/index.js +++ b/tracker/index.js @@ -5,23 +5,25 @@ import { removeTrailingSlash } from '../lib/url'; const { screen: { width, height }, navigator: { language }, - location: { hostname, pathname, search }, + location, localStorage, document, history, } = window; + const { hostname, pathname, search } = location; + const { currentScript } = document; - const script = document.querySelector('script[data-website-id]'); + if (!currentScript) return; - if (!script) return; - - const attr = script.getAttribute.bind(script); - const website = attr('data-website-id'); - const hostUrl = attr('data-host-url'); - const autoTrack = attr('data-auto-track') !== 'false'; - const dnt = attr('data-do-not-track'); - const cssEvents = attr('data-css-events') !== 'false'; - const domain = attr('data-domains') || ''; + const _data = 'data-'; + const _false = 'false'; + const attr = currentScript.getAttribute.bind(currentScript); + const website = attr(_data + 'website-id'); + const hostUrl = attr(_data + 'host-url'); + const autoTrack = attr(_data + 'auto-track') !== _false; + const dnt = attr(_data + 'do-not-track'); + const cssEvents = attr(_data + 'css-events') !== _false; + const domain = attr(_data + 'domains') || ''; const domains = domain.split(',').map(n => n.trim()); const eventClass = /^umami--([a-z]+)--([\w]+[\w-]*)$/; @@ -34,7 +36,8 @@ import { removeTrailingSlash } from '../lib/url'; const root = hostUrl ? removeTrailingSlash(hostUrl) - : script.src.split('/').slice(0, -1).join('/'); + : currentScript.src.split('/').slice(0, -1).join('/'); + const endpoint = `${root}/api/collect`; const screen = `${width}x${height}`; const listeners = {}; let currentUrl = `${pathname}${search}`; @@ -43,21 +46,6 @@ import { removeTrailingSlash } from '../lib/url'; /* Collect metrics */ - const post = (url, data, callback) => { - const req = new XMLHttpRequest(); - req.open('POST', url, true); - req.setRequestHeader('Content-Type', 'application/json'); - if (cache) req.setRequestHeader('x-umami-cache', cache); - - req.onreadystatechange = () => { - if (req.readyState === 4) { - callback(req.response); - } - }; - - req.send(JSON.stringify(data)); - }; - const getPayload = () => ({ website, hostname, @@ -68,7 +56,7 @@ import { removeTrailingSlash } from '../lib/url'; const assign = (a, b) => { Object.keys(b).forEach(key => { - a[key] = b[key]; + if (b[key] !== undefined) a[key] = b[key]; }); return a; }; @@ -76,17 +64,16 @@ import { removeTrailingSlash } from '../lib/url'; const collect = (type, payload) => { if (trackingDisabled()) return; - post( - `${root}/api/collect`, - { - type, - payload, - }, - res => (cache = res), - ); + return fetch(endpoint, { + method: 'POST', + body: JSON.stringify({ type, payload }), + headers: assign({ 'Content-Type': 'application/json' }, { ['x-umami-cache']: cache }), + }) + .then(res => res.text()) + .then(text => (cache = text)); }; - const trackView = (url = currentUrl, referrer = currentRef, uuid = website) => { + const trackView = (url = currentUrl, referrer = currentRef, uuid = website) => collect( 'pageview', assign(getPayload(), { @@ -95,9 +82,8 @@ import { removeTrailingSlash } from '../lib/url'; referrer, }), ); - }; - const trackEvent = (event_name = 'custom', event_data, url = currentUrl, uuid = website) => { + const trackEvent = (event_name, event_data, url = currentUrl, uuid = website) => collect( 'event', assign(getPayload(), { @@ -107,49 +93,45 @@ import { removeTrailingSlash } from '../lib/url'; event_data, }), ); - }; /* Handle events */ - const sendEvent = name => { - const payload = getPayload(); - - payload.event_name = name; - - const data = JSON.stringify({ - type: 'event', - payload, - }); - - fetch(`${root}/api/collect`, { - method: 'POST', - body: data, - keepalive: true, - }); - }; - const addEvents = node => { const elements = node.querySelectorAll(eventSelect); Array.prototype.forEach.call(elements, addEvent); }; const addEvent = element => { - (element.getAttribute('class') || '').split(' ').forEach(className => { + const get = element.getAttribute.bind(element); + (get('class') || '').split(' ').forEach(className => { if (!eventClass.test(className)) return; - const [, type, name] = className.split('--'); + const [, event, name] = className.split('--'); const listener = listeners[className] ? listeners[className] - : (listeners[className] = () => { - if (element.tagName === 'A') { - sendEvent(name); + : (listeners[className] = e => { + if ( + event === 'click' && + element.tagName === 'A' && + !( + e.ctrlKey || + e.shiftKey || + e.metaKey || + (e.button && e.button === 1) || + get('target') + ) + ) { + e.preventDefault(); + trackEvent(name).then(() => { + location.href = get('href'); + }); } else { trackEvent(name); } }); - element.addEventListener(type, listener, true); + element.addEventListener(event, listener, true); }); };