Moved events components to events page. Updated map data loading.

This commit is contained in:
Mike Cao 2024-08-08 12:00:38 -07:00
parent c6b8114945
commit f135e4ffbb
8 changed files with 52 additions and 35 deletions

View File

@ -7,6 +7,7 @@ import Link from 'next/link';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Button, Icon, Text } from 'react-basics'; import { Button, Icon, Text } from 'react-basics';
import Lightning from 'assets/lightning.svg';
import styles from './WebsiteHeader.module.css'; import styles from './WebsiteHeader.module.css';
export function WebsiteHeader({ export function WebsiteHeader({
@ -52,7 +53,7 @@ export function WebsiteHeader({
}, },
{ {
label: formatMessage(labels.events), label: formatMessage(labels.events),
icon: <Icons.Bolt />, icon: <Lightning />,
path: '/events', path: '/events',
}, },
]; ];

View File

@ -1,4 +1,3 @@
import { useState } from 'react';
import { Grid, GridRow } from 'components/layout/Grid'; import { Grid, GridRow } from 'components/layout/Grid';
import PagesTable from 'components/metrics/PagesTable'; import PagesTable from 'components/metrics/PagesTable';
import ReferrersTable from 'components/metrics/ReferrersTable'; import ReferrersTable from 'components/metrics/ReferrersTable';
@ -9,13 +8,15 @@ import WorldMap from 'components/metrics/WorldMap';
import CountriesTable from 'components/metrics/CountriesTable'; import CountriesTable from 'components/metrics/CountriesTable';
import EventsTable from 'components/metrics/EventsTable'; import EventsTable from 'components/metrics/EventsTable';
import EventsChart from 'components/metrics/EventsChart'; import EventsChart from 'components/metrics/EventsChart';
import { usePathname } from 'next/navigation';
export default function WebsiteTableView({ websiteId }: { websiteId: string }) { export default function WebsiteTableView({ websiteId }: { websiteId: string }) {
const [countryData, setCountryData] = useState(); const pathname = usePathname();
const tableProps = { const tableProps = {
websiteId, websiteId,
limit: 10, limit: 10,
}; };
const isSharePage = pathname.includes('/share/');
return ( return (
<Grid> <Grid>
@ -29,13 +30,15 @@ export default function WebsiteTableView({ websiteId }: { websiteId: string }) {
<DevicesTable {...tableProps} /> <DevicesTable {...tableProps} />
</GridRow> </GridRow>
<GridRow columns="two-one"> <GridRow columns="two-one">
<WorldMap data={countryData} /> <WorldMap websiteId={websiteId} />
<CountriesTable {...tableProps} onDataLoad={setCountryData} /> <CountriesTable {...tableProps} />
</GridRow>
<GridRow columns="one-two">
<EventsTable {...tableProps} />
<EventsChart websiteId={websiteId} />
</GridRow> </GridRow>
{isSharePage && (
<GridRow columns="one-two">
<EventsTable {...tableProps} />
<EventsChart websiteId={websiteId} />
</GridRow>
)}
</Grid> </Grid>
); );
} }

1
src/assets/lightning.svg Normal file
View File

@ -0,0 +1 @@
<svg xml:space="preserve" viewBox="0 0 682.667 682.667" xmlns="http://www.w3.org/2000/svg"><defs><clipPath clipPathUnits="userSpaceOnUse" id="a"><path d="M0 512h512V0H0Z"/></clipPath></defs><g clip-path="url(#a)" transform="matrix(1.33333 0 0 -1.33333 0 682.667)"><path d="M0 0h137.962L69.319-155.807h140.419L.242-482l55.349 222.794h-155.853z" style="fill:none;stroke:currentColor;stroke-width:30;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1" transform="translate(201.262 496.994)"/></g></svg>

After

Width:  |  Height:  |  Size: 551 B

View File

@ -4,7 +4,7 @@ import { useFilterParams } from '../useFilterParams';
export function useWebsiteMetrics( export function useWebsiteMetrics(
websiteId: string, websiteId: string,
queryParams: { type: string; limit: number; search: string; startAt?: number; endAt?: number }, queryParams: { type: string; limit?: number; search?: string; startAt?: number; endAt?: number },
options?: Omit<UseQueryOptions & { onDataLoad?: (data: any) => void }, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions & { onDataLoad?: (data: any) => void }, 'queryKey' | 'queryFn'>,
) { ) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();

View File

@ -4,21 +4,12 @@ import { useLocale, useMessages, useFormat } from 'components/hooks';
import MetricsTable, { MetricsTableProps } from './MetricsTable'; import MetricsTable, { MetricsTableProps } from './MetricsTable';
import TypeIcon from 'components/common/TypeIcon'; import TypeIcon from 'components/common/TypeIcon';
export function CountriesTable({ export function CountriesTable({ ...props }: MetricsTableProps) {
onDataLoad,
...props
}: {
onDataLoad: (data: any) => void;
} & MetricsTableProps) {
const { locale } = useLocale(); const { locale } = useLocale();
const { countryNames } = useCountryNames(locale); const { countryNames } = useCountryNames(locale);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { formatCountry } = useFormat(); const { formatCountry } = useFormat();
const handleDataLoad = (data: any) => {
onDataLoad?.(data);
};
const renderLink = ({ x: code }) => { const renderLink = ({ x: code }) => {
return ( return (
<FilterLink <FilterLink
@ -39,7 +30,6 @@ export function CountriesTable({
type="country" type="country"
metric={formatMessage(labels.visitors)} metric={formatMessage(labels.visitors)}
renderLabel={renderLink} renderLabel={renderLink}
onDataLoad={handleDataLoad}
/> />
); );
} }

View File

@ -4,7 +4,7 @@ import classNames from 'classnames';
import { colord } from 'colord'; import { colord } from 'colord';
import HoverTooltip from 'components/common/HoverTooltip'; import HoverTooltip from 'components/common/HoverTooltip';
import { ISO_COUNTRIES, MAP_FILE } from 'lib/constants'; import { ISO_COUNTRIES, MAP_FILE } from 'lib/constants';
import { useTheme } from 'components/hooks'; import { useDateRange, useTheme, useWebsiteMetrics } from 'components/hooks';
import { useCountryNames } from 'components/hooks'; import { useCountryNames } from 'components/hooks';
import { useLocale } from 'components/hooks'; import { useLocale } from 'components/hooks';
import { useMessages } from 'components/hooks'; import { useMessages } from 'components/hooks';
@ -12,16 +12,35 @@ import { formatLongNumber } from 'lib/format';
import { percentFilter } from 'lib/filters'; import { percentFilter } from 'lib/filters';
import styles from './WorldMap.module.css'; import styles from './WorldMap.module.css';
export function WorldMap({ data = [], className }: { data?: any[]; className?: string }) { export function WorldMap({
websiteId,
data,
className,
}: {
websiteId?: string;
data?: any[];
className?: string;
}) {
const [tooltip, setTooltipPopup] = useState(); const [tooltip, setTooltipPopup] = useState();
const { theme, colors } = useTheme(); const { theme, colors } = useTheme();
const { locale } = useLocale(); const { locale } = useLocale();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { countryNames } = useCountryNames(locale); const { countryNames } = useCountryNames(locale);
const visitorsLabel = formatMessage(labels.visitors).toLocaleLowerCase(locale); const visitorsLabel = formatMessage(labels.visitors).toLocaleLowerCase(locale);
const metrics = useMemo(() => (data ? percentFilter(data) : []), [data]); const {
dateRange: { startDate, endDate },
} = useDateRange(websiteId);
const { data: mapData } = useWebsiteMetrics(websiteId, {
type: 'country',
startAt: +startDate,
endAt: +endDate,
});
const metrics = useMemo(
() => (data || mapData ? percentFilter((data || mapData) as any[]) : []),
[data, mapData],
);
function getFillColor(code: string) { const getFillColor = (code: string) => {
if (code === 'AQ') return; if (code === 'AQ') return;
const country = metrics?.find(({ x }) => x === code); const country = metrics?.find(({ x }) => x === code);
@ -32,19 +51,19 @@ export function WorldMap({ data = [], className }: { data?: any[]; className?: s
return colord(colors.map.baseColor) return colord(colors.map.baseColor)
[theme === 'light' ? 'lighten' : 'darken'](0.4 * (1.0 - country.z / 100)) [theme === 'light' ? 'lighten' : 'darken'](0.4 * (1.0 - country.z / 100))
.toHex(); .toHex();
} };
function getOpacity(code) { const getOpacity = (code: string) => {
return code === 'AQ' ? 0 : 1; return code === 'AQ' ? 0 : 1;
} };
function handleHover(code) { const handleHover = (code: string) => {
if (code === 'AQ') return; if (code === 'AQ') return;
const country = metrics?.find(({ x }) => x === code); const country = metrics?.find(({ x }) => x === code);
setTooltipPopup( setTooltipPopup(
`${countryNames[code]}: ${formatLongNumber(country?.y || 0)} ${visitorsLabel}` as any, `${countryNames[code]}: ${formatLongNumber(country?.y || 0)} ${visitorsLabel}` as any,
); );
} };
return ( return (
<div <div

View File

@ -26,14 +26,17 @@ export default async (
await useAuth(req, res); await useAuth(req, res);
await useValidate(schema, req, res); await useValidate(schema, req, res);
const { websiteId } = req.query; const { websiteId, startAt, endAt } = req.query;
if (req.method === 'GET') { if (req.method === 'GET') {
if (!(await canViewWebsite(req.auth, websiteId))) { if (!(await canViewWebsite(req.auth, websiteId))) {
return unauthorized(res); return unauthorized(res);
} }
const data = await getWebsiteEvents(websiteId, {}, req.query); const startDate = new Date(+startAt);
const endDate = new Date(+endAt);
const data = await getWebsiteEvents(websiteId, { startDate, endDate }, req.query);
return ok(res, data); return ok(res, data);
} }

View File

@ -30,14 +30,14 @@ export default async (
const { websiteId, startAt, endAt } = req.query; const { websiteId, startAt, endAt } = req.query;
const startDate = new Date(+startAt);
const endDate = new Date(+endAt);
if (req.method === 'GET') { if (req.method === 'GET') {
if (!(await canViewWebsite(req.auth, websiteId))) { if (!(await canViewWebsite(req.auth, websiteId))) {
return unauthorized(res); return unauthorized(res);
} }
const startDate = new Date(+startAt);
const endDate = new Date(+endAt);
const data = await getWebsiteSessions(websiteId, { startDate, endDate }, req.query); const data = await getWebsiteSessions(websiteId, { startDate, endDate }, req.query);
return ok(res, data); return ok(res, data);