Skip to content

Commit

Permalink
feat(analytics): add tutor/tutee/parent graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholaschiang committed Feb 7, 2022
1 parent 4a98bd6 commit 82e8fb3
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 17 deletions.
215 changes: 201 additions & 14 deletions components/analytics/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ function Card<T extends Record<string, number> & { week: number }>({
monday.setDate(monday.getDate() - 7 - monday.getDay() + 1);
return monday.valueOf() === new Date(d.week).valueOf();
});
return today ? today[content[0].dataKey] : 0;
return (today ?? data[data.length - 1])[content[0].dataKey];
}, [data, content]);

return (
<div className='card'>
<article className='header'>
<header>
<h2 className={cn({ loading: num === undefined })}>
{content && content[0].rate && num !== undefined ? formatRate(num) : num}
{content && content[0].rate && num !== undefined
? formatRate(num)
: num}
</h2>
<h3>{title}</h3>
</header>
Expand Down Expand Up @@ -199,6 +201,30 @@ export default function Analytics(): JSX.Element {
})),
[data]
);
const tutors = useMemo(
() =>
data?.tutors.map((d) => ({
...d,
week: new Date(d.week).valueOf(),
})),
[data]
);
const tutees = useMemo(
() =>
data?.tutees.map((d) => ({
...d,
week: new Date(d.week).valueOf(),
})),
[data]
);
const parents = useMemo(
() =>
data?.parents.map((d) => ({
...d,
week: new Date(d.week).valueOf(),
})),
[data]
);

