mirror of
https://github.com/umami-software/umami.git
synced 2026-02-23 22:15:35 +01:00
New website nav.
This commit is contained in:
parent
5e6799a715
commit
a534c51b5e
38 changed files with 190 additions and 159 deletions
|
|
@ -0,0 +1,142 @@
|
|||
import { Grid, Column } from '@umami/react-zen';
|
||||
import { useMessages, useResultQuery } from '@/components/hooks';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { ListTable } from '@/components/metrics/ListTable';
|
||||
import { MetricCard } from '@/components/metrics/MetricCard';
|
||||
import { MetricsBar } from '@/components/metrics/MetricsBar';
|
||||
import { SectionHeader } from '@/components/common/SectionHeader';
|
||||
import { formatLongNumber } from '@/lib/format';
|
||||
import { percentFilter } from '@/lib/filters';
|
||||
|
||||
export interface AttributionProps {
|
||||
websiteId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
model: string;
|
||||
type: string;
|
||||
step: string;
|
||||
currency?: string;
|
||||
}
|
||||
|
||||
export function Attribution({
|
||||
websiteId,
|
||||
startDate,
|
||||
endDate,
|
||||
model,
|
||||
type,
|
||||
step,
|
||||
currency,
|
||||
}: AttributionProps) {
|
||||
const { data, error, isLoading } = useResultQuery<any>('attribution', {
|
||||
websiteId,
|
||||
startDate,
|
||||
endDate,
|
||||
model,
|
||||
type,
|
||||
step,
|
||||
});
|
||||
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const { pageviews, visitors, visits } = data?.total || {};
|
||||
|
||||
const metrics = data
|
||||
? [
|
||||
{
|
||||
value: visitors,
|
||||
label: formatMessage(labels.visitors),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
value: visits,
|
||||
label: formatMessage(labels.visits),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
value: pageviews,
|
||||
label: formatMessage(labels.views),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
function UTMTable({ data = [], title }: { data: any; title: string }) {
|
||||
return (
|
||||
<ListTable
|
||||
title={title}
|
||||
metric={formatMessage(currency ? labels.revenue : labels.visitors)}
|
||||
currency={currency}
|
||||
data={percentFilter(
|
||||
data.map(({ name, value }) => ({
|
||||
x: name,
|
||||
y: Number(value),
|
||||
})),
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LoadingPanel data={data} isLoading={isLoading} error={error}>
|
||||
{data && (
|
||||
<Column gap>
|
||||
<MetricsBar>
|
||||
{metrics?.map(({ label, value, formatValue }) => {
|
||||
return (
|
||||
<MetricCard key={label} value={value} label={label} formatValue={formatValue} />
|
||||
);
|
||||
})}
|
||||
</MetricsBar>
|
||||
<SectionHeader title={formatMessage(labels.sources)} />
|
||||
<Grid columns="1fr 1fr" gap>
|
||||
<Panel>
|
||||
<ListTable
|
||||
title={formatMessage(labels.referrer)}
|
||||
metric={formatMessage(currency ? labels.revenue : labels.visitors)}
|
||||
currency={currency}
|
||||
data={percentFilter(
|
||||
data?.['referrer']?.map(({ name, value }) => ({
|
||||
x: name,
|
||||
y: Number(value),
|
||||
})),
|
||||
)}
|
||||
/>
|
||||
</Panel>
|
||||
<Panel>
|
||||
<ListTable
|
||||
title={formatMessage(labels.paidAds)}
|
||||
metric={formatMessage(currency ? labels.revenue : labels.visitors)}
|
||||
currency={currency}
|
||||
data={percentFilter(
|
||||
data?.['paidAds']?.map(({ name, value }) => ({
|
||||
x: name,
|
||||
y: Number(value),
|
||||
})),
|
||||
)}
|
||||
/>
|
||||
</Panel>
|
||||
</Grid>
|
||||
<SectionHeader title="UTM" />
|
||||
<Grid columns="1fr 1fr" gap>
|
||||
<Panel>
|
||||
<UTMTable data={data?.['utm_source']} title={formatMessage(labels.sources)} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<UTMTable data={data?.['utm_medium']} title={formatMessage(labels.medium)} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<UTMTable data={data?.['utm_cmapaign']} title={formatMessage(labels.campaigns)} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<UTMTable data={data?.['utm_content']} title={formatMessage(labels.content)} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<UTMTable data={data?.['utm_term']} title={formatMessage(labels.terms)} />
|
||||
</Panel>
|
||||
</Grid>
|
||||
</Column>
|
||||
)}
|
||||
</LoadingPanel>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
'use client';
|
||||
import { useState } from 'react';
|
||||
import { Column, Grid, Select, ListItem, SearchField } from '@umami/react-zen';
|
||||
import { Attribution } from './Attribution';
|
||||
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
|
||||
import { useDateRange, useMessages } from '@/components/hooks';
|
||||
|
||||
export function AttributionPage({ websiteId }: { websiteId: string }) {
|
||||
const [model, setModel] = useState('first-click');
|
||||
const [type, setType] = useState('page');
|
||||
const [step, setStep] = useState('/');
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const {
|
||||
dateRange: { startDate, endDate },
|
||||
} = useDateRange(websiteId);
|
||||
|
||||
return (
|
||||
<Column gap="6">
|
||||
<WebsiteControls websiteId={websiteId} />
|
||||
<Grid columns="1fr 1fr 1fr" gap>
|
||||
<Column>
|
||||
<Select
|
||||
label={formatMessage(labels.model)}
|
||||
value={model}
|
||||
defaultValue={model}
|
||||
onChange={setModel}
|
||||
>
|
||||
<ListItem id="first-click">{formatMessage(labels.firstClick)}</ListItem>
|
||||
<ListItem id="last-click">{formatMessage(labels.lastClick)}</ListItem>
|
||||
</Select>
|
||||
</Column>
|
||||
<Column>
|
||||
<Select
|
||||
label={formatMessage(labels.type)}
|
||||
value={type}
|
||||
defaultValue={type}
|
||||
onChange={setType}
|
||||
>
|
||||
<ListItem id="page">{formatMessage(labels.page)}</ListItem>
|
||||
<ListItem id="event">{formatMessage(labels.event)}</ListItem>
|
||||
</Select>
|
||||
</Column>
|
||||
<Column>
|
||||
<SearchField
|
||||
label={formatMessage(labels.conversionStep)}
|
||||
value={step}
|
||||
defaultValue={step}
|
||||
onSearch={setStep}
|
||||
delay={1000}
|
||||
/>
|
||||
</Column>
|
||||
</Grid>
|
||||
<Attribution
|
||||
websiteId={websiteId}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
model={model}
|
||||
type={type}
|
||||
step={step}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { Metadata } from 'next';
|
||||
import { AttributionPage } from './AttributionPage';
|
||||
|
||||
export default async function ({ params }: { params: Promise<{ websiteId: string }> }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <AttributionPage websiteId={websiteId} />;
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Attribution',
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue