UTM report.

This commit is contained in:
Mike Cao 2024-03-14 02:45:00 -07:00
parent e602aedd21
commit bca9c87021
25 changed files with 379 additions and 39 deletions

View file

@ -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',
};

View file

@ -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} />;
}

View file

@ -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} />;
}

View file

@ -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 (

View file

@ -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 } });

View file

@ -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',
};

View 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;

View 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>
);
}

View file

@ -0,0 +1,5 @@
import UTMReport from './UTMReport';
export default function UTMReportPage() {
return <UTMReport />;
}

View 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;
}

View 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>
);
}

View 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',
};