Made filters work for all reports.

This commit is contained in:
Mike Cao 2025-06-29 23:57:11 -07:00
parent ea83afbc13
commit 8b64029409
46 changed files with 328 additions and 275 deletions

View file

@ -24,7 +24,7 @@ export function WebsiteControls({
{allowDateFilter && <WebsiteDateFilter websiteId={websiteId} allowCompare={allowCompare} />}
{allowMonthFilter && <WebsiteMonthSelect websiteId={websiteId} />}
</Row>
<FilterBar />
{allowFilter && <FilterBar />}
</Column>
);
}

View file

@ -70,7 +70,7 @@ export function ReportsNav({ websiteId }: { websiteId: string }) {
key={id}
href={renderUrl(
`/websites/${websiteId}/reports${path}`,
path === '/retention' ? false : null,
path === '/retention' ? { date: undefined } : null,
)}
>
<NavMenuItem isSelected={isSelected}>

View file

@ -48,8 +48,8 @@ export function Attribution({
const metrics = data
? [
{
value: pageviews,
label: formatMessage(labels.views),
value: visitors,
label: formatMessage(labels.visitors),
formatValue: formatLongNumber,
},
{
@ -58,8 +58,8 @@ export function Attribution({
formatValue: formatLongNumber,
},
{
value: visitors,
label: formatMessage(labels.visitors),
value: pageviews,
label: formatMessage(labels.views),
formatValue: formatLongNumber,
},
]
@ -83,60 +83,64 @@ export function Attribution({
return (
<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>
<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>
{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>
);
}

View file

@ -11,7 +11,7 @@ export function RevenuePage({ websiteId }: { websiteId: string }) {
return (
<Column gap>
<WebsiteControls websiteId={websiteId} allowCompare={false} />
<WebsiteControls websiteId={websiteId} allowFilter={false} />
<Revenue websiteId={websiteId} startDate={startDate} endDate={endDate} />
</Column>
);

View file

@ -26,47 +26,49 @@ export function UTM({ websiteId, startDate, endDate }: UTMProps) {
return (
<LoadingPanel data={data} isLoading={isLoading} error={error}>
<Column gap>
{UTM_PARAMS.map(param => {
const items = toArray(data?.[param]);
const chartData = {
labels: items.map(({ name }) => name),
datasets: [
{
data: items.map(({ value }) => value),
backgroundColor: CHART_COLORS,
borderWidth: 0,
},
],
};
const total = items.reduce((sum, { value }) => {
return +sum + +value;
}, 0);
{data && (
<Column gap>
{UTM_PARAMS.map(param => {
const items = toArray(data?.[param]);
const chartData = {
labels: items.map(({ name }) => name),
datasets: [
{
data: items.map(({ value }) => value),
backgroundColor: CHART_COLORS,
borderWidth: 0,
},
],
};
const total = items.reduce((sum, { value }) => {
return +sum + +value;
}, 0);
return (
<Panel key={param}>
<Grid columns="1fr 1fr">
<Column>
<Heading>
<Text transform="capitalize">{param.replace(/^utm_/, '')}</Text>
</Heading>
<ListTable
metric={formatMessage(labels.views)}
data={items.map(({ name, value }) => ({
x: name,
y: value,
z: (value / total) * 100,
}))}
/>
</Column>
<Column>
<PieChart type="doughnut" chartData={chartData} />
</Column>
</Grid>
</Panel>
);
})}
</Column>
return (
<Panel key={param}>
<Grid columns="1fr 1fr">
<Column>
<Heading>
<Text transform="capitalize">{param.replace(/^utm_/, '')}</Text>
</Heading>
<ListTable
metric={formatMessage(labels.views)}
data={items.map(({ name, value }) => ({
x: name,
y: value,
z: (value / total) * 100,
}))}
/>
</Column>
<Column>
<PieChart type="doughnut" chartData={chartData} />
</Column>
</Grid>
</Panel>
);
})}
</Column>
)}
</LoadingPanel>
);
}

View file

@ -15,6 +15,7 @@ export async function POST(request: Request) {
websiteId,
dateRange: { startDate, endDate },
parameters: { model, type, step, currency },
...filters
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@ -22,6 +23,7 @@ export async function POST(request: Request) {
}
const data = await getAttribution(websiteId, {
...filters,
startDate: new Date(startDate),
endDate: new Date(endDate),
model,

View file

@ -15,7 +15,7 @@ export async function POST(request: Request) {
websiteId,
dateRange: { startDate, endDate },
parameters: { fields },
filters,
...filters
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@ -23,9 +23,9 @@ export async function POST(request: Request) {
}
const data = await getBreakdown(websiteId, fields, {
...filters,
startDate: new Date(startDate),
endDate: new Date(endDate),
...filters,
});
return json(data);

View file

@ -15,6 +15,7 @@ export async function POST(request: Request) {
websiteId,
dateRange: { startDate, endDate },
parameters: { steps, window },
...filters
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@ -22,6 +23,7 @@ export async function POST(request: Request) {
}
const data = await getFunnel(websiteId, {
...filters,
startDate: new Date(startDate),
endDate: new Date(endDate),
steps,

View file

@ -15,6 +15,7 @@ export async function POST(request: Request) {
websiteId,
dateRange: { startDate, endDate },
parameters: { type, value, property, operator },
...filters
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@ -22,12 +23,13 @@ export async function POST(request: Request) {
}
const data = await getGoal(websiteId, {
...filters,
startDate: new Date(startDate),
endDate: new Date(endDate),
type,
value,
property,
operator,
startDate: new Date(startDate),
endDate: new Date(endDate),
});
return json(data);

View file

@ -15,6 +15,7 @@ export async function POST(request: Request) {
websiteId,
dateRange: { startDate, endDate },
parameters: { steps, startStep, endStep },
...filters
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@ -22,6 +23,7 @@ export async function POST(request: Request) {
}
const data = await getJourney(websiteId, {
...filters,
startDate: new Date(startDate),
endDate: new Date(endDate),
steps,

View file

@ -14,6 +14,7 @@ export async function POST(request: Request) {
const {
websiteId,
dateRange: { startDate, endDate, timezone },
...filters
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@ -21,6 +22,7 @@ export async function POST(request: Request) {
}
const data = await getRetention(websiteId, {
...filters,
startDate: new Date(startDate),
endDate: new Date(endDate),
timezone,

View file

@ -15,6 +15,7 @@ export async function POST(request: Request) {
websiteId,
dateRange: { startDate, endDate, unit },
parameters: { currency },
...filters
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@ -22,6 +23,7 @@ export async function POST(request: Request) {
}
const data = await getRevenue(websiteId, {
...filters,
startDate: new Date(startDate),
endDate: new Date(endDate),
unit,

View file

@ -14,6 +14,7 @@ export async function POST(request: Request) {
const {
websiteId,
dateRange: { startDate, endDate },
...filters
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@ -21,6 +22,7 @@ export async function POST(request: Request) {
}
const data = await getUTM(websiteId, {
...filters,
startDate: new Date(startDate),
endDate: new Date(endDate),
});