diff --git a/common/stats.ts b/common/stats.ts index 9221e10e..8ddf3466 100644 --- a/common/stats.ts +++ b/common/stats.ts @@ -15,12 +15,8 @@ export type Stats = { dailySignups: number[] weekOnWeekRetention: number[] monthlyRetention: number[] - weeklyActivationRate: number[] - topTenthActions: { - daily: number[] - weekly: number[] - monthly: number[] - } + dailyActivationRate: number[] + dailyActivationRateWeeklyAvg: number[] manaBet: { daily: number[] weekly: number[] diff --git a/functions/src/update-stats.ts b/functions/src/update-stats.ts index 98b03931..1434c4f2 100644 --- a/functions/src/update-stats.ts +++ b/functions/src/update-stats.ts @@ -6,7 +6,7 @@ import * as timezone from 'dayjs/plugin/timezone' dayjs.extend(utc) dayjs.extend(timezone) -import { concat, countBy, sortBy, range, zip, uniq, sum, sumBy } from 'lodash' +import { range, zip, uniq, sum, sumBy } from 'lodash' import { getValues, log, logMemory } from './utils' import { Bet } from '../../common/bet' import { Contract } from '../../common/contract' @@ -278,51 +278,20 @@ export const updateStatsCore = async () => { firstBetDict[bet.userId] = i } } - const weeklyActivationRate = dailyNewUsers.map((_, i) => { - const start = Math.max(0, i - 6) - const end = i - let activatedCount = 0 - let newUsers = 0 - for (let j = start; j <= end; j++) { - const userIds = dailyNewUsers[j].map((user) => user.id) - newUsers += userIds.length - for (const userId of userIds) { - const dayIndex = firstBetDict[userId] - if (dayIndex !== undefined && dayIndex <= end) { - activatedCount++ - } - } - } - return activatedCount / (newUsers || 1) + const dailyActivationRate = dailyNewUsers.map((newUsers, i) => { + const activedCount = sumBy(newUsers, (user) => { + const firstBet = firstBetDict[user.id] + return firstBet === i ? 1 : 0 + }) + return activedCount / newUsers.length + }) + const dailyActivationRateWeeklyAvg = dailyActivationRate.map((_, i) => { + const start = Math.max(0, i - 6) + const end = i + 1 + return average(dailyActivationRate.slice(start, end)) }) - const dailySignups = dailyNewUsers.map((users) => users.length) - const dailyTopTenthActions = zip( - dailyContracts, - dailyBets, - dailyComments - ).map(([contracts, bets, comments]) => { - const userIds = concat( - contracts?.map((c) => c.creatorId) ?? [], - bets?.map((b) => b.userId) ?? [], - comments?.map((c) => c.userId) ?? [] - ) - const counts = Object.values(countBy(userIds)) - const sortedCounts = sortBy(counts, (count) => count).reverse() - if (sortedCounts.length === 0) return 0 - const tenthPercentile = sortedCounts[Math.floor(sortedCounts.length * 0.1)] - return tenthPercentile - }) - const weeklyTopTenthActions = dailyTopTenthActions.map((_, i) => { - const start = Math.max(0, i - 6) - const end = i + 1 - return average(dailyTopTenthActions.slice(start, end)) - }) - const monthlyTopTenthActions = dailyTopTenthActions.map((_, i) => { - const start = Math.max(0, i - 29) - const end = i + 1 - return average(dailyTopTenthActions.slice(start, end)) - }) + const dailySignups = dailyNewUsers.map((users) => users.length) // Total mana divided by 100. const dailyManaBet = dailyBets.map((bets) => { @@ -360,13 +329,9 @@ export const updateStatsCore = async () => { dailyCommentCounts, dailySignups, weekOnWeekRetention, - weeklyActivationRate, + dailyActivationRate, + dailyActivationRateWeeklyAvg, monthlyRetention, - topTenthActions: { - daily: dailyTopTenthActions, - weekly: weeklyTopTenthActions, - monthly: monthlyTopTenthActions, - }, manaBet: { daily: dailyManaBet, weekly: weeklyManaBet, diff --git a/web/pages/stats.tsx b/web/pages/stats.tsx index 67bcbb56..40847470 100644 --- a/web/pages/stats.tsx +++ b/web/pages/stats.tsx @@ -64,30 +64,20 @@ export function CustomAnalytics(props: Stats) { dailySignups, weekOnWeekRetention, monthlyRetention, - weeklyActivationRate, - topTenthActions, + dailyActivationRate, + dailyActivationRateWeeklyAvg, manaBet, } = props - const dailyDividedByWeekly = dailyActiveUsers - .map((dailyActive, i) => - Math.round((100 * dailyActive) / weeklyActiveUsers[i]) - ) - .slice(7) - - const dailyDividedByMonthly = dailyActiveUsers - .map((dailyActive, i) => - Math.round((100 * dailyActive) / monthlyActiveUsers[i]) - ) - .slice(7) - - const weeklyDividedByMonthly = weeklyActiveUsers - .map((weeklyActive, i) => - Math.round((100 * weeklyActive) / monthlyActiveUsers[i]) - ) - .slice(7) - - const oneWeekLaterDate = startDate + 7 * 24 * 60 * 60 * 1000 + const dailyDividedByWeekly = dailyActiveUsers.map( + (dailyActive, i) => dailyActive / weeklyActiveUsers[i] + ) + const dailyDividedByMonthly = dailyActiveUsers.map( + (dailyActive, i) => dailyActive / monthlyActiveUsers[i] + ) + const weeklyDividedByMonthly = weeklyActiveUsers.map( + (weeklyActive, i) => weeklyActive / monthlyActiveUsers[i] + ) return ( @@ -180,7 +170,7 @@ export function CustomAnalytics(props: Stats) { content: ( @@ -191,7 +181,7 @@ export function CustomAnalytics(props: Stats) { content: ( @@ -296,14 +286,38 @@ export function CustomAnalytics(props: Stats) { - + <Title text="Activation rate" /> <p className="text-gray-500"> - Out of all new users this week, how many placed at least one bet? + Out of all new users, how many placed at least one bet? </p> - <DailyPercentChart - dailyPercent={weeklyActivationRate.slice(7)} - startDate={oneWeekLaterDate} - small + <Spacer h={4} /> + + <Tabs + defaultIndex={1} + tabs={[ + { + title: 'Daily', + content: ( + <DailyPercentChart + dailyPercent={dailyActivationRate} + startDate={startDate} + excludeFirstDays={1} + small + /> + ), + }, + { + title: 'Daily (7d avg)', + content: ( + <DailyPercentChart + dailyPercent={dailyActivationRateWeeklyAvg} + startDate={startDate} + excludeFirstDays={7} + small + /> + ), + }, + ]} /> <Spacer h={8} /> @@ -316,7 +330,7 @@ export function CustomAnalytics(props: Stats) { content: ( <DailyPercentChart dailyPercent={dailyDividedByWeekly} - startDate={oneWeekLaterDate} + startDate={startDate} small excludeFirstDays={7} /> @@ -327,7 +341,7 @@ export function CustomAnalytics(props: Stats) { content: ( <DailyPercentChart dailyPercent={dailyDividedByMonthly} - startDate={oneWeekLaterDate} + startDate={startDate} small excludeFirstDays={30} /> @@ -338,7 +352,7 @@ export function CustomAnalytics(props: Stats) { content: ( <DailyPercentChart dailyPercent={weeklyDividedByMonthly} - startDate={oneWeekLaterDate} + startDate={startDate} small excludeFirstDays={30} /> @@ -348,47 +362,6 @@ export function CustomAnalytics(props: Stats) { /> <Spacer h={8} /> - <Title text="Action count of top tenth" /> - <p className="text-gray-500"> - Number of actions (bets, comments, markets created) taken by the tenth - percentile of top users. - </p> - <Tabs - defaultIndex={1} - tabs={[ - { - title: 'Daily', - content: ( - <DailyCountChart - dailyCounts={topTenthActions.daily} - startDate={startDate} - small - /> - ), - }, - { - title: 'Weekly', - content: ( - <DailyCountChart - dailyCounts={topTenthActions.weekly} - startDate={startDate} - small - /> - ), - }, - { - title: 'Monthly', - content: ( - <DailyCountChart - dailyCounts={topTenthActions.monthly} - startDate={startDate} - small - /> - ), - }, - ]} - /> - <Title text="Total mana bet" /> <p className="text-gray-500"> Sum of bet amounts. (Divided by 100 to be more readable.) @@ -428,6 +401,7 @@ export function CustomAnalytics(props: Stats) { }, ]} /> + <Spacer h={8} /> </Col> ) }