Use new charts for stats page

This commit is contained in:
Marshall Polaris 2022-10-02 15:21:03 -07:00
parent 173d2304ea
commit 2268bb9eac
2 changed files with 113 additions and 204 deletions

View File

@ -1,139 +1,77 @@
import { Point, ResponsiveLine } from '@nivo/line' import { useMemo } from 'react'
import clsx from 'clsx' import { scaleTime, scaleLinear } from 'd3-scale'
import { formatPercent } from 'common/util/format' import { min, max } from 'lodash'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { zip } from 'lodash'
import { useWindowSize } from 'web/hooks/use-window-size'
import { Col } from '../layout/col'
export function DailyCountChart(props: { import { formatPercent } from 'common/util/format'
startDate: number import { Row } from '../layout/row'
dailyCounts: number[] import {
small?: boolean HistoryPoint,
}) { SingleValueHistoryChart,
const { dailyCounts, startDate, small } = props } from 'web/components/charts/generic-charts'
const { width } = useWindowSize() import { TooltipProps, MARGIN_X, MARGIN_Y } from 'web/components/charts/helpers'
import { SizedContainer } from 'web/components/sized-container'
const dates = dailyCounts.map((_, i) => const getPoints = (startDate: number, dailyValues: number[]) => {
dayjs(startDate).add(i, 'day').toDate() const startDateDayJs = dayjs(startDate)
) return dailyValues.map((y, i) => ({
x: startDateDayJs.add(i, 'day').toDate(),
const points = zip(dates, dailyCounts).map(([date, betCount]) => ({ y: y,
x: date,
y: betCount,
})) }))
const data = [{ id: 'Count', data: points, color: '#11b981' }] }
const bottomAxisTicks = width && width < 600 ? 6 : undefined
const DailyCountTooltip = (props: TooltipProps<Date, HistoryPoint>) => {
const { data, mouseX, xScale } = props
const d = xScale.invert(mouseX)
return ( return (
<div <Row className="items-center gap-2">
className={clsx( <span className="font-semibold">{dayjs(d).format('MMM DD')}</span>
'h-[250px] w-full overflow-hidden', <span className="text-greyscale-6">{data.y}</span>
!small && 'md:h-[400px]' </Row>
)}
>
<ResponsiveLine
data={data}
yScale={{ type: 'linear', stacked: false }}
xScale={{
type: 'time',
}}
axisBottom={{
tickValues: bottomAxisTicks,
format: (date) => dayjs(date).format('MMM DD'),
}}
colors={{ datum: 'color' }}
pointSize={0}
pointBorderWidth={1}
pointBorderColor="#fff"
enableSlices="x"
enableGridX={!!width && width >= 800}
enableArea
margin={{ top: 20, right: 28, bottom: 22, left: 40 }}
sliceTooltip={({ slice }) => {
const point = slice.points[0]
return <Tooltip point={point} />
}}
/>
</div>
) )
} }
export function DailyPercentChart(props: { const DailyPercentTooltip = (props: TooltipProps<Date, HistoryPoint>) => {
const { data, mouseX, xScale } = props
const d = xScale.invert(mouseX)
return (
<Row className="items-center gap-2">
<span className="font-semibold">{dayjs(d).format('MMM DD')}</span>
<span className="text-greyscale-6">{formatPercent(data.y)}</span>
</Row>
)
}
export function DailyChart(props: {
startDate: number startDate: number
dailyPercent: number[] dailyValues: number[]
small?: boolean
excludeFirstDays?: number excludeFirstDays?: number
pct?: boolean
}) { }) {
const { dailyPercent, startDate, small, excludeFirstDays } = props const { dailyValues, startDate, excludeFirstDays, pct } = props
const { width } = useWindowSize()
const dates = dailyPercent.map((_, i) => const data = useMemo(
dayjs(startDate).add(i, 'day').toDate() () => getPoints(startDate, dailyValues).slice(excludeFirstDays ?? 0),
[startDate, dailyValues, excludeFirstDays]
) )
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const points = zip(dates, dailyPercent) const maxDate = max(data.map((d) => d.x))!
.map(([date, percent]) => ({ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
x: date, const maxValue = max(data.map((d) => d.y))!
y: percent,
}))
.slice(excludeFirstDays ?? 0)
const data = [{ id: 'Percent', data: points, color: '#11b981' }]
const bottomAxisTicks = width && width < 600 ? 6 : undefined
return ( return (
<div <SizedContainer fullHeight={250} mobileHeight={250}>
className={clsx( {(width, height) => (
'h-[250px] w-full overflow-hidden', <SingleValueHistoryChart
!small && 'md:h-[400px]' w={width}
)} h={height}
> xScale={scaleTime([startDate, maxDate], [0, width - MARGIN_X])}
<ResponsiveLine yScale={scaleLinear([0, maxValue], [height - MARGIN_Y, 0])}
data={data} data={data}
yScale={{ type: 'linear', stacked: false }} Tooltip={pct ? DailyPercentTooltip : DailyCountTooltip}
xScale={{ color="#11b981"
type: 'time', pct={pct}
}}
axisLeft={{
format: formatPercent,
}}
axisBottom={{
tickValues: bottomAxisTicks,
format: (date) => dayjs(date).format('MMM DD'),
}}
colors={{ datum: 'color' }}
pointSize={0}
pointBorderWidth={1}
pointBorderColor="#fff"
enableSlices="x"
enableGridX={!!width && width >= 800}
enableArea
margin={{ top: 20, right: 28, bottom: 22, left: 40 }}
sliceTooltip={({ slice }) => {
const point = slice.points[0]
return <Tooltip point={point} isPercent />
}}
/> />
</div> )}
) </SizedContainer>
}
function Tooltip(props: { point: Point; isPercent?: boolean }) {
const { point, isPercent } = props
return (
<Col className="border border-gray-300 bg-white py-2 px-3">
<div
className="pb-1"
style={{
color: point.serieColor,
}}
>
<strong>{point.serieId}</strong>{' '}
{isPercent ? formatPercent(+point.data.y) : Math.round(+point.data.y)}
</div>
<div>{dayjs(point.data.x).format('MMM DD')}</div>
</Col>
) )
} }

View File

@ -1,8 +1,5 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { import { DailyChart } from 'web/components/analytics/charts'
DailyCountChart,
DailyPercentChart,
} from 'web/components/analytics/charts'
import { Col } from 'web/components/layout/col' import { Col } from 'web/components/layout/col'
import { Spacer } from 'web/components/layout/spacer' import { Spacer } from 'web/components/layout/spacer'
import { Tabs } from 'web/components/layout/tabs' import { Tabs } from 'web/components/layout/tabs'
@ -96,40 +93,36 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'Daily', title: 'Daily',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={dailyActiveUsers} dailyValues={dailyActiveUsers}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Daily (7d avg)', title: 'Daily (7d avg)',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={dailyActiveUsersWeeklyAvg} dailyValues={dailyActiveUsersWeeklyAvg}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Weekly', title: 'Weekly',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={weeklyActiveUsers} dailyValues={weeklyActiveUsers}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Monthly', title: 'Monthly',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={monthlyActiveUsers} dailyValues={monthlyActiveUsers}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
@ -149,44 +142,44 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'D1', title: 'D1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={d1} dailyValues={d1}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={1} excludeFirstDays={1}
pct
/> />
), ),
}, },
{ {
title: 'D1 (7d avg)', title: 'D1 (7d avg)',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={d1WeeklyAvg} dailyValues={d1WeeklyAvg}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={7} excludeFirstDays={7}
pct
/> />
), ),
}, },
{ {
title: 'W1', title: 'W1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={weekOnWeekRetention} dailyValues={weekOnWeekRetention}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={14} excludeFirstDays={14}
pct
/> />
), ),
}, },
{ {
title: 'M1', title: 'M1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={monthlyRetention} dailyValues={monthlyRetention}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={60} excludeFirstDays={60}
pct
/> />
), ),
}, },
@ -207,33 +200,33 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'ND1', title: 'ND1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={nd1} dailyValues={nd1}
startDate={startDate} startDate={startDate}
excludeFirstDays={1} excludeFirstDays={1}
small pct
/> />
), ),
}, },
{ {
title: 'ND1 (7d avg)', title: 'ND1 (7d avg)',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={nd1WeeklyAvg} dailyValues={nd1WeeklyAvg}
startDate={startDate} startDate={startDate}
excludeFirstDays={7} excludeFirstDays={7}
small pct
/> />
), ),
}, },
{ {
title: 'NW1', title: 'NW1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={nw1} dailyValues={nw1}
startDate={startDate} startDate={startDate}
excludeFirstDays={14} excludeFirstDays={14}
small pct
/> />
), ),
}, },
@ -249,41 +242,31 @@ export function CustomAnalytics(props: Stats) {
{ {
title: capitalize(PAST_BETS), title: capitalize(PAST_BETS),
content: ( content: (
<DailyCountChart <DailyChart dailyValues={dailyBetCounts} startDate={startDate} />
dailyCounts={dailyBetCounts}
startDate={startDate}
small
/>
), ),
}, },
{ {
title: 'Markets created', title: 'Markets created',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={dailyContractCounts} dailyValues={dailyContractCounts}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Comments', title: 'Comments',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={dailyCommentCounts} dailyValues={dailyCommentCounts}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Signups', title: 'Signups',
content: ( content: (
<DailyCountChart <DailyChart dailyValues={dailySignups} startDate={startDate} />
dailyCounts={dailySignups}
startDate={startDate}
small
/>
), ),
}, },
]} ]}
@ -304,22 +287,22 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'Daily', title: 'Daily',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={dailyActivationRate} dailyValues={dailyActivationRate}
startDate={startDate} startDate={startDate}
excludeFirstDays={1} excludeFirstDays={1}
small pct
/> />
), ),
}, },
{ {
title: 'Daily (7d avg)', title: 'Daily (7d avg)',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={dailyActivationRateWeeklyAvg} dailyValues={dailyActivationRateWeeklyAvg}
startDate={startDate} startDate={startDate}
excludeFirstDays={7} excludeFirstDays={7}
small pct
/> />
), ),
}, },
@ -335,33 +318,33 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'Daily / Weekly', title: 'Daily / Weekly',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={dailyDividedByWeekly} dailyValues={dailyDividedByWeekly}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={7} excludeFirstDays={7}
pct
/> />
), ),
}, },
{ {
title: 'Daily / Monthly', title: 'Daily / Monthly',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={dailyDividedByMonthly} dailyValues={dailyDividedByMonthly}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={30} excludeFirstDays={30}
pct
/> />
), ),
}, },
{ {
title: 'Weekly / Monthly', title: 'Weekly / Monthly',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={weeklyDividedByMonthly} dailyValues={weeklyDividedByMonthly}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={30} excludeFirstDays={30}
pct
/> />
), ),
}, },
@ -380,31 +363,19 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'Daily', title: 'Daily',
content: ( content: (
<DailyCountChart <DailyChart dailyValues={manaBet.daily} startDate={startDate} />
dailyCounts={manaBet.daily}
startDate={startDate}
small
/>
), ),
}, },
{ {
title: 'Weekly', title: 'Weekly',
content: ( content: (
<DailyCountChart <DailyChart dailyValues={manaBet.weekly} startDate={startDate} />
dailyCounts={manaBet.weekly}
startDate={startDate}
small
/>
), ),
}, },
{ {
title: 'Monthly', title: 'Monthly',
content: ( content: (
<DailyCountChart <DailyChart dailyValues={manaBet.monthly} startDate={startDate} />
dailyCounts={manaBet.monthly}
startDate={startDate}
small
/>
), ),
}, },
]} ]}