Goals components. Removed some completed reports.

This commit is contained in:
Mike Cao 2025-05-25 08:58:38 -07:00
parent 7662b77ce3
commit 4552256930
39 changed files with 120 additions and 740 deletions

View file

@ -16,7 +16,7 @@ export function WebsiteDetailsPage({ websiteId }: { websiteId: string }) {
return (
<Column gap>
<WebsiteControls websiteId={websiteId} />
<WebsiteControls websiteId={websiteId} allowCompare={true} />
<Panel>
<WebsiteMetricsBar websiteId={websiteId} showFilter={true} showChange={true} />
</Panel>

View file

@ -80,12 +80,6 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) {
icon: <Icons.Network />,
path: '/attribution',
},
{
id: 'reports',
label: formatMessage(labels.reports),
icon: <Icons.Reports />,
path: '/reports',
},
];
const selected = links.find(({ path }) => path && pathname.endsWith(path))?.id || 'overview';

View file

@ -0,0 +1,24 @@
import { Button, MenuTrigger, Dialog, Icon, Text, Modal } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import { GoalAddForm } from './GoalAddForm';
import { Icons } from '@/components/icons';
export function GoalAddButton({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
return (
<MenuTrigger>
<Button variant="primary">
<Icon>
<Icons.Plus />
</Icon>
<Text>{formatMessage(labels.addGoal)}</Text>
</Button>
<Modal>
<Dialog variant="modal" title={formatMessage(labels.addGoal)}>
{({ close }) => <GoalAddForm websiteId={websiteId} onClose={close} />}
</Dialog>
</Modal>
</MenuTrigger>
);
}

View file

@ -0,0 +1,64 @@
import {
Form,
FormField,
TextField,
Select,
FormButtons,
FormSubmitButton,
Button,
} from '@umami/react-zen';
import { useApi, useMessages } from '@/components/hooks';
export function GoalAddForm({ onSave, onClose }: { onSave?: () => void; onClose?: () => void }) {
const { formatMessage, labels } = useMessages();
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post('/websites', { ...data }),
});
const handleSubmit = async (data: any) => {
mutate(data, {
onSuccess: async () => {
onSave?.();
onClose?.();
},
});
};
const items = [
{ id: 'page', label: formatMessage(labels.page) },
{ id: 'event', label: formatMessage(labels.event) },
];
return (
<Form onSubmit={handleSubmit} error={error?.message}>
<FormField
name="name"
label={formatMessage(labels.name)}
rules={{ required: formatMessage(labels.required) }}
>
<TextField />
</FormField>
<FormField
name="type"
label={formatMessage(labels.type)}
rules={{ required: formatMessage(labels.required) }}
>
<Select items={items} defaultValue="page" />
</FormField>
<FormField
name="value"
label={formatMessage(labels.value)}
rules={{ required: formatMessage(labels.required) }}
>
<TextField />
</FormField>
<FormButtons>
<Button onPress={onClose} isDisabled={isPending}>
{formatMessage(labels.cancel)}
</Button>
<FormSubmitButton isDisabled={false}>{formatMessage(labels.add)}</FormSubmitButton>
</FormButtons>
</Form>
);
}

View file

@ -1,14 +1,16 @@
'use client';
import { Column, Button, Heading } from '@umami/react-zen';
import { Column } from '@umami/react-zen';
import { SectionHeader } from '@/components/common/SectionHeader';
import { GoalAddButton } from './GoalAddButton';
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
export function GoalsPage({ websiteId }: { websiteId: string }) {
return (
<Column>
{websiteId}
<Button>Add goal</Button>
<Heading>Goal 1</Heading>
<Heading>Goal 2</Heading>
<Heading>Goal 3</Heading>
<WebsiteControls websiteId={websiteId} />
<SectionHeader>
<GoalAddButton websiteId={websiteId} />
</SectionHeader>
</Column>
);
}

View file

@ -1,26 +0,0 @@
'use client';
import Link from 'next/link';
import { Button, Flexbox, Icon, Icons, Text } from '@umami/react-zen';
import { useMessages, useNavigation } from '@/components/hooks';
import { ReportsDataTable } from '@/app/(main)/reports/ReportsDataTable';
export function WebsiteReportsPage({ websiteId }) {
const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useNavigation();
return (
<>
<Flexbox alignItems="center" justifyContent="end">
<Link href={renderTeamUrl('/reports/create')}>
<Button variant="primary">
<Icon>
<Icons.Plus />
</Icon>
<Text>{formatMessage(labels.createReport)}</Text>
</Button>
</Link>
</Flexbox>
<ReportsDataTable websiteId={websiteId} />
</>
);
}

View file

@ -1,12 +0,0 @@
import { WebsiteReportsPage } from './WebsiteReportsPage';
import { Metadata } from 'next';
export default async function ({ params }: { params: Promise<{ websiteId: string }> }) {
const { websiteId } = await params;
return <WebsiteReportsPage websiteId={websiteId} />;
}
export const metadata: Metadata = {
title: 'Website Reports',
};

View file

@ -7,21 +7,15 @@ export function RevenueTable({ data = [] }) {
return (
<DataTable data={data}>
<DataColumn id="currency" label={formatMessage(labels.currency)} align="end">
{(row: any) => row.currency}
</DataColumn>
<DataColumn id="currency" label={formatMessage(labels.total)} align="end">
<DataColumn id="currency" label={formatMessage(labels.currency)} align="end" />
<DataColumn id="total" label={formatMessage(labels.total)} align="end">
{(row: any) => formatLongCurrency(row.sum, row.currency)}
</DataColumn>
<DataColumn id="currency" label={formatMessage(labels.average)} align="end">
<DataColumn id="average" label={formatMessage(labels.average)} align="end">
{(row: any) => formatLongCurrency(row.count ? row.sum / row.count : 0, row.currency)}
</DataColumn>
<DataColumn id="currency" label={formatMessage(labels.transactions)} align="end">
{(row: any) => row.count}
</DataColumn>
<DataColumn id="currency" label={formatMessage(labels.uniqueCustomers)} align="end">
{(row: any) => row.unique_count}
</DataColumn>
<DataColumn id="count" label={formatMessage(labels.transactions)} align="end" />
<DataColumn id="unique_count" label={formatMessage(labels.uniqueCustomers)} align="end" />
</DataTable>
);
}

View file

@ -9,6 +9,7 @@ import { GridRow } from '@/components/common/GridRow';
import { useMessages } from '@/components/hooks';
import { SessionsWeekly } from './SessionsWeekly';
import { Panel } from '@/components/common/Panel';
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
export function SessionsPage({ websiteId }) {
const [tab, setTab] = useState('activity');
@ -16,6 +17,7 @@ export function SessionsPage({ websiteId }) {
return (
<Column gap="3">
<WebsiteControls websiteId={websiteId} />
<Panel>
<SessionsMetricsBar websiteId={websiteId} />
</Panel>