add dropoff percentages to funnel report

This commit is contained in:
Francis Cao 2023-07-21 00:14:37 -07:00
parent 94967d45e1
commit 858f465566
5 changed files with 15 additions and 7 deletions

View File

@ -161,6 +161,7 @@ export const labels = defineMessages({
overview: { id: 'labels.overview', defaultMessage: 'Overview' }, overview: { id: 'labels.overview', defaultMessage: 'Overview' },
totalRecords: { id: 'labels.total-records', defaultMessage: 'Total records' }, totalRecords: { id: 'labels.total-records', defaultMessage: 'Total records' },
insights: { id: 'label.insights', defaultMessage: 'Insights' }, insights: { id: 'label.insights', defaultMessage: 'Insights' },
dropoff: { id: 'label.dropoff', defaultMessage: 'Dropoff' },
}); });
export const messages = defineMessages({ export const messages = defineMessages({

View File

@ -78,7 +78,7 @@ const AnimatedRow = ({
showPercentage = true, showPercentage = true,
}) => { }) => {
const props = useSpring({ const props = useSpring({
width: percent, width: Number(percent),
y: value, y: value,
from: { width: 0, y: 0 }, from: { width: 0, y: 0 },
config: animate ? config.default : { duration: 0 }, config: animate ? config.default : { duration: 0 },

View File

@ -6,13 +6,12 @@ import { ReportContext } from '../Report';
export function FunnelTable() { export function FunnelTable() {
const { report } = useContext(ReportContext); const { report } = useContext(ReportContext);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
return ( return (
<DataTable <DataTable
data={report?.data} data={report?.data}
title={formatMessage(labels.url)} title={formatMessage(labels.url)}
metric={formatMessage(labels.visitors)} metric={formatMessage(labels.visitors)}
showPercentage={false} showPercentage={true}
/> />
); );
} }

View File

@ -48,11 +48,11 @@ function getDropoffQuery() {
const db = getDatabaseType(process.env.DATABASE_URL); const db = getDatabaseType(process.env.DATABASE_URL);
if (db === POSTGRESQL) { if (db === POSTGRESQL) {
return `round((1.0 - count::numeric/lag(count, 1) over ()),2)`; return `round((1.0 - count::numeric/lag(nullif(count, 0), 1) over ()),2) * 100`;
} }
if (db === MYSQL) { if (db === MYSQL) {
return `round((1.0 - count/LAG(count, 1) OVER (ORDER BY level)),2)`; return `round((1.0 - count/LAG(nullif(count, 0), 1) OVER (ORDER BY level)),2) * 100`;
} }
} }
@ -173,6 +173,7 @@ function getFunnelQuery(
and ${getAddMinutesQuery(`l.created_at `, windowMinutes)} and ${getAddMinutesQuery(`l.created_at `, windowMinutes)}
and we.referrer_path = $${i + initParamLength} and we.referrer_path = $${i + initParamLength}
and we.url_path = $${levelNumber + initParamLength} and we.url_path = $${levelNumber + initParamLength}
and we.created_at between $2 and $3
and we.website_id = $1${toUuid()} and we.website_id = $1${toUuid()}
)`; )`;
} }
@ -216,6 +217,8 @@ async function rawQuery(query: string, params: never[] = []): Promise<any> {
const sql = db === MYSQL ? query.replace(/\$[0-9]+/g, '?') : query; const sql = db === MYSQL ? query.replace(/\$[0-9]+/g, '?') : query;
// console.log(sql);
// console.log(params);
return prisma.rawQuery(sql, params); return prisma.rawQuery(sql, params);
} }

View File

@ -31,6 +31,7 @@ async function relationalQuery(
{ {
x: string; x: string;
y: number; y: number;
z: number;
}[] }[]
> { > {
const { windowMinutes, startDate, endDate, urls } = criteria; const { windowMinutes, startDate, endDate, urls } = criteria;
@ -60,8 +61,12 @@ async function relationalQuery(
from levelCount; from levelCount;
`, `,
params, params,
).then((a: { [key: string]: number }) => { ).then(results => {
return urls.map((b, i) => ({ x: b, y: a[0][`level${i + 1}`] || 0 })); return urls.map((a, i) => ({
x: a,
y: results[i]?.count || 0,
z: results[i]?.drop_off || 0,
}));
}); });
} }