mirror of
https://github.com/umami-software/umami.git
synced 2026-02-07 22:27:16 +01:00
Refactor part 2: Electric Boogaloo. Standardize way of passing filter parameters.
This commit is contained in:
parent
f26f1b0581
commit
cdf391d5c2
90 changed files with 867 additions and 709 deletions
|
|
@ -3,17 +3,11 @@ import { useUsersQuery } from '@/components/hooks';
|
|||
import { UsersTable } from './UsersTable';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export function UsersDataTable({
|
||||
showActions,
|
||||
children,
|
||||
}: {
|
||||
showActions?: boolean;
|
||||
children?: ReactNode;
|
||||
}) {
|
||||
export function UsersDataTable({ showActions }: { showActions?: boolean; children?: ReactNode }) {
|
||||
const queryResult = useUsersQuery();
|
||||
|
||||
return (
|
||||
<DataGrid queryResult={queryResult} renderEmpty={() => children}>
|
||||
<DataGrid queryResult={queryResult} allowSearch={true}>
|
||||
{({ data }) => <UsersTable data={data} showActions={showActions} />}
|
||||
</DataGrid>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import { TagsTable } from '@/components/metrics/TagsTable';
|
|||
import { getCompareDate } from '@/lib/date';
|
||||
import { formatNumber } from '@/lib/format';
|
||||
import { useState } from 'react';
|
||||
import { useWebsites } from '@/store/websites';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { DateDisplay } from '@/components/common/DateDisplay';
|
||||
|
||||
|
|
@ -42,8 +41,7 @@ const views = {
|
|||
|
||||
export function WebsiteCompareTables({ websiteId }: { websiteId: string }) {
|
||||
const [data, setData] = useState([]);
|
||||
const { dateRange } = useDateRange(websiteId);
|
||||
const dateCompare = useWebsites(state => state[websiteId]?.dateCompare);
|
||||
const { dateRange, dateCompare } = useDateRange(websiteId);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const {
|
||||
updateParams,
|
||||
|
|
|
|||
|
|
@ -17,43 +17,43 @@ export function WebsiteMetricsBar({
|
|||
const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(websiteId);
|
||||
const isAllTime = dateRange.value === 'all';
|
||||
|
||||
const { pageviews, visitors, visits, bounces, totaltime, previous } = data || {};
|
||||
const { pageviews, visitors, visits, bounces, totaltime, comparison } = data || {};
|
||||
|
||||
const metrics = data
|
||||
? [
|
||||
{
|
||||
value: visitors,
|
||||
label: formatMessage(labels.visitors),
|
||||
change: visitors - previous.visitors,
|
||||
change: visitors - comparison.visitors,
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
value: visits,
|
||||
label: formatMessage(labels.visits),
|
||||
change: visits - previous.visits,
|
||||
change: visits - comparison.visits,
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
value: pageviews,
|
||||
label: formatMessage(labels.views),
|
||||
change: pageviews - previous.pageviews,
|
||||
change: pageviews - comparison.pageviews,
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
label: formatMessage(labels.bounceRate),
|
||||
value: (Math.min(visits, bounces) / visits) * 100,
|
||||
prev: (Math.min(previous.visits, previous.bounces) / previous.visits) * 100,
|
||||
prev: (Math.min(comparison.visits, comparison.bounces) / comparison.visits) * 100,
|
||||
change:
|
||||
(Math.min(visits, bounces) / visits) * 100 -
|
||||
(Math.min(previous.visits, previous.bounces) / previous.visits) * 100,
|
||||
(Math.min(comparison.visits, comparison.bounces) / comparison.visits) * 100,
|
||||
formatValue: n => Math.round(+n) + '%',
|
||||
reverseColors: true,
|
||||
},
|
||||
{
|
||||
label: formatMessage(labels.visitDuration),
|
||||
value: totaltime / visits,
|
||||
prev: previous.totaltime / previous.visits,
|
||||
change: totaltime / visits - previous.totaltime / previous.visits,
|
||||
prev: comparison.totaltime / comparison.visits,
|
||||
change: totaltime / visits - comparison.totaltime / comparison.visits,
|
||||
formatValue: n =>
|
||||
`${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { useWebsiteEventsQuery } from '@/components/hooks';
|
||||
import { useState } from 'react';
|
||||
import { useMessages, useWebsiteEventsQuery } from '@/components/hooks';
|
||||
import { EventsTable } from './EventsTable';
|
||||
import { DataGrid } from '@/components/common/DataGrid';
|
||||
import { ReactNode } from 'react';
|
||||
import { FilterButtons } from '@/components/common/FilterButtons';
|
||||
|
||||
export function EventsDataTable({
|
||||
websiteId,
|
||||
|
|
@ -10,10 +12,37 @@ export function EventsDataTable({
|
|||
teamId?: string;
|
||||
children?: ReactNode;
|
||||
}) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const queryResult = useWebsiteEventsQuery(websiteId);
|
||||
const [view, setView] = useState('all');
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
id: 'all',
|
||||
label: formatMessage(labels.all),
|
||||
},
|
||||
{
|
||||
id: 'page',
|
||||
label: formatMessage(labels.page),
|
||||
},
|
||||
{
|
||||
id: 'event',
|
||||
label: formatMessage(labels.event),
|
||||
},
|
||||
];
|
||||
|
||||
const renderActions = () => {
|
||||
return <FilterButtons items={buttons} value={view} onChange={setView} />;
|
||||
};
|
||||
|
||||
return (
|
||||
<DataGrid queryResult={queryResult} allowSearch={true} autoFocus={false}>
|
||||
<DataGrid
|
||||
queryResult={queryResult}
|
||||
allowSearch={true}
|
||||
autoFocus={false}
|
||||
allowPaging={true}
|
||||
renderActions={renderActions}
|
||||
>
|
||||
{({ data }) => <EventsTable data={data} />}
|
||||
</DataGrid>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { Avatar } from '@/components/common/Avatar';
|
|||
import Link from 'next/link';
|
||||
import { Bolt, Eye } from '@/components/icons';
|
||||
import { DateDistance } from '@/components/common/DateDistance';
|
||||
import { TypeIcon } from '@/components/common/TypeIcon';
|
||||
|
||||
export function EventsTable({ data = [] }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
@ -16,13 +17,6 @@ export function EventsTable({ data = [] }) {
|
|||
|
||||
return (
|
||||
<DataTable data={data}>
|
||||
<DataColumn id="session" label={formatMessage(labels.session)} width="100px">
|
||||
{(row: any) => (
|
||||
<Link href={renderUrl(`/websites/${row.websiteId}/sessions/${row.sessionId}`)}>
|
||||
<Avatar seed={row.sessionId} size={64} />
|
||||
</Link>
|
||||
)}
|
||||
</DataColumn>
|
||||
<DataColumn id="event" label={formatMessage(labels.event)} width="2fr">
|
||||
{(row: any) => {
|
||||
return (
|
||||
|
|
@ -34,8 +28,21 @@ export function EventsTable({ data = [] }) {
|
|||
);
|
||||
}}
|
||||
</DataColumn>
|
||||
<DataColumn id="created" label={formatMessage(labels.created)} width="200px">
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
<DataColumn id="created" width="1fr" align="end">
|
||||
{(row: any) => (
|
||||
<Row alignItems="center" gap>
|
||||
<DateDistance date={new Date(row.createdAt)} />
|
||||
<Link href={renderUrl(`/websites/${row.websiteId}/sessions/${row.sessionId}`)}>
|
||||
<Avatar seed={row.sessionId} size={32} />
|
||||
</Link>
|
||||
<Row alignItems="center" gap="1">
|
||||
<TypeIcon type="country" value={row.country} />
|
||||
<TypeIcon type="browser" value={row.browser} />
|
||||
<TypeIcon type="os" value={row.os} />
|
||||
<TypeIcon type="device" value={row.device} />
|
||||
</Row>
|
||||
</Row>
|
||||
)}
|
||||
</DataColumn>
|
||||
</DataTable>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -30,15 +30,11 @@ export function Attribution({
|
|||
}: AttributionProps) {
|
||||
const { data, error, isLoading } = useResultQuery<any>('attribution', {
|
||||
websiteId,
|
||||
dateRange: {
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
parameters: {
|
||||
model,
|
||||
type,
|
||||
step,
|
||||
},
|
||||
startDate,
|
||||
endDate,
|
||||
model,
|
||||
type,
|
||||
step,
|
||||
});
|
||||
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
|
|||
|
|
@ -7,12 +7,10 @@ export interface BreakdownProps {
|
|||
websiteId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
parameters: {
|
||||
fields: string[];
|
||||
};
|
||||
selectedFields: string[];
|
||||
}
|
||||
|
||||
export function Breakdown({ websiteId, parameters, startDate, endDate }: BreakdownProps) {
|
||||
export function Breakdown({ websiteId, selectedFields = [], startDate, endDate }: BreakdownProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { formatValue } = useFormat();
|
||||
const { fields } = useFields();
|
||||
|
|
@ -20,19 +18,17 @@ export function Breakdown({ websiteId, parameters, startDate, endDate }: Breakdo
|
|||
'breakdown',
|
||||
{
|
||||
websiteId,
|
||||
dateRange: {
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
parameters,
|
||||
startDate,
|
||||
endDate,
|
||||
fields: selectedFields,
|
||||
},
|
||||
{ enabled: !!parameters.fields.length },
|
||||
{ enabled: !!selectedFields.length },
|
||||
);
|
||||
|
||||
return (
|
||||
<LoadingPanel data={data} isLoading={isLoading} error={error}>
|
||||
<DataTable data={data}>
|
||||
{parameters?.fields.map(field => {
|
||||
{selectedFields.map(field => {
|
||||
return (
|
||||
<DataColumn key={field} id={field} label={fields.find(f => f.name === field)?.label}>
|
||||
{row => {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export function BreakdownPage({ websiteId }: { websiteId: string }) {
|
|||
websiteId={websiteId}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
parameters={{ fields }}
|
||||
selectedFields={fields}
|
||||
/>
|
||||
</Panel>
|
||||
</Column>
|
||||
|
|
|
|||
|
|
@ -17,15 +17,11 @@ type FunnelResult = {
|
|||
remaining: number;
|
||||
};
|
||||
|
||||
export function Funnel({ id, name, type, parameters, websiteId, startDate, endDate }) {
|
||||
export function Funnel({ id, name, type, parameters, websiteId }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { data, error, isLoading } = useResultQuery<any>(type, {
|
||||
const { data, error, isLoading } = useResultQuery(type, {
|
||||
websiteId,
|
||||
dateRange: {
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
parameters,
|
||||
...parameters,
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { LoadingPanel } from '@/components/common/LoadingPanel';
|
|||
import { Panel } from '@/components/common/Panel';
|
||||
|
||||
export function FunnelsPage({ websiteId }: { websiteId: string }) {
|
||||
const { result, query } = useReportsQuery({ websiteId, type: 'funnel' });
|
||||
const { data, isLoading, error } = useReportsQuery({ websiteId, type: 'funnel' });
|
||||
const {
|
||||
dateRange: { startDate, endDate },
|
||||
} = useDateRange(websiteId);
|
||||
|
|
@ -20,14 +20,16 @@ export function FunnelsPage({ websiteId }: { websiteId: string }) {
|
|||
<SectionHeader>
|
||||
<FunnelAddButton websiteId={websiteId} />
|
||||
</SectionHeader>
|
||||
<LoadingPanel data={result?.data} isLoading={query?.isLoading} error={query?.error}>
|
||||
<Grid gap>
|
||||
{result?.data?.map((report: any) => (
|
||||
<Panel key={report.id}>
|
||||
<Funnel {...report} startDate={startDate} endDate={endDate} />
|
||||
</Panel>
|
||||
))}
|
||||
</Grid>
|
||||
<LoadingPanel data={data} isLoading={isLoading} error={error}>
|
||||
{data && (
|
||||
<Grid gap>
|
||||
{data['data']?.map((report: any) => (
|
||||
<Panel key={report.id}>
|
||||
<Funnel {...report} startDate={startDate} endDate={endDate} />
|
||||
</Panel>
|
||||
))}
|
||||
</Grid>
|
||||
)}
|
||||
</LoadingPanel>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,11 +26,9 @@ export function Goal({ id, name, type, parameters, websiteId, startDate, endDate
|
|||
const { formatMessage, labels } = useMessages();
|
||||
const { data, error, isLoading, isFetching } = useResultQuery<GoalData>(type, {
|
||||
websiteId,
|
||||
dateRange: {
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
parameters,
|
||||
startDate,
|
||||
endDate,
|
||||
...parameters,
|
||||
});
|
||||
const isPage = parameters?.type === 'page';
|
||||
|
||||
|
|
|
|||
|
|
@ -22,28 +22,15 @@ export interface JourneyProps {
|
|||
endStep?: string;
|
||||
}
|
||||
|
||||
export function Journey({
|
||||
websiteId,
|
||||
startDate,
|
||||
endDate,
|
||||
steps,
|
||||
startStep,
|
||||
endStep,
|
||||
}: JourneyProps) {
|
||||
export function Journey({ websiteId, steps, startStep, endStep }: JourneyProps) {
|
||||
const [selectedNode, setSelectedNode] = useState(null);
|
||||
const [activeNode, setActiveNode] = useState(null);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { data, error, isLoading } = useResultQuery<any>('journey', {
|
||||
websiteId,
|
||||
dateRange: {
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
parameters: {
|
||||
steps,
|
||||
startStep,
|
||||
endStep,
|
||||
},
|
||||
steps,
|
||||
startStep,
|
||||
endStep,
|
||||
});
|
||||
|
||||
useEscapeKey(() => setSelectedNode(null));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { Grid, Row, Column, Text, Icon } from '@umami/react-zen';
|
||||
import { Users } from '@/components/icons';
|
||||
import { useMessages, useLocale, useResultQuery, useTimezone } from '@/components/hooks';
|
||||
import { useMessages, useLocale, useResultQuery } from '@/components/hooks';
|
||||
import { formatDate } from '@/lib/date';
|
||||
import { formatLongNumber } from '@/lib/format';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
|
|
@ -19,14 +19,10 @@ export interface RetentionProps {
|
|||
export function Retention({ websiteId, days = DAYS, startDate, endDate }: RetentionProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { locale } = useLocale();
|
||||
const { timezone } = useTimezone();
|
||||
const { data, error, isLoading } = useResultQuery<any>('retention', {
|
||||
const { data, error, isLoading } = useResultQuery('retention', {
|
||||
websiteId,
|
||||
dateRange: {
|
||||
startDate,
|
||||
endDate,
|
||||
timezone,
|
||||
},
|
||||
startDate,
|
||||
endDate,
|
||||
});
|
||||
|
||||
const rows =
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { endOfMonth, startOfMonth } from 'date-fns';
|
|||
export function RetentionPage({ websiteId }: { websiteId: string }) {
|
||||
const {
|
||||
dateRange: { startDate },
|
||||
} = useDateRange(websiteId);
|
||||
} = useDateRange(websiteId, { ignoreOffset: true });
|
||||
|
||||
const monthStartDate = startOfMonth(startDate);
|
||||
const monthEndDate = endOfMonth(startDate);
|
||||
|
|
|
|||
|
|
@ -32,13 +32,9 @@ export function Revenue({ websiteId, startDate, endDate }: RevenueProps) {
|
|||
const unit = getMinimumUnit(startDate, endDate);
|
||||
const { data, error, isLoading } = useResultQuery<any>('revenue', {
|
||||
websiteId,
|
||||
dateRange: {
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
parameters: {
|
||||
currency,
|
||||
},
|
||||
startDate,
|
||||
endDate,
|
||||
currency,
|
||||
});
|
||||
|
||||
const renderCountryName = useCallback(
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@ export function UTM({ websiteId, startDate, endDate }: UTMProps) {
|
|||
const { formatMessage, labels } = useMessages();
|
||||
const { data, error, isLoading } = useResultQuery<any>('utm', {
|
||||
websiteId,
|
||||
dateRange: {
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
startDate,
|
||||
endDate,
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,21 +1,15 @@
|
|||
import { useWebsiteSessionsQuery } from '@/components/hooks';
|
||||
import { SessionsTable } from './SessionsTable';
|
||||
import { DataGrid } from '@/components/common/DataGrid';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export function SessionsDataTable({
|
||||
websiteId,
|
||||
children,
|
||||
}: {
|
||||
websiteId?: string;
|
||||
teamId?: string;
|
||||
children?: ReactNode;
|
||||
}) {
|
||||
export function SessionsDataTable({ websiteId }: { websiteId?: string; teamId?: string }) {
|
||||
const queryResult = useWebsiteSessionsQuery(websiteId);
|
||||
|
||||
return (
|
||||
<DataGrid queryResult={queryResult} renderEmpty={() => children} allowPaging>
|
||||
{({ data }) => <SessionsTable data={data} showDomain={!websiteId} />}
|
||||
<DataGrid queryResult={queryResult} allowPaging allowSearch>
|
||||
{({ data }) => {
|
||||
return <SessionsTable data={data} showDomain={!websiteId} />;
|
||||
}}
|
||||
</DataGrid>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export function SessionsTable({ data = [] }: { data: any[]; showDomain?: boolean
|
|||
<DataColumn id="id" label={formatMessage(labels.session)} width="100px">
|
||||
{(row: any) => (
|
||||
<Link href={`sessions/${row.id}`}>
|
||||
<Avatar seed={row.id} size={64} />
|
||||
<Avatar seed={row.id} size={48} />
|
||||
</Link>
|
||||
)}
|
||||
</DataColumn>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request';
|
||||
import { json, unauthorized } from '@/lib/response';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
import { getAttribution } from '@/queries/sql/reports/getAttribution';
|
||||
import { AttributionParameters, getAttribution } from '@/queries/sql/reports/getAttribution';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const { auth, body, error } = await parseRequest(request, reportResultSchema);
|
||||
|
|
@ -11,26 +11,16 @@ export async function POST(request: Request) {
|
|||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
dateRange: { startDate, endDate },
|
||||
parameters: { model, type, step, currency },
|
||||
...filters
|
||||
} = body;
|
||||
const { websiteId } = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getAttribution(websiteId, {
|
||||
...filters,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
model,
|
||||
type,
|
||||
step,
|
||||
currency,
|
||||
});
|
||||
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||
const filters = getQueryFilters(body.filters);
|
||||
|
||||
const data = await getAttribution(websiteId, parameters as AttributionParameters, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getBreakdown } from '@/queries';
|
||||
import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request';
|
||||
import { BreakdownParameters, getBreakdown } from '@/queries';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
|
|
@ -11,22 +11,16 @@ export async function POST(request: Request) {
|
|||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
dateRange: { startDate, endDate },
|
||||
parameters: { fields },
|
||||
...filters
|
||||
} = body;
|
||||
const { websiteId } = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getBreakdown(websiteId, fields, {
|
||||
...filters,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
});
|
||||
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||
const filters = getQueryFilters(body.filters);
|
||||
|
||||
const data = await getBreakdown(websiteId, parameters as BreakdownParameters, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getFunnel } from '@/queries';
|
||||
import { parseRequest, getQueryFilters, setWebsiteDate } from '@/lib/request';
|
||||
import { FunnelParameters, getFunnel } from '@/queries';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
|
|
@ -11,24 +11,16 @@ export async function POST(request: Request) {
|
|||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
dateRange: { startDate, endDate },
|
||||
parameters: { steps, window },
|
||||
...filters
|
||||
} = body;
|
||||
const { websiteId } = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getFunnel(websiteId, {
|
||||
...filters,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
steps,
|
||||
windowMinutes: +window,
|
||||
});
|
||||
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||
const filters = getQueryFilters(body.filters);
|
||||
|
||||
const data = await getFunnel(websiteId, parameters as FunnelParameters, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { getGoal } from '@/queries/sql/reports/getGoal';
|
||||
import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request';
|
||||
import { getGoal, GoalParameters } from '@/queries/sql/reports/getGoal';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
|
|
@ -11,27 +11,16 @@ export async function POST(request: Request) {
|
|||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
dateRange: { startDate, endDate },
|
||||
parameters: { type, value, property, operator },
|
||||
} = body;
|
||||
const { websiteId } = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const filters = await getQueryFilters(body.filters);
|
||||
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||
const filters = getQueryFilters(body.filters);
|
||||
|
||||
const data = await getGoal(websiteId, {
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
type,
|
||||
value,
|
||||
property,
|
||||
operator,
|
||||
filters,
|
||||
});
|
||||
const data = await getGoal(websiteId, parameters as GoalParameters, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request';
|
||||
import { getJourney } from '@/queries';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
|
||||
|
|
@ -11,25 +11,15 @@ export async function POST(request: Request) {
|
|||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
dateRange: { startDate, endDate },
|
||||
parameters: { steps, startStep, endStep },
|
||||
...filters
|
||||
} = body;
|
||||
const { websiteId, parameters, filters } = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getJourney(websiteId, {
|
||||
...filters,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
steps,
|
||||
startStep,
|
||||
endStep,
|
||||
});
|
||||
const queryFilters = await setWebsiteDate(websiteId, getQueryFilters(filters));
|
||||
|
||||
const data = await getJourney(websiteId, parameters, queryFilters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getRetention } from '@/queries';
|
||||
import { parseRequest, getQueryFilters, setWebsiteDate } from '@/lib/request';
|
||||
import { getRetention, RetentionParameters } from '@/queries';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
|
|
@ -11,22 +11,16 @@ export async function POST(request: Request) {
|
|||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
dateRange: { startDate, endDate, timezone },
|
||||
...filters
|
||||
} = body;
|
||||
const { websiteId } = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getRetention(websiteId, {
|
||||
...filters,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
timezone,
|
||||
});
|
||||
const filters = getQueryFilters(body.filters);
|
||||
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||
|
||||
const data = await getRetention(websiteId, parameters as RetentionParameters, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters, setWebsiteDate } from '@/lib/request';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
import { getRevenue } from '@/queries/sql/reports/getRevenue';
|
||||
import { getRevenue, RevenuParameters } from '@/queries/sql/reports/getRevenue';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const { auth, body, error } = await parseRequest(request, reportResultSchema);
|
||||
|
|
@ -11,24 +11,16 @@ export async function POST(request: Request) {
|
|||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
dateRange: { startDate, endDate, unit },
|
||||
parameters: { currency },
|
||||
...filters
|
||||
} = body;
|
||||
const { websiteId } = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getRevenue(websiteId, {
|
||||
...filters,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
unit,
|
||||
currency,
|
||||
});
|
||||
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||
const filters = getQueryFilters(body.filters);
|
||||
|
||||
const data = await getRevenue(websiteId, parameters as RevenuParameters, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getUTM } from '@/queries';
|
||||
import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request';
|
||||
import { getUTM, UTMParameters } from '@/queries';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
|
|
@ -11,21 +11,16 @@ export async function POST(request: Request) {
|
|||
return error();
|
||||
}
|
||||
|
||||
const {
|
||||
websiteId,
|
||||
dateRange: { startDate, endDate },
|
||||
...filters
|
||||
} = body;
|
||||
const { websiteId } = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getUTM(websiteId, {
|
||||
...filters,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
});
|
||||
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||
const filters = getQueryFilters(body.filters);
|
||||
|
||||
const data = await getUTM(websiteId, parameters as UTMParameters, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { z } from 'zod';
|
|||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { pagingParams } from '@/lib/schema';
|
||||
import { dateRangeParams, pagingParams, filterParams } from '@/lib/schema';
|
||||
import { getWebsiteEvents } from '@/queries';
|
||||
|
||||
export async function GET(
|
||||
|
|
@ -10,8 +10,8 @@ export async function GET(
|
|||
{ params }: { params: Promise<{ websiteId: string }> },
|
||||
) {
|
||||
const schema = z.object({
|
||||
startAt: z.coerce.number().int(),
|
||||
endAt: z.coerce.number().int(),
|
||||
...dateRangeParams,
|
||||
...filterParams,
|
||||
...pagingParams,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters, setWebsiteDate } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { filterParams, timezoneParam, unitParam } from '@/lib/schema';
|
||||
|
|
@ -29,7 +29,7 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
const filters = await setWebsiteDate(websiteId, getQueryFilters(query));
|
||||
|
||||
const data = await getEventMetrics(websiteId, filters);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import { canViewWebsite } from '@/lib/auth';
|
|||
import {
|
||||
SESSION_COLUMNS,
|
||||
EVENT_COLUMNS,
|
||||
FILTER_COLUMNS,
|
||||
OPERATORS,
|
||||
SEARCH_DOMAINS,
|
||||
SOCIAL_DOMAINS,
|
||||
EMAIL_DOMAINS,
|
||||
|
|
@ -13,7 +11,7 @@ import {
|
|||
VIDEO_DOMAINS,
|
||||
PAID_AD_PARAMS,
|
||||
} from '@/lib/constants';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters, setWebsiteDate } from '@/lib/request';
|
||||
import { json, unauthorized, badRequest } from '@/lib/response';
|
||||
import { getPageviewMetrics, getSessionMetrics, getChannelMetrics } from '@/queries';
|
||||
import { filterParams } from '@/lib/schema';
|
||||
|
|
@ -45,20 +43,14 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const column = FILTER_COLUMNS[type] || type;
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
const filters = await setWebsiteDate(websiteId, getQueryFilters(query));
|
||||
|
||||
if (search) {
|
||||
filters[type] = {
|
||||
name: type,
|
||||
column,
|
||||
operator: OPERATORS.contains,
|
||||
value: search,
|
||||
};
|
||||
filters[type] = `c.${search}`;
|
||||
}
|
||||
|
||||
if (SESSION_COLUMNS.includes(type)) {
|
||||
const data = await getSessionMetrics(websiteId, type, filters, limit, offset);
|
||||
const data = await getSessionMetrics(websiteId, { type, limit, offset }, filters);
|
||||
|
||||
if (type === 'language') {
|
||||
const combined = {};
|
||||
|
|
@ -80,7 +72,7 @@ export async function GET(
|
|||
}
|
||||
|
||||
if (EVENT_COLUMNS.includes(type)) {
|
||||
const data = await getPageviewMetrics(websiteId, type, filters, limit, offset);
|
||||
const data = await getPageviewMetrics(websiteId, { type, limit, offset }, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from 'zod';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request';
|
||||
import { dateRangeParams, filterParams } from '@/lib/schema';
|
||||
import { getCompareDate } from '@/lib/date';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
const filters = await setWebsiteDate(websiteId, getQueryFilters(query));
|
||||
|
||||
const [pageviews, sessions] = await Promise.all([
|
||||
getPageviewStats(websiteId, filters),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request';
|
||||
import { json, unauthorized } from '@/lib/response';
|
||||
import { getSessionDataValues } from '@/queries';
|
||||
import { z } from 'zod';
|
||||
|
|
@ -22,7 +22,7 @@ export async function GET(
|
|||
|
||||
const { propertyName } = query;
|
||||
const { websiteId } = await params;
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
const filters = await setWebsiteDate(websiteId, getQueryFilters(query));
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { dateRangeParams, filterParams, pagingParams } from '@/lib/schema';
|
||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
const filters = await setWebsiteDate(websiteId, getQueryFilters(query));
|
||||
|
||||
const data = await getWebsiteSessions(websiteId, filters);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters, setWebsiteDate } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { filterParams } from '@/lib/schema';
|
||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const filters = await getQueryFilters(query);
|
||||
const filters = await setWebsiteDate(websiteId, getQueryFilters(query));
|
||||
|
||||
const metrics = await getWebsiteSessionStats(websiteId, filters);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { z } from 'zod';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters, setWebsiteDate } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { filterParams } from '@/lib/schema';
|
||||
import { getWebsiteStats } from '@/queries';
|
||||
import { getCompareDate } from '@/lib/date';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
|
|
@ -28,15 +29,17 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
const filters = await setWebsiteDate(websiteId, getQueryFilters(query));
|
||||
|
||||
const data = await getWebsiteStats(websiteId, filters);
|
||||
|
||||
const previous = await getWebsiteStats(websiteId, {
|
||||
const { startDate, endDate } = getCompareDate('prev', filters.startDate, filters.endDate);
|
||||
|
||||
const comparison = await getWebsiteStats(websiteId, {
|
||||
...filters,
|
||||
startDate: filters.compareStartDate,
|
||||
endDate: filters.compareEndDate,
|
||||
startDate,
|
||||
endDate,
|
||||
});
|
||||
|
||||
return json({ ...data, previous });
|
||||
return json({ ...data, comparison });
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue