Skip to content

Commit

Permalink
Add daily active user viewers
Browse files Browse the repository at this point in the history
  • Loading branch information
IanPhilips committed Jan 27, 2025
1 parent fc48446 commit 522737a
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 8 deletions.
46 changes: 41 additions & 5 deletions backend/scheduler/src/jobs/update-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ async function getDailyBets(
return bets as { day: string; values: StatBet[] }[]
}

async function getDailyViewers(
pg: SupabaseDirectClient,
start: string,
end: string
) {
const viewers = await pg.manyOrNone(
`select
date_trunc('day', ts at time zone 'america/los_angeles')::date as day,
count(distinct(data->>'deviceId')) as viewer_count
from user_events
where
ts >= date_to_midnight_pt($1)
and ts < date_to_midnight_pt($2)
group by day
order by day asc`,
[start, end]
)

return viewers as { day: string; viewer_count: number }[]
}

async function getDailyComments(
pg: SupabaseDirectClient,
start: string,
Expand Down Expand Up @@ -241,13 +262,28 @@ export const updateActivityStats = async (
.format('YYYY-MM-DD')

log(`Fetching data for activity stats between ${startWithBuffer} and ${end}`)
const [dailyBets, dailyContracts, dailyComments] = await Promise.all([
getDailyBets(pg, startWithBuffer, end),
getDailyContracts(pg, startWithBuffer, end),
getDailyComments(pg, startWithBuffer, end),
])
const [dailyBets, dailyContracts, dailyComments, dailyViewers] =
await Promise.all([
getDailyBets(pg, startWithBuffer, end),
getDailyContracts(pg, startWithBuffer, end),
getDailyComments(pg, startWithBuffer, end),
getDailyViewers(pg, startWithBuffer, end),
])
logMemory()

log('upsert viewer counts')
await bulkUpsertStats(
pg,
dailyViewers.map((viewers, i) => ({
start_date: viewers.day,
dav: viewers.viewer_count,
wav: average(dailyViewers.slice(i - 6, i + 1).map((v) => v.viewer_count)),
mav: average(
dailyViewers.slice(i - 29, i + 1).map((v) => v.viewer_count)
),
}))
)

log('upsert bets counts and totals')
await bulkUpsertStats(
pg,
Expand Down
5 changes: 4 additions & 1 deletion backend/supabase/daily_stats.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ create table if not exists
start_date date primary key not null,
topic_daus jsonb,
w1 numeric,
wau numeric
wau numeric,
dav numeric,
mav numeric,
wav numeric
);

-- Row Level Security
Expand Down
9 changes: 9 additions & 0 deletions common/src/supabase/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,9 @@ export type Database = {
signups_real: number | null
start_date: string
w1: number | null
dav: number | null
wav: number | null
mav: number | null
wau: number | null
topic_daus: Json | null
cash_bet_count: number | null
Expand Down Expand Up @@ -604,6 +607,9 @@ export type Database = {
signups_real?: number | null
start_date: string
w1?: number | null
dav?: number | null
wav?: number | null
mav?: number | null
wau?: number | null
topic_daus?: Json | null
cash_bet_count?: number | null
Expand Down Expand Up @@ -633,6 +639,9 @@ export type Database = {
engaged_users?: number | null
feed_conversion?: number | null
m1?: number | null
dav?: number | null
wav?: number | null
mav?: number | null
mau?: number | null
nd1?: number | null
nw1?: number | null
Expand Down
2 changes: 1 addition & 1 deletion web/lib/supabase/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const getStats = async (startDate?: string) => {
.from('daily_stats')
.select()
.order('start_date')
.gte('start_date', startDate ?? '2022-01-01')
.gte('start_date', startDate ?? '2024-01-01')
)
return data

Expand Down
44 changes: 43 additions & 1 deletion web/pages/stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,16 +196,58 @@ export function CustomAnalytics(props: {
.map((row) => row.dau)
.filter((val): val is number => val != null)
)
const avgDAVlastWeek = average(
stats
.slice(-7)
.map((row) => row.dav)
.filter((val): val is number => val != null)
)
const last30dSales = sum(stats.slice(-30).map((row) => row.sales || 0))

const isAdmin = useAdmin()

return (
<Col className="px-4 sm:pl-6 sm:pr-16">
<div className="flex items-start justify-between">
<Title>Active traders</Title>
<Title>Active users</Title>
<Button onClick={() => getStats().then(setStats)}>Reload All</Button>
</div>
<p className="text-ink-500">
An active user is a user who has taken any action on the site.
</p>
<div className="text-ink-500 mt-2">
<b>{formatLargeNumber(current.dav ?? 0)}</b> yesterday;{' '}
{formatLargeNumber(avgDAVlastWeek)} avg last week
</div>
<Spacer h={4} />
<Tabs
className="mb-4"
defaultIndex={1}
tabs={[
{
title: 'Daily',
content: <DailyChart values={dataFor('dav')} />,
},
{
title: 'Daily (7d avg)',
content: (
<DailyChart values={rollingAvg(dataFor('dav'), 7).map(round)} />
),
},
{
title: 'Weekly',
content: <DailyChart values={dataFor('wav')} />,
},
{
title: 'Monthly',
content: <DailyChart values={dataFor('mav')} />,
},
]}
/>
<Spacer h={8} />
<div className="flex items-start justify-between">
<Title>Active traders</Title>
</div>
<p className="text-ink-500">
An active trader is a user who has traded in, commented on, or created a
question.
Expand Down

0 comments on commit 522737a

Please sign in to comment.