// TODO: Ensure that the scale on the chart isn't dependent on the data points
// being equally spaced out. Instead, it should be relative to the data point
Expand Down Expand Up @@ -313,9 +339,9 @@ export default function Analytics(): JSX.Element {
]}
color='#81C784'
>
The growth rate of the number of meetings per week. This graph
should look very similar to the growth rate of users with meetings
per week; both metrics are directly correlated.
The growth rate of the number of meetings per week. This graph should
look very similar to the growth rate of users with meetings per week;
both metrics are directly correlated.
</Card>
<Card
title={
Expand Down Expand Up @@ -382,9 +408,9 @@ export default function Analytics(): JSX.Element {
color='#F06292'
>
The number of users created per week. You’ll notice this graph
correlates well with the <strong>Total users</strong> graph below
it; as the number of new users spikes, the total number of users
will spike too.
correlates well with the <strong>Total users</strong> graph below it;
as the number of new users spikes, the total number of users will
spike too.
</Card>
<Card
title={
Expand All @@ -406,8 +432,8 @@ export default function Analytics(): JSX.Element {
]}
color='#F06292'
>
The growth rate of the number of users created per week. Note that
all of these growth rate graphs depict the derivatives of their
The growth rate of the number of users created per week. Note that all
of these growth rate graphs depict the derivatives of their
corresponding weekly metrics; they are graphs of the slopes.
</Card>
<Card
Expand All @@ -434,9 +460,8 @@ export default function Analytics(): JSX.Element {
<Link href='https://hbr.org/2010/02/entrepreneurs-beware-of-vanity-metrics'>
vanity metric
</Link>
; a number that looks good on paper but isn’t action oriented. Use
it for press releases or marketing, but not to measure actual
growth.
; a number that looks good on paper but isn’t action oriented. Use it
for press releases or marketing, but not to measure actual growth.
</Card>
<Card
title={
Expand All @@ -458,7 +483,169 @@ export default function Analytics(): JSX.Element {
]}
color='#9575CD'
>
The weekly growth rate of the total number of users. Again, this is
The weekly growth rate of the total number of users. Again, this is a{' '}
<Link href='https://hbr.org/2010/02/entrepreneurs-beware-of-vanity-metrics'>
vanity metric
</Link>
; this growth rate will <i>always</i> be positive and thus will{' '}
<i>never</i> provide meaningful feedback on how growth is doing.
</Card>
<Card
title={
<>
Tutors
<br />
in all time
</>
}
data={tutors}
header='Total tutors'
content={[
{ dataKey: 'total', dataLabel: 'total tutors' },
{
dataKey: 'total_growth',
dataLabel: 'from previous week',
rate: true,
},
]}
color='#9575CD'
>
The total number of tutors. This is a{' '}
<Link href='https://hbr.org/2010/02/entrepreneurs-beware-of-vanity-metrics'>
vanity metric
</Link>
; a number that looks good on paper but isn’t action oriented. Use it
for press releases or marketing, but not to measure actual growth.
</Card>
<Card
title={
<>
Weekly growth rate of
<br />
the total number of tutors
</>
}
data={tutors}
header='Total tutors'
content={[
{
dataKey: 'total_growth',
dataLabel: 'from previous week',
rate: true,
},
{ dataKey: 'total', dataLabel: 'total tutors' },
]}
color='#9575CD'
>
The weekly growth rate of the total number of tutors. Again, this is a{' '}
<Link href='https://hbr.org/2010/02/entrepreneurs-beware-of-vanity-metrics'>
vanity metric
</Link>
; this growth rate will <i>always</i> be positive and thus will{' '}
<i>never</i> provide meaningful feedback on how growth is doing.
</Card>
<Card
title={
<>
Tutees
<br />
in all time
</>
}
data={tutees}
header='Total tutees'
content={[
{ dataKey: 'total', dataLabel: 'total tutees' },
{
dataKey: 'total_growth',
dataLabel: 'from previous week',
rate: true,
},
]}
color='#9575CD'
>
The total number of tutees. This is a{' '}
<Link href='https://hbr.org/2010/02/entrepreneurs-beware-of-vanity-metrics'>
vanity metric
</Link>
; a number that looks good on paper but isn’t action oriented. Use it
for press releases or marketing, but not to measure actual growth.
</Card>
<Card
title={
<>
Weekly growth rate of
<br />
the total number of tutees
</>
}
data={tutees}
header='Total tutees'
content={[
{
dataKey: 'total_growth',
dataLabel: 'from previous week',
rate: true,
},
{ dataKey: 'total', dataLabel: 'total tutees' },
]}
color='#9575CD'
>
The weekly growth rate of the total number of tutees. Again, this is a{' '}
<Link href='https://hbr.org/2010/02/entrepreneurs-beware-of-vanity-metrics'>
vanity metric
</Link>
; this growth rate will <i>always</i> be positive and thus will{' '}
<i>never</i> provide meaningful feedback on how growth is doing.
</Card>
<Card
title={
<>
Parents
<br />
in all time
</>
}
data={parents}
header='Total parents'
content={[
{ dataKey: 'total', dataLabel: 'total parents' },
{
dataKey: 'total_growth',
dataLabel: 'from previous week',
rate: true,
},
]}
color='#9575CD'
>
The total number of parents. This is a{' '}
<Link href='https://hbr.org/2010/02/entrepreneurs-beware-of-vanity-metrics'>
vanity metric
</Link>
; a number that looks good on paper but isn’t action oriented. Use it
for press releases or marketing, but not to measure actual growth.
</Card>
<Card
title={
<>
Weekly growth rate of
<br />
the total number of parents
</>
}
data={parents}
header='Total parents'
content={[
{
dataKey: 'total_growth',
dataLabel: 'from previous week',
rate: true,
},
{ dataKey: 'total', dataLabel: 'total parents' },
]}
color='#9575CD'
>
The weekly growth rate of the total number of parents. Again, this is
a{' '}
<Link href='https://hbr.org/2010/02/entrepreneurs-beware-of-vanity-metrics'>
vanity metric
Expand Down
5 changes: 3 additions & 2 deletions db/analytics.pgsql
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ language sql stable;

-- Users (and growth rate and total).
drop function if exists users;
create or replace function users(org_id text, time_zone text)
create or replace function users(org_id text, time_zone text, tag user_tag)
returns table (week timestamptz, users bigint, growth float, total numeric, total_growth float)
as $$
select *, (total::float / lag(total) over (order by week) - 1) total_growth
Expand All @@ -43,7 +43,8 @@ as $$
users
inner join relation_orgs on relation_orgs.user = users.id
where
relation_orgs.org = org_id
(relation_orgs.org = org_id) and
(tag is null or tag = any (users.tags))
group by week
) as _
) as _;
Expand Down
26 changes: 25 additions & 1 deletion pages/api/orgs/[id]/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export interface DBServiceHours {
export interface AnalyticsRes {
usersWithMeetings: DBUsersWithMeetings[];
users: DBUsers[];
tutors: DBUsers[];
tutees: DBUsers[];
parents: DBUsers[];
meetings: DBMeetings[];
serviceHours: DBServiceHours[];
}
Expand All @@ -58,11 +61,17 @@ export default async function analyticsAPI(
const [
{ data: usersWithMeetings, error: usersWithMeetingsError },
{ data: users, error: usersError },
{ data: tutors, error: tutorsError },
{ data: tutees, error: tuteesError },
{ data: parents, error: parentsError },
{ data: meetings, error: meetingsError },
{ data: serviceHours, error: serviceHoursError },
] = await Promise.all([
supabase.rpc<DBUsersWithMeetings>('users_with_meetings', props),
supabase.rpc<DBUsers>('users', props),
supabase.rpc<DBUsers>('users', { ...props, tag: null }),
supabase.rpc<DBUsers>('users', { ...props, tag: 'tutor' }),
supabase.rpc<DBUsers>('users', { ...props, tag: 'tutee' }),
supabase.rpc<DBUsers>('users', { ...props, tag: 'parent' }),
supabase.rpc<DBMeetings>('meetings', props),
supabase.rpc<DBServiceHours>('service_hours', props),
]);
Expand All @@ -74,6 +83,18 @@ export default async function analyticsAPI(
const msg = 'Error fetching "users" analytics';
throw new APIError(`${msg}: ${usersError?.message}`, 500);
}
if (tutorsError || !tutors) {
const msg = 'Error fetching "tutors" analytics';
throw new APIError(`${msg}: ${tutorsError?.message}`, 500);
}
if (tuteesError || !tutees) {
const msg = 'Error fetching "tutees" analytics';
throw new APIError(`${msg}: ${tuteesError?.message}`, 500);
}
if (parentsError || !parents) {
const msg = 'Error fetching "parents" analytics';
throw new APIError(`${msg}: ${parentsError?.message}`, 500);
}
if (meetingsError || !meetings) {
const msg = 'Error fetching "meetings" analytics';
throw new APIError(`${msg}: ${meetingsError?.message}`, 500);
Expand All @@ -85,6 +106,9 @@ export default async function analyticsAPI(
res.status(200).json({
usersWithMeetings,
users,
tutors,
tutees,
parents,
meetings,
serviceHours,
});
Expand Down

0 comments on commit 82e8fb3

Please sign in to comment.