Refactored realtime.

This commit is contained in:
Mike Cao 2024-06-19 21:47:27 -07:00
parent cda3ba345b
commit 5108b91f80
16 changed files with 205 additions and 227 deletions

View file

@ -5,7 +5,7 @@ import styles from './RealtimeHeader.module.css';
export function RealtimeHeader({ data }: { data: RealtimeData }) {
const { formatMessage, labels } = useMessages();
const { pageviews, visitors, events, countries } = data || {};
const { totals }: any = data || {};
return (
<div className={styles.header}>
@ -13,22 +13,22 @@ export function RealtimeHeader({ data }: { data: RealtimeData }) {
<MetricCard
className={styles.card}
label={formatMessage(labels.views)}
value={pageviews?.length}
value={totals.views}
/>
<MetricCard
className={styles.card}
label={formatMessage(labels.visitors)}
value={visitors?.length}
value={totals.visitors}
/>
<MetricCard
className={styles.card}
label={formatMessage(labels.events)}
value={events?.length}
value={totals.events}
/>
<MetricCard
className={styles.card}
label={formatMessage(labels.countries)}
value={countries?.length}
value={totals.countries}
/>
</div>
</div>

View file

@ -54,20 +54,20 @@ export function RealtimeLog({ data }: { data: RealtimeData }) {
},
];
const getTime = ({ timestamp }) => format(timestamp, 'h:mm:ss');
const getTime = ({ timestamp }) => format(timestamp * 1000, 'h:mm:ss');
const getColor = ({ id, sessionId }) => stringToColor(sessionId || id);
const getIcon = ({ __type }) => icons[__type];
const getDetail = (log: {
__type: any;
eventName: any;
urlPath: any;
browser: any;
os: any;
country: any;
device: any;
__type: string;
eventName: string;
urlPath: string;
browser: string;
os: string;
country: string;
device: string;
}) => {
const { __type, eventName, urlPath: url, browser, os, country, device } = log;
@ -141,8 +141,12 @@ export function RealtimeLog({ data }: { data: RealtimeData }) {
return [];
}
const { pageviews, visitors, events } = data;
let logs = [...pageviews, ...visitors, ...events].sort(thenby.firstBy('createdAt', -1));
const { events, visitors } = data;
let logs = [
...events.map(e => ({ __type: e.eventName ? TYPE_EVENT : TYPE_PAGEVIEW, ...e })),
...visitors.map(v => ({ __type: TYPE_SESSION, ...v })),
].sort(thenby.firstBy('timestamp', -1));
if (search) {
logs = logs.filter(({ eventName, urlPath, browser, os, country, device }) => {

View file

@ -1,4 +1,4 @@
import { Key, useContext, useMemo, useState } from 'react';
import { Key, useContext, useState } from 'react';
import { ButtonGroup, Button, Flexbox } from 'react-basics';
import thenby from 'thenby';
import { percentFilter } from 'lib/filters';
@ -11,7 +11,7 @@ import { WebsiteContext } from '../WebsiteProvider';
export function RealtimeUrls({ data }: { data: RealtimeData }) {
const website = useContext(WebsiteContext);
const { formatMessage, labels } = useMessages();
const { pageviews } = data || {};
const { referrers, urls } = data || {};
const [filter, setFilter] = useState<Key>(FILTER_REFERRERS);
const limit = 15;
@ -35,47 +35,29 @@ export function RealtimeUrls({ data }: { data: RealtimeData }) {
);
};
const [referrers = [], pages = []] = useMemo(() => {
if (pageviews) {
const referrers = percentFilter(
pageviews
.reduce((arr, { referrerDomain }) => {
if (referrerDomain) {
const row = arr.find(({ x }) => x === referrerDomain);
const domains = percentFilter(
Object.keys(referrers)
.map(key => {
return {
x: key,
y: referrers[key],
};
})
.sort(thenby.firstBy('y', -1))
.slice(0, limit),
);
if (!row) {
arr.push({ x: referrerDomain, y: 1 });
} else {
row.y += 1;
}
}
return arr;
}, [])
.sort(thenby.firstBy('y', -1))
.slice(0, limit),
);
const pages = percentFilter(
pageviews
.reduce((arr, { urlPath }) => {
const row = arr.find(({ x }) => x === urlPath);
if (!row) {
arr.push({ x: urlPath, y: 1 });
} else {
row.y += 1;
}
return arr;
}, [])
.sort(thenby.firstBy('y', -1))
.slice(0, limit),
);
return [referrers, pages];
}
return [];
}, [pageviews]);
const pages = percentFilter(
Object.keys(urls)
.map(key => {
return {
x: key,
y: urls[key],
};
})
.sort(thenby.firstBy('y', -1))
.slice(0, limit),
);
return (
<>
@ -89,7 +71,7 @@ export function RealtimeUrls({ data }: { data: RealtimeData }) {
title={formatMessage(labels.referrers)}
metric={formatMessage(labels.views)}
renderLabel={renderLink}
data={referrers}
data={domains}
/>
)}
{filter === FILTER_PAGES && (

View file

@ -1,4 +1,5 @@
'use client';
import { firstBy } from 'thenby';
import { Grid, GridRow } from 'components/layout/Grid';
import Page from 'components/layout/Page';
import RealtimeChart from 'components/metrics/RealtimeChart';
@ -10,6 +11,7 @@ import RealtimeUrls from './RealtimeUrls';
import RealtimeCountries from './RealtimeCountries';
import WebsiteHeader from '../WebsiteHeader';
import WebsiteProvider from '../WebsiteProvider';
import { percentFilter } from 'lib/filters';
export function WebsiteRealtimePage({ websiteId }) {
const { data, isLoading, error } = useRealtime(websiteId);
@ -18,6 +20,12 @@ export function WebsiteRealtimePage({ websiteId }) {
return <Page isLoading={isLoading} error={error} />;
}
const countries = percentFilter(
Object.keys(data.countries)
.map(key => ({ x: key, y: data.countries[key] }))
.sort(firstBy('y', -1)),
);
return (
<WebsiteProvider websiteId={websiteId}>
<WebsiteHeader websiteId={websiteId} />
@ -29,8 +37,8 @@ export function WebsiteRealtimePage({ websiteId }) {
<RealtimeLog data={data} />
</GridRow>
<GridRow columns="one-two">
<RealtimeCountries data={data?.countries} />
<WorldMap data={data?.countries} />
<RealtimeCountries data={countries} />
<WorldMap data={countries} />
</GridRow>
</Grid>
</WebsiteProvider>