Convert realtime components to TS.

This commit is contained in:
Mike Cao 2023-12-09 00:35:54 -08:00
parent e67282d7d8
commit 8d31f43f0f
12 changed files with 75 additions and 51 deletions

View File

@ -6,7 +6,7 @@ import { EventDataMetricsBar } from './EventDataMetricsBar';
import { useDateRange, useApi, useNavigation } from 'components/hooks';
import styles from './WebsiteEventData.module.css';
function useData(websiteId, event) {
function useData(websiteId: string, event: string) {
const [dateRange] = useDateRange(websiteId);
const { startDate, endDate } = dateRange;
const { get, useQuery } = useApi();

View File

@ -1,7 +1,7 @@
'use client';
import { useMemo, useState, useEffect } from 'react';
import { subMinutes, startOfMinute } from 'date-fns';
import firstBy from 'thenby';
import thenby from 'thenby';
import { Grid, GridRow } from 'components/layout/Grid';
import Page from 'components/layout/Page';
import RealtimeChart from 'components/metrics/RealtimeChart';
@ -15,9 +15,10 @@ import useApi from 'components/hooks/useApi';
import { percentFilter } from 'lib/filters';
import { REALTIME_RANGE, REALTIME_INTERVAL } from 'lib/constants';
import { useWebsite } from 'components/hooks';
import { RealtimeData } from 'lib/types';
import styles from './Realtime.module.css';
function mergeData(state = [], data = [], time) {
function mergeData(state = [], data = [], time: number) {
const ids = state.map(({ __id }) => __id);
return state
.concat(data.filter(({ __id }) => !ids.includes(__id)))
@ -25,7 +26,7 @@ function mergeData(state = [], data = [], time) {
}
export function Realtime({ websiteId }) {
const [currentData, setCurrentData] = useState();
const [currentData, setCurrentData] = useState<RealtimeData>();
const { get, useQuery } = useApi();
const { data: website } = useWebsite(websiteId);
const { data, isLoading, error } = useQuery({
@ -33,7 +34,6 @@ export function Realtime({ websiteId }) {
queryFn: () => get(`/realtime/${websiteId}`, { startAt: currentData?.timestamp || 0 }),
enabled: !!(websiteId && website),
refetchInterval: REALTIME_INTERVAL,
cache: false,
});
useEffect(() => {
@ -50,9 +50,9 @@ export function Realtime({ websiteId }) {
}
}, [data]);
const realtimeData = useMemo(() => {
const realtimeData: RealtimeData = useMemo(() => {
if (!currentData) {
return { pageviews: [], sessions: [], events: [], countries: [], visitors: [] };
return { pageviews: [], sessions: [], events: [], countries: [], visitors: [], timestamp: 0 };
}
currentData.countries = percentFilter(
@ -75,7 +75,7 @@ export function Realtime({ websiteId }) {
}
return arr;
}, [])
.sort(firstBy('y', -1)),
.sort(thenby.firstBy('y', -1)),
);
currentData.visitors = currentData.sessions.reduce((arr, val) => {
@ -89,18 +89,18 @@ export function Realtime({ websiteId }) {
}, [currentData]);
if (isLoading || error) {
return <Page loading={isLoading} error={error} />;
return <Page isLoading={isLoading} error={error} />;
}
return (
<>
<WebsiteHeader websiteId={websiteId} />
<RealtimeHeader websiteId={websiteId} data={currentData} />
<RealtimeHeader data={currentData} />
<RealtimeChart className={styles.chart} data={realtimeData} unit="minute" />
<Grid>
<GridRow columns="one-two">
<RealtimeUrls websiteId={websiteId} websiteDomain={website?.domain} data={realtimeData} />
<RealtimeLog websiteId={websiteId} websiteDomain={website?.domain} data={realtimeData} />
<RealtimeUrls websiteDomain={website?.domain} data={realtimeData} />
<RealtimeLog websiteDomain={website?.domain} data={realtimeData} />
</GridRow>
<GridRow columns="one-two">
<RealtimeCountries data={realtimeData?.countries} />

View File

@ -1,10 +1,11 @@
import MetricCard from 'components/metrics/MetricCard';
import useMessages from 'components/hooks/useMessages';
import { RealtimeData } from 'lib/types';
import styles from './RealtimeHeader.module.css';
export function RealtimeHeader({ data = {} }) {
export function RealtimeHeader({ data }: { data: RealtimeData }) {
const { formatMessage, labels } = useMessages();
const { pageviews, visitors, events, countries } = data;
const { pageviews, visitors, events, countries } = data || {};
return (
<div className={styles.header}>

View File

@ -1,7 +1,7 @@
import { useMemo, useState } from 'react';
import { StatusLight, Icon, Text } from 'react-basics';
import { FixedSizeList } from 'react-window';
import firstBy from 'thenby';
import thenby from 'thenby';
import FilterButtons from 'components/common/FilterButtons';
import Empty from 'components/common/Empty';
import useLocale from 'components/hooks/useLocale';
@ -130,7 +130,7 @@ export function RealtimeLog({ data, websiteDomain }) {
}
const { pageviews, visitors, events } = data;
const logs = [...pageviews, ...visitors, ...events].sort(firstBy('createdAt', -1));
const logs = [...pageviews, ...visitors, ...events].sort(thenby.firstBy('createdAt', -1));
if (filter !== TYPE_ALL) {
return logs.filter(({ __type }) => __type === filter);

View File

@ -1,15 +1,22 @@
import { useMemo, useState } from 'react';
import { Key, useMemo, useState } from 'react';
import { ButtonGroup, Button, Flexbox } from 'react-basics';
import firstBy from 'thenby';
import thenby from 'thenby';
import { percentFilter } from 'lib/filters';
import ListTable from 'components/metrics/ListTable';
import { FILTER_PAGES, FILTER_REFERRERS } from 'lib/constants';
import useMessages from 'components/hooks/useMessages';
import { RealtimeData } from 'lib/types';
export function RealtimeUrls({ websiteDomain, data = {} }) {
export function RealtimeUrls({
websiteDomain,
data,
}: {
websiteDomain: string;
data: RealtimeData;
}) {
const { formatMessage, labels } = useMessages();
const { pageviews } = data;
const [filter, setFilter] = useState(FILTER_REFERRERS);
const { pageviews } = data || {};
const [filter, setFilter] = useState<Key>(FILTER_REFERRERS);
const limit = 15;
const buttons = [
@ -48,7 +55,7 @@ export function RealtimeUrls({ websiteDomain, data = {} }) {
}
return arr;
}, [])
.sort(firstBy('y', -1))
.sort(thenby.firstBy('y', -1))
.slice(0, limit),
);
@ -64,7 +71,7 @@ export function RealtimeUrls({ websiteDomain, data = {} }) {
}
return arr;
}, [])
.sort(firstBy('y', -1))
.sort(thenby.firstBy('y', -1))
.slice(0, limit),
);

View File

@ -1,9 +1,10 @@
import { getMinimumUnit, parseDateRange } from 'lib/date';
import { setItem } from 'next-basics';
import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE } from 'lib/constants';
import useLocale from './useLocale';
import websiteStore, { setWebsiteDateRange } from 'store/websites';
import appStore, { setDateRange } from 'store/app';
import { DateRange } from 'lib/types';
import useLocale from './useLocale';
import useApi from './useApi';
export function useDateRange(websiteId?: string) {
@ -14,9 +15,9 @@ export function useDateRange(websiteId?: string) {
const globalConfig = appStore(state => state.dateRange);
const dateRange = parseDateRange(websiteConfig || globalConfig || defaultConfig, locale);
const saveDateRange = async value => {
const saveDateRange = async (value: DateRange | string) => {
if (websiteId) {
let dateRange = value;
let dateRange: DateRange | string = value;
if (typeof value === 'string') {
if (value === 'all') {
@ -37,14 +38,17 @@ export function useDateRange(websiteId?: string) {
}
}
setWebsiteDateRange(websiteId, dateRange);
setWebsiteDateRange(websiteId, dateRange as DateRange);
} else {
setItem(DATE_RANGE_CONFIG, value);
setDateRange(value);
}
};
return [dateRange, saveDateRange];
return [dateRange, saveDateRange] as [
{ startDate: Date; endDate: Date },
(value: string | DateRange) => void,
];
}
export default useDateRange;

View File

@ -3,6 +3,7 @@ import { format, startOfMinute, subMinutes, isBefore } from 'date-fns';
import PageviewsChart from './PageviewsChart';
import { getDateArray } from 'lib/date';
import { DEFAULT_ANIMATION_DURATION, REALTIME_RANGE } from 'lib/constants';
import { RealtimeData } from 'lib/types';
function mapData(data: any[]) {
let last = 0;
@ -24,11 +25,9 @@ function mapData(data: any[]) {
}
export interface RealtimeChartProps {
data: {
pageviews: any[];
visitors: any[];
};
data: RealtimeData;
unit: string;
className?: string;
}
export function RealtimeChart({ data, unit, ...props }: RealtimeChartProps) {

View File

@ -32,6 +32,7 @@ import {
subWeeks,
} from 'date-fns';
import { getDateLocale } from 'lib/lang';
import { DateRange } from 'lib/types';
export const TIME_UNIT = {
minute: 'minute',
@ -54,13 +55,13 @@ export function getTimezone() {
return moment.tz.guess();
}
export function getLocalTime(t) {
export function getLocalTime(t: string | number | Date) {
return addMinutes(new Date(t), new Date().getTimezoneOffset());
}
export function parseDateRange(value, locale = 'en-US') {
export function parseDateRange(value: string | object, locale = 'en-US'): DateRange {
if (typeof value === 'object') {
return value;
return value as DateRange;
}
if (value === 'all') {
@ -93,7 +94,7 @@ export function parseDateRange(value, locale = 'en-US') {
if (!match) return null;
const { num, unit } = match.groups;
const selectedUnit = { num, unit };
const selectedUnit = { num: +num, unit };
if (+num === 1) {
switch (unit) {
@ -172,7 +173,7 @@ export function parseDateRange(value, locale = 'en-US') {
switch (unit) {
case 'day':
return {
startDate: subDays(startOfDay(now), num - 1),
startDate: subDays(startOfDay(now), +num - 1),
endDate: endOfDay(now),
unit,
value,
@ -180,7 +181,7 @@ export function parseDateRange(value, locale = 'en-US') {
};
case 'hour':
return {
startDate: subHours(startOfHour(now), num - 1),
startDate: subHours(startOfHour(now), +num - 1),
endDate: endOfHour(now),
unit,
value,
@ -189,7 +190,10 @@ export function parseDateRange(value, locale = 'en-US') {
}
}
export function incrementDateRange(value, increment) {
export function incrementDateRange(
value: { startDate: any; endDate: any; selectedUnit: any },
increment: number,
) {
const { startDate, endDate, selectedUnit } = value;
const { num, unit } = selectedUnit;
@ -235,7 +239,7 @@ export function incrementDateRange(value, increment) {
}
}
export function getAllowedUnits(startDate, endDate) {
export function getAllowedUnits(startDate: Date, endDate: Date) {
const units = ['minute', 'hour', 'day', 'month', 'year'];
const minUnit = getMinimumUnit(startDate, endDate);
const index = units.indexOf(minUnit === 'year' ? 'month' : minUnit);
@ -243,7 +247,7 @@ export function getAllowedUnits(startDate, endDate) {
return index >= 0 ? units.splice(index) : [];
}
export function getMinimumUnit(startDate, endDate) {
export function getMinimumUnit(startDate: number | Date, endDate: number | Date) {
if (differenceInMinutes(endDate, startDate) <= 60) {
return 'minute';
} else if (differenceInHours(endDate, startDate) <= 48) {
@ -257,25 +261,25 @@ export function getMinimumUnit(startDate, endDate) {
return 'year';
}
export function getDateFromString(str) {
export function getDateFromString(str: string) {
const [ymd, hms] = str.split(' ');
const [year, month, day] = ymd.split('-');
if (hms) {
const [hour, min, sec] = hms.split(':');
return new Date(year, month - 1, day, hour, min, sec);
return new Date(+year, +month - 1, +day, +hour, +min, +sec);
}
return new Date(year, month - 1, day);
return new Date(+year, +month - 1, +day);
}
export function getDateArray(data, startDate, endDate, unit) {
export function getDateArray(data: any[], startDate: Date, endDate: Date, unit: string) {
const arr = [];
const [diff, add, normalize] = dateFuncs[unit];
const n = diff(endDate, startDate) + 1;
function findData(date) {
function findData(date: Date) {
const d = data.find(({ x }) => {
return normalize(getDateFromString(x)).getTime() === date.getTime();
});
@ -293,7 +297,7 @@ export function getDateArray(data, startDate, endDate, unit) {
return arr;
}
export function getDateLength(startDate, endDate, unit) {
export function getDateLength(startDate: Date, endDate: Date, unit: string | number) {
const [diff] = dateFuncs[unit];
return diff(endDate, startDate) + 1;
}
@ -310,7 +314,7 @@ export const CUSTOM_FORMATS = {
},
};
export function formatDate(date, str, locale = 'en-US') {
export function formatDate(date: string | number | Date, str: string, locale = 'en-US') {
return format(
typeof date === 'string' ? new Date(date) : date,
CUSTOM_FORMATS?.[locale]?.[str] || str,
@ -320,10 +324,10 @@ export function formatDate(date, str, locale = 'en-US') {
);
}
export function maxDate(...args) {
export function maxDate(...args: Date[]) {
return max(args.filter(n => isDate(n)));
}
export function minDate(...args) {
export function minDate(...args: any[]) {
return min(args.filter(n => isDate(n)));
}

View File

@ -180,7 +180,7 @@ export interface DateRange {
endDate: Date;
value: string;
unit?: TimeUnit;
selectedUnit?: TimeUnit;
selectedUnit?: { num: number; unit: TimeUnit };
}
export interface QueryFilters {
@ -207,3 +207,12 @@ export interface QueryOptions {
joinSession?: boolean;
columns?: { [key: string]: string };
}
export interface RealtimeData {
pageviews: any[];
sessions: any[];
events: any[];
timestamp: number;
countries?: any[];
visitors?: any[];
}