From bd4c6879c8533f0106a16e71bb00347d326cda82 Mon Sep 17 00:00:00 2001 From: Ben Vinegar <2153+benvinegar@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:09:00 -0500 Subject: [PATCH] Clearer code re: missing bounce data --- app/routes/__tests__/resources.stats.test.tsx | 11 +++-- app/routes/resources.stats.tsx | 47 +++++++++---------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/app/routes/__tests__/resources.stats.test.tsx b/app/routes/__tests__/resources.stats.test.tsx index 192d024..f0629e3 100644 --- a/app/routes/__tests__/resources.stats.test.tsx +++ b/app/routes/__tests__/resources.stats.test.tsx @@ -48,11 +48,12 @@ describe("resources.stats loader", () => { expect(data).toEqual({ views: 1000, visitors: 250, - bounceRate: "50%", + bounceRate: 0.5, + hasSufficientBounceData: true, }); }); - test("if bounce data isn't complete for the given interval, show n/a", async () => { + test("if bounce data isn't complete for the given interval, hasSufficientBounceData is false", async () => { // set system time as jan 8th vi.setSystemTime(new Date("2023-01-08T00:00:00").getTime()); @@ -79,7 +80,8 @@ describe("resources.stats loader", () => { expect(data).toEqual({ views: 1000, visitors: 250, - bounceRate: "n/a", + bounceRate: 0.5, + hasSufficientBounceData: false, }); }); @@ -110,7 +112,8 @@ describe("resources.stats loader", () => { expect(data).toEqual({ views: 1000, visitors: 250, - bounceRate: "50%", + bounceRate: 0.5, + hasSufficientBounceData: true, }); }); }); diff --git a/app/routes/resources.stats.tsx b/app/routes/resources.stats.tsx index eacdce9..2891260 100644 --- a/app/routes/resources.stats.tsx +++ b/app/routes/resources.stats.tsx @@ -24,42 +24,32 @@ export async function loader({ context, request }: LoaderFunctionArgs) { const { earliestEvent, earliestBounce } = await earliestEvents; const { startDate } = getDateTimeRange(interval, tz); - // FOR BACKWARDS COMPATIBILITY, ONLY CALCULATE BOUNCE RATE IF WE HAVE - // DATE FOR THE ENTIRE QUERY PERIOD + // FOR BACKWARDS COMPAT, ONLY SHOW BOUNCE RATE IF WE HAVE DATE FOR THE ENTIRE QUERY PERIOD // ----------------------------------------------------------------------------- - // bounce rate is a later-introduced metric that may not have been recorded for + // Bounce rate is a later-introduced metric that may not have been recorded for // the full duration of the queried Counterscale dataset (not possible to backfill // data we dont have!) - // so, cannot reliably show "bounce rate" if bounce data was unavailable for a portion - // of the query period + // So, cannot reliably show "bounce rate" if bounce data was unavailable for a portion + // of the query period. - // to figure if we can give an answer or not, we inspect the earliest bounce/earliest event data, - // and decide if our dataset is "complete" for the given interval - let bounceRate; + // To figure out if we can give an answer or not, we inspect the earliest bounce/earliest event + // data recorded, and determine if our dataset is "complete" for the given query interval. - if ( - counts.visitors > 0 && + const hasSufficientBounceData = earliestBounce !== null && earliestEvent !== null && (earliestEvent.getTime() == earliestBounce.getTime() || // earliest event recorded a bounce -- any query is fine - earliestBounce < startDate) // earliest bounce occurred before start of query period -- this query is fine - ) { - bounceRate = (counts.bounces / counts.visitors).toLocaleString( - "en-US", - { - style: "percent", - minimumFractionDigits: 0, - }, - ); - } else { - bounceRate = "n/a"; - } + earliestBounce < startDate); // earliest bounce occurred before start of query period -- this query is fine + + const bounceRate = + counts.visitors > 0 ? counts.bounces / counts.visitors : undefined; return json({ views: counts.views, visitors: counts.visitors, bounceRate: bounceRate, + hasSufficientBounceData, }); } @@ -76,7 +66,8 @@ export const StatsCard = ({ }) => { const dataFetcher = useFetcher(); - const { views, visitors, bounceRate } = dataFetcher.data || {}; + const { views, visitors, bounceRate, hasSufficientBounceData } = + dataFetcher.data || {}; const countFormatter = Intl.NumberFormat("en", { notation: "compact" }); useEffect(() => { @@ -113,7 +104,15 @@ export const StatsCard = ({
Bounce Rate
-
{bounceRate}
+ {hasSufficientBounceData ? ( +
+ {bounceRate !== undefined + ? `${Math.round(bounceRate * 100)}%` + : "-"} +
+ ) : ( +
n/a
+ )}