mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-06 01:15:42 +01:00
Moved events components to events page. Updated map data loading.
This commit is contained in:
parent
c6b8114945
commit
f135e4ffbb
@ -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',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -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>
|
||||||
|
{isSharePage && (
|
||||||
<GridRow columns="one-two">
|
<GridRow columns="one-two">
|
||||||
<EventsTable {...tableProps} />
|
<EventsTable {...tableProps} />
|
||||||
<EventsChart websiteId={websiteId} />
|
<EventsChart websiteId={websiteId} />
|
||||||
</GridRow>
|
</GridRow>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
1
src/assets/lightning.svg
Normal file
1
src/assets/lightning.svg
Normal 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 |
@ -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();
|
||||||
|
@ -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}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user