mirror of
https://github.com/umami-software/umami.git
synced 2026-02-08 06:37:18 +01:00
UTM report.
This commit is contained in:
parent
e602aedd21
commit
bca9c87021
25 changed files with 379 additions and 39 deletions
|
|
@ -1,4 +1,5 @@
|
|||
'use client';
|
||||
import { Metadata } from 'next';
|
||||
import ReportsHeader from './ReportsHeader';
|
||||
import ReportsDataTable from './ReportsDataTable';
|
||||
|
||||
|
|
@ -10,6 +11,7 @@ export default function ReportsPage({ teamId }: { teamId: string }) {
|
|||
</>
|
||||
);
|
||||
}
|
||||
export const metadata = {
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Reports',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
import FunnelReport from '../funnel/FunnelReport';
|
||||
import EventDataReport from '../event-data/EventDataReport';
|
||||
import InsightsReport from '../insights/InsightsReport';
|
||||
import RetentionReport from '../retention/RetentionReport';
|
||||
import { useApi } from 'components/hooks';
|
||||
|
||||
const reports = {
|
||||
funnel: FunnelReport,
|
||||
'event-data': EventDataReport,
|
||||
insights: InsightsReport,
|
||||
retention: RetentionReport,
|
||||
};
|
||||
|
||||
export default function ReportDetails({ reportId }: { reportId: string }) {
|
||||
const { get, useQuery } = useApi();
|
||||
const { data: report } = useQuery({
|
||||
queryKey: ['reports', reportId],
|
||||
queryFn: () => get(`/reports/${reportId}`),
|
||||
});
|
||||
|
||||
if (!report) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ReportComponent = reports[report.type];
|
||||
|
||||
return <ReportComponent reportId={reportId} />;
|
||||
}
|
||||
|
|
@ -1,6 +1,27 @@
|
|||
'use client';
|
||||
import ReportDetails from './ReportDetails';
|
||||
import FunnelReport from '../funnel/FunnelReport';
|
||||
import EventDataReport from '../event-data/EventDataReport';
|
||||
import InsightsReport from '../insights/InsightsReport';
|
||||
import RetentionReport from '../retention/RetentionReport';
|
||||
import UTMReport from '../utm/UTMReport';
|
||||
import { useReport } from 'components/hooks';
|
||||
|
||||
export default function ReportPage({ reportId }) {
|
||||
return <ReportDetails reportId={reportId} />;
|
||||
const reports = {
|
||||
funnel: FunnelReport,
|
||||
'event-data': EventDataReport,
|
||||
insights: InsightsReport,
|
||||
retention: RetentionReport,
|
||||
utm: UTMReport,
|
||||
};
|
||||
|
||||
export default function ReportPage({ reportId }: { reportId: string }) {
|
||||
const { report } = useReport(reportId);
|
||||
|
||||
if (!report) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ReportComponent = reports[report.type];
|
||||
|
||||
return <ReportComponent reportId={reportId} />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import PageHeader from 'components/layout/PageHeader';
|
|||
import Funnel from 'assets/funnel.svg';
|
||||
import Lightbulb from 'assets/lightbulb.svg';
|
||||
import Magnet from 'assets/magnet.svg';
|
||||
import Tag from 'assets/tag.svg';
|
||||
import styles from './ReportTemplates.module.css';
|
||||
import { useMessages, useTeamUrl } from 'components/hooks';
|
||||
|
||||
|
|
@ -30,6 +31,12 @@ export function ReportTemplates({ showHeader = true }: { showHeader?: boolean })
|
|||
url: renderTeamUrl('/reports/retention'),
|
||||
icon: <Magnet />,
|
||||
},
|
||||
{
|
||||
title: formatMessage(labels.utm),
|
||||
description: formatMessage(labels.utmDescription),
|
||||
url: renderTeamUrl('/reports/utm'),
|
||||
icon: <Tag />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ export function InsightsParameters() {
|
|||
filters,
|
||||
};
|
||||
|
||||
const handleSubmit = values => {
|
||||
const handleSubmit = (values: any) => {
|
||||
runReport(values);
|
||||
};
|
||||
|
||||
const handleAdd = (id, value) => {
|
||||
const handleAdd = (id: string | number, value: { name: any }) => {
|
||||
const data = parameterData[id];
|
||||
|
||||
if (!data.find(({ name }) => name === value.name)) {
|
||||
|
|
@ -65,7 +65,7 @@ export function InsightsParameters() {
|
|||
}
|
||||
};
|
||||
|
||||
const handleRemove = (id, index) => {
|
||||
const handleRemove = (id: string, index: number) => {
|
||||
const data = [...parameterData[id]];
|
||||
data.splice(index, 1);
|
||||
updateReport({ parameters: { [id]: data } });
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
'use client';
|
||||
import { Metadata } from 'next';
|
||||
import RetentionReport from './RetentionReport';
|
||||
|
||||
export default function RetentionReportPage() {
|
||||
return <RetentionReport />;
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Retention Report',
|
||||
};
|
||||
|
|
|
|||
36
src/app/(main)/reports/utm/UTMParameters.tsx
Normal file
36
src/app/(main)/reports/utm/UTMParameters.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { useContext } from 'react';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { Form, FormButtons, SubmitButton } from 'react-basics';
|
||||
import { ReportContext } from '../[reportId]/Report';
|
||||
import BaseParameters from '../[reportId]/BaseParameters';
|
||||
|
||||
export function UTMParameters() {
|
||||
const { report, runReport, isRunning } = useContext(ReportContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const { id, parameters } = report || {};
|
||||
const { websiteId, dateRange } = parameters || {};
|
||||
const queryDisabled = !websiteId || !dateRange;
|
||||
|
||||
const handleSubmit = (data: any, e: any) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
if (!queryDisabled) {
|
||||
runReport(data);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||
<BaseParameters showDateSelect={true} allowWebsiteSelect={!id} />
|
||||
<FormButtons>
|
||||
<SubmitButton variant="primary" disabled={queryDisabled} isLoading={isRunning}>
|
||||
{formatMessage(labels.runQuery)}
|
||||
</SubmitButton>
|
||||
</FormButtons>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
export default UTMParameters;
|
||||
28
src/app/(main)/reports/utm/UTMReport.tsx
Normal file
28
src/app/(main)/reports/utm/UTMReport.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
'use client';
|
||||
import Report from '../[reportId]/Report';
|
||||
import ReportHeader from '../[reportId]/ReportHeader';
|
||||
import ReportMenu from '../[reportId]/ReportMenu';
|
||||
import ReportBody from '../[reportId]/ReportBody';
|
||||
import UTMParameters from './UTMParameters';
|
||||
import UTMView from './UTMView';
|
||||
import Tag from 'assets/tag.svg';
|
||||
import { REPORT_TYPES } from 'lib/constants';
|
||||
|
||||
const defaultParameters = {
|
||||
type: REPORT_TYPES.utm,
|
||||
parameters: {},
|
||||
};
|
||||
|
||||
export default function UTMReport({ reportId }: { reportId?: string }) {
|
||||
return (
|
||||
<Report reportId={reportId} defaultParameters={defaultParameters}>
|
||||
<ReportHeader icon={<Tag />} />
|
||||
<ReportMenu>
|
||||
<UTMParameters />
|
||||
</ReportMenu>
|
||||
<ReportBody>
|
||||
<UTMView />
|
||||
</ReportBody>
|
||||
</Report>
|
||||
);
|
||||
}
|
||||
5
src/app/(main)/reports/utm/UTMReportPage.tsx
Normal file
5
src/app/(main)/reports/utm/UTMReportPage.tsx
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import UTMReport from './UTMReport';
|
||||
|
||||
export default function UTMReportPage() {
|
||||
return <UTMReport />;
|
||||
}
|
||||
24
src/app/(main)/reports/utm/UTMView.module.css
Normal file
24
src/app/(main)/reports/utm/UTMView.module.css
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.params {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.label {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.value {
|
||||
min-width: 50px;
|
||||
text-align: right;
|
||||
}
|
||||
43
src/app/(main)/reports/utm/UTMView.tsx
Normal file
43
src/app/(main)/reports/utm/UTMView.tsx
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { useContext } from 'react';
|
||||
import { firstBy } from 'thenby';
|
||||
import { ReportContext } from '../[reportId]/Report';
|
||||
import styles from './UTMView.module.css';
|
||||
|
||||
function toArray(data: { [key: string]: number }) {
|
||||
return Object.keys(data)
|
||||
.map(key => {
|
||||
return { name: key, value: data[key] };
|
||||
})
|
||||
.sort(firstBy('value', -1));
|
||||
}
|
||||
|
||||
export default function UTMView() {
|
||||
const { report } = useContext(ReportContext);
|
||||
const { data } = report || {};
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{Object.keys(data).map(key => {
|
||||
return (
|
||||
<div key={key}>
|
||||
<div className={styles.title}>{key}</div>
|
||||
<div className={styles.params}>
|
||||
{toArray(data[key]).map(({ name, value }) => {
|
||||
return (
|
||||
<div key={name} className={styles.row}>
|
||||
<div className={styles.label}>{name}</div>
|
||||
<div className={styles.value}>{value}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
10
src/app/(main)/reports/utm/page.tsx
Normal file
10
src/app/(main)/reports/utm/page.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Metadata } from 'next';
|
||||
import UTMReportPage from './UTMReportPage';
|
||||
|
||||
export default function () {
|
||||
return <UTMReportPage />;
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'UTM Report',
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue