Updated hooks. Changed url, host to path, hostname.

This commit is contained in:
Mike Cao 2025-06-20 22:35:02 -07:00
parent 25a9c011b3
commit 543674c7f2
146 changed files with 23348 additions and 2533 deletions

View file

@ -13,38 +13,38 @@ import { useMessages, useNavigation, useGlobalState } from '@/components/hooks';
export function SideNav(props: any) {
const { formatMessage, labels } = useMessages();
const { renderTeamUrl, pathname } = useNavigation();
const { renderUrl, pathname } = useNavigation();
const [isCollapsed] = useGlobalState('sidenav-collapsed');
const links = [
{
label: formatMessage(labels.websites),
href: renderTeamUrl('/websites'),
href: renderUrl('/websites'),
icon: <Globe />,
},
{
label: formatMessage(labels.boards),
href: renderTeamUrl('/boards'),
href: renderUrl('/boards'),
icon: <LayoutDashboard />,
},
{
label: formatMessage(labels.links),
href: renderTeamUrl('/links'),
href: renderUrl('/links'),
icon: <LinkIcon />,
},
{
label: formatMessage(labels.pixels),
href: renderTeamUrl('/pixels'),
href: renderUrl('/pixels'),
icon: <Grid2X2 />,
},
{
label: formatMessage(labels.settings),
href: renderTeamUrl('/settings'),
href: renderUrl('/settings'),
icon: <Settings />,
},
{
label: formatMessage(labels.admin),
href: renderTeamUrl('/admin'),
href: renderUrl('/admin'),
icon: <LockKeyhole />,
},
].filter(n => n);

View file

@ -22,7 +22,7 @@ export function WebsitesTable({
children,
}: WebsitesTableProps) {
const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useNavigation();
const { renderUrl } = useNavigation();
if (!data?.length) {
return children;
@ -31,7 +31,7 @@ export function WebsitesTable({
return (
<DataTable data={data}>
<DataColumn id="name" label={formatMessage(labels.name)}>
{(row: any) => <Link href={renderTeamUrl(`/websites/${row.id}`)}>{row.name}</Link>}
{(row: any) => <Link href={renderUrl(`/websites/${row.id}`)}>{row.name}</Link>}
</DataColumn>
<DataColumn id="domain" label={formatMessage(labels.domain)} />
{showActions && (
@ -42,7 +42,7 @@ export function WebsitesTable({
return (
<MenuButton>
{allowEdit && (
<MenuItem href={renderTeamUrl(`/websites/${websiteId}`)}>
<MenuItem href={renderUrl(`/websites/${websiteId}`)}>
<Row alignItems="center" gap>
<Icon data-test="link-button-view">
<Eye />
@ -52,7 +52,7 @@ export function WebsitesTable({
</MenuItem>
)}
{allowView && (
<MenuItem href={renderTeamUrl(`/settings/websites/${websiteId}`)}>
<MenuItem href={renderUrl(`/settings/websites/${websiteId}`)}>
<Row alignItems="center" gap>
<Icon data-test="link-button-edit">
<SquarePen />

View file

@ -17,7 +17,7 @@ export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?:
const { formatMessage, labels, messages } = useMessages();
const { user } = useLoginQuery();
const { touch } = useModified();
const { teamId, renderTeamUrl } = useNavigation();
const { teamId, renderUrl } = useNavigation();
const router = useRouter();
const { result } = useTeamsQuery(user.id);
const canTransferWebsite =
@ -38,7 +38,7 @@ export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?:
const handleSave = () => {
touch('websites');
onSave?.();
router.push(renderTeamUrl(`/settings/websites`));
router.push(renderUrl(`/settings/websites`));
};
const handleReset = async () => {

View file

@ -7,10 +7,10 @@ import { Panel } from '@/components/common/Panel';
export function WebsiteChart({
websiteId,
compareMode = false,
compareMode,
}: {
websiteId: string;
compareMode?: boolean;
compareMode?: string;
}) {
const { dateRange, dateCompare } = useDateRange(websiteId);
const { startDate, endDate, unit, value } = dateRange;

View file

@ -46,81 +46,81 @@ export function WebsiteCompareTables({ websiteId }: { websiteId: string }) {
const dateCompare = useWebsites(state => state[websiteId]?.dateCompare);
const { formatMessage, labels } = useMessages();
const {
renderUrl,
updateParams,
query: { view },
} = useNavigation();
const Component: typeof MetricsTable = views[view || 'url'] || (() => null);
const Component: typeof MetricsTable = views[view || 'path'] || (() => null);
const items = [
{
id: 'url',
id: 'path',
label: formatMessage(labels.pages),
url: renderUrl({ view: 'url' }),
url: updateParams({ view: 'path' }),
},
{
id: 'referrer',
label: formatMessage(labels.referrers),
url: renderUrl({ view: 'referrer' }),
url: updateParams({ view: 'referrer' }),
},
{
id: 'browser',
label: formatMessage(labels.browsers),
url: renderUrl({ view: 'browser' }),
url: updateParams({ view: 'browser' }),
},
{
id: 'os',
label: formatMessage(labels.os),
url: renderUrl({ view: 'os' }),
url: updateParams({ view: 'os' }),
},
{
id: 'device',
label: formatMessage(labels.devices),
url: renderUrl({ view: 'device' }),
url: updateParams({ view: 'device' }),
},
{
id: 'country',
label: formatMessage(labels.countries),
url: renderUrl({ view: 'country' }),
url: updateParams({ view: 'country' }),
},
{
id: 'region',
label: formatMessage(labels.regions),
url: renderUrl({ view: 'region' }),
url: updateParams({ view: 'region' }),
},
{
id: 'city',
label: formatMessage(labels.cities),
url: renderUrl({ view: 'city' }),
url: updateParams({ view: 'city' }),
},
{
id: 'language',
label: formatMessage(labels.languages),
url: renderUrl({ view: 'language' }),
url: updateParams({ view: 'language' }),
},
{
id: 'screen',
label: formatMessage(labels.screens),
url: renderUrl({ view: 'screen' }),
url: updateParams({ view: 'screen' }),
},
{
id: 'event',
label: formatMessage(labels.events),
url: renderUrl({ view: 'event' }),
url: updateParams({ view: 'event' }),
},
{
id: 'query',
label: formatMessage(labels.queryParameters),
url: renderUrl({ view: 'query' }),
url: updateParams({ view: 'query' }),
},
{
id: 'host',
label: formatMessage(labels.hosts),
url: renderUrl({ view: 'host' }),
id: 'hostname',
label: formatMessage(labels.hostname),
url: updateParams({ view: 'hostname' }),
},
{
id: 'tag',
label: formatMessage(labels.tags),
url: renderUrl({ view: 'tag' }),
url: updateParams({ view: 'tag' }),
},
];

View file

@ -7,7 +7,7 @@ import { CitiesTable } from '@/components/metrics/CitiesTable';
import { CountriesTable } from '@/components/metrics/CountriesTable';
import { DevicesTable } from '@/components/metrics/DevicesTable';
import { EventsTable } from '@/components/metrics/EventsTable';
import { HostsTable } from '@/components/metrics/HostsTable';
import { HostnamesTable } from '@/components/metrics/HostnamesTable';
import { LanguagesTable } from '@/components/metrics/LanguagesTable';
import { OSTable } from '@/components/metrics/OSTable';
import { PagesTable } from '@/components/metrics/PagesTable';
@ -21,13 +21,13 @@ import { Panel } from '@/components/common/Panel';
import { Arrow } from '@/components/icons';
const views = {
url: PagesTable,
path: PagesTable,
entry: PagesTable,
exit: PagesTable,
title: PagesTable,
referrer: ReferrersTable,
grouped: ReferrersTable,
host: HostsTable,
hostname: HostnamesTable,
browser: BrowsersTable,
os: OSTable,
device: DevicesTable,
@ -51,85 +51,85 @@ export function WebsiteExpandedView({
}) {
const { formatMessage, labels } = useMessages();
const {
renderUrl,
updateParams,
query: { view },
} = useNavigation();
const items = [
{
id: 'url',
id: 'path',
label: formatMessage(labels.pages),
url: renderUrl({ view: 'url' }),
url: updateParams({ view: 'path' }),
},
{
id: 'referrer',
label: formatMessage(labels.referrers),
url: renderUrl({ view: 'referrer' }),
url: updateParams({ view: 'referrer' }),
},
{
id: 'channel',
label: formatMessage(labels.channels),
url: renderUrl({ view: 'channel' }),
url: updateParams({ view: 'channel' }),
},
{
id: 'browser',
label: formatMessage(labels.browsers),
url: renderUrl({ view: 'browser' }),
url: updateParams({ view: 'browser' }),
},
{
id: 'os',
label: formatMessage(labels.os),
url: renderUrl({ view: 'os' }),
url: updateParams({ view: 'os' }),
},
{
id: 'device',
label: formatMessage(labels.devices),
url: renderUrl({ view: 'device' }),
url: updateParams({ view: 'device' }),
},
{
id: 'country',
label: formatMessage(labels.countries),
url: renderUrl({ view: 'country' }),
url: updateParams({ view: 'country' }),
},
{
id: 'region',
label: formatMessage(labels.regions),
url: renderUrl({ view: 'region' }),
url: updateParams({ view: 'region' }),
},
{
id: 'city',
label: formatMessage(labels.cities),
url: renderUrl({ view: 'city' }),
url: updateParams({ view: 'city' }),
},
{
id: 'language',
label: formatMessage(labels.languages),
url: renderUrl({ view: 'language' }),
url: updateParams({ view: 'language' }),
},
{
id: 'screen',
label: formatMessage(labels.screens),
url: renderUrl({ view: 'screen' }),
url: updateParams({ view: 'screen' }),
},
{
id: 'event',
label: formatMessage(labels.events),
url: renderUrl({ view: 'event' }),
url: updateParams({ view: 'event' }),
},
{
id: 'query',
label: formatMessage(labels.queryParameters),
url: renderUrl({ view: 'query' }),
url: updateParams({ view: 'query' }),
},
{
id: 'host',
label: formatMessage(labels.hosts),
url: renderUrl({ view: 'host' }),
id: 'hostname',
label: formatMessage(labels.hostname),
url: updateParams({ view: 'hostname' }),
},
{
id: 'tag',
label: formatMessage(labels.tags),
url: renderUrl({ view: 'tag' }),
url: updateParams({ view: 'tag' }),
},
];
@ -139,7 +139,7 @@ export function WebsiteExpandedView({
<Panel>
<Grid columns="auto 1fr" gap="6">
<Column gap="6" width="200px" border="right" paddingRight="3">
<LinkButton href={renderUrl({ view: undefined })} variant="quiet" scroll={false}>
<LinkButton href={updateParams({ view: undefined })} variant="quiet" scroll={false}>
<Icon rotate={180}>
<Arrow />
</Icon>

View file

@ -13,7 +13,7 @@ export function WebsiteFilterButton({
showText?: boolean;
}) {
const { formatMessage, labels } = useMessages();
const { renderUrl, router } = useNavigation();
const { updateParams, router } = useNavigation();
const { filters } = useFilters();
const handleChange = (filters: any[]) => {
@ -25,7 +25,7 @@ export function WebsiteFilterButton({
return obj;
}, {});
const url = renderUrl(params);
const url = updateParams(params);
router.push(url);
};

View file

@ -15,7 +15,7 @@ import { InputItem } from '@/lib/types';
export function WebsiteMenu({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
const { router, renderUrl, renderTeamUrl } = useNavigation();
const { router, updateParams, renderUrl } = useNavigation();
const menuItems: InputItem[] = [
{ id: 'share', label: formatMessage(labels.share), icon: <Share /> },
@ -24,9 +24,9 @@ export function WebsiteMenu({ websiteId }: { websiteId: string }) {
const handleAction = (id: any) => {
if (id === 'compare') {
router.push(renderUrl({ compare: 'prev' }));
router.push(updateParams({ compare: 'prev' }));
} else if (id === 'edit') {
router.push(renderTeamUrl(`/settings/websites/${websiteId}`));
router.push(renderUrl(`/settings/websites/${websiteId}`));
}
};

View file

@ -18,7 +18,7 @@ import Link from 'next/link';
export function WebsiteNav({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
const { pathname, renderTeamUrl } = useNavigation();
const { pathname, renderUrl } = useNavigation();
const links = [
{
@ -103,7 +103,7 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) {
const isSelected = selected === id;
return (
<Link key={id} href={renderTeamUrl(`/websites/${websiteId}${path}`)}>
<Link key={id} href={renderUrl(`/websites/${websiteId}${path}`)}>
<NavMenuItem isSelected={isSelected}>
<Row alignItems="center" gap>
<Icon>{icon}</Icon>

View file

@ -5,7 +5,7 @@ import { Clock, Eye, Lightning, User, ChartPie } from '@/components/icons';
export function WebsiteTabs() {
const website = useWebsite();
const { pathname, renderTeamUrl } = useNavigation();
const { pathname, renderUrl } = useNavigation();
const { formatMessage, labels } = useMessages();
const links = [
@ -49,7 +49,7 @@ export function WebsiteTabs() {
<TabList>
{links.map(({ id, label, icon, path }) => {
return (
<Tab key={id} id={id} href={renderTeamUrl(`/websites/${website.id}${path}`)}>
<Tab key={id} id={id} href={renderUrl(`/websites/${website.id}${path}`)}>
<Row alignItems="center" gap>
<Icon>{icon}</Icon>
<Text>{label}</Text>

View file

@ -8,7 +8,7 @@ import { Bolt, Eye } from '@/components/icons';
export function EventsTable({ data = [] }) {
const { formatTimezoneDate } = useTimezone();
const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useNavigation();
const { renderUrl } = useNavigation();
if (data.length === 0) {
return <Empty />;
@ -18,7 +18,7 @@ export function EventsTable({ data = [] }) {
<DataTable data={data}>
<DataColumn id="session" label={formatMessage(labels.session)} width="100px">
{(row: any) => (
<Link href={renderTeamUrl(`/websites/${row.websiteId}/sessions/${row.sessionId}`)}>
<Link href={renderUrl(`/websites/${row.websiteId}/sessions/${row.sessionId}`)}>
<Avatar seed={row.sessionId} size={64} />
</Link>
)}

View file

@ -3,12 +3,14 @@ import { Row } from '@umami/react-zen';
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';
import { RealtimeData } from '@/lib/types';
import { WebsiteContext } from '../WebsiteProvider';
import { FilterButtons } from '@/components/common/FilterButtons';
const FILTER_REFERRERS = 'filter-referrers';
const FILTER_PAGES = 'filter-pages';
export function RealtimeUrls({ data }: { data: RealtimeData }) {
const website = useContext(WebsiteContext);
const { formatMessage, labels } = useMessages();

View file

@ -5,7 +5,7 @@ import Link from 'next/link';
export function ReportsNav({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
const { pathname, renderTeamUrl } = useNavigation();
const { pathname, renderUrl } = useNavigation();
const links = [
{
@ -66,7 +66,7 @@ export function ReportsNav({ websiteId }: { websiteId: string }) {
const isSelected = selected === id;
return (
<Link key={id} href={renderTeamUrl(`/websites/${websiteId}/reports${path}`)}>
<Link key={id} href={renderUrl(`/websites/${websiteId}/reports${path}`)}>
<NavMenuItem isSelected={isSelected}>
<Row alignItems="center" gap>
<Icon>{icon}</Icon>

View file

@ -22,7 +22,7 @@ export function BreakdownPage({ websiteId }: { websiteId: string }) {
const {
dateRange: { startDate, endDate },
} = useDateRange(websiteId);
const [fields, setFields] = useState(['url']);
const [fields, setFields] = useState(['path']);
return (
<Column gap>

View file

@ -114,40 +114,42 @@ export function Revenue({ websiteId, startDate, endDate }: RevenueProps) {
<CurrencySelect value={currency} onChange={setCurrency} />
</Grid>
<LoadingPanel data={data} isLoading={isLoading} error={error}>
<Column gap>
<MetricsBar>
{metrics?.map(({ label, value, formatValue }) => {
return (
<MetricCard key={label} value={value} label={label} formatValue={formatValue} />
);
})}
</MetricsBar>
<Panel>
<BarChart
chartData={chartData}
minDate={startDate}
maxDate={endDate}
unit={unit}
stacked={true}
currency={currency}
renderXLabel={renderDateLabels(unit, locale)}
height="400px"
/>
</Panel>
<Panel>
<ListTable
title={formatMessage(labels.country)}
metric={formatMessage(labels.revenue)}
data={data?.country.map(({ name, value }: { name: string; value: number }) => ({
x: name,
y: value,
z: (value / data?.total.sum) * 100,
}))}
currency={currency}
renderLabel={renderCountryName}
/>
</Panel>
</Column>
{data && (
<Column gap>
<MetricsBar>
{metrics?.map(({ label, value, formatValue }) => {
return (
<MetricCard key={label} value={value} label={label} formatValue={formatValue} />
);
})}
</MetricsBar>
<Panel>
<BarChart
chartData={chartData}
minDate={startDate}
maxDate={endDate}
unit={unit}
stacked={true}
currency={currency}
renderXLabel={renderDateLabels(unit, locale)}
height="400px"
/>
</Panel>
<Panel>
<ListTable
title={formatMessage(labels.country)}
metric={formatMessage(labels.revenue)}
data={data?.country.map(({ name, value }: { name: string; value: number }) => ({
x: name,
y: value,
z: (value / data?.total.sum) * 100,
}))}
currency={currency}
renderLabel={renderCountryName}
/>
</Panel>
</Column>
)}
</LoadingPanel>
</Column>
);

View file

@ -24,7 +24,6 @@ export async function GET(
const { websiteId } = await params;
const { type, search } = query;
const { startDate, endDate } = await getRequestDateRange(query);
if (!(await canViewWebsite(auth, websiteId))) {
return unauthorized();
@ -34,6 +33,8 @@ export async function GET(
return badRequest('Invalid type.');
}
const { startDate, endDate } = await getRequestDateRange(query);
const values = await getValues(websiteId, FILTER_COLUMNS[type], startDate, endDate, search);
return json(values.filter(n => n).sort());