Use new charts for stats page
This commit is contained in:
parent
173d2304ea
commit
2268bb9eac
|
@ -1,139 +1,77 @@
|
|||
import { Point, ResponsiveLine } from '@nivo/line'
|
||||
import clsx from 'clsx'
|
||||
import { formatPercent } from 'common/util/format'
|
||||
import { useMemo } from 'react'
|
||||
import { scaleTime, scaleLinear } from 'd3-scale'
|
||||
import { min, max } from 'lodash'
|
||||
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: {
|
||||
startDate: number
|
||||
dailyCounts: number[]
|
||||
small?: boolean
|
||||
}) {
|
||||
const { dailyCounts, startDate, small } = props
|
||||
const { width } = useWindowSize()
|
||||
import { formatPercent } from 'common/util/format'
|
||||
import { Row } from '../layout/row'
|
||||
import {
|
||||
HistoryPoint,
|
||||
SingleValueHistoryChart,
|
||||
} from 'web/components/charts/generic-charts'
|
||||
import { TooltipProps, MARGIN_X, MARGIN_Y } from 'web/components/charts/helpers'
|
||||
import { SizedContainer } from 'web/components/sized-container'
|
||||
|
||||
const dates = dailyCounts.map((_, i) =>
|
||||
dayjs(startDate).add(i, 'day').toDate()
|
||||
)
|
||||
|
||||
const points = zip(dates, dailyCounts).map(([date, betCount]) => ({
|
||||
x: date,
|
||||
y: betCount,
|
||||
const getPoints = (startDate: number, dailyValues: number[]) => {
|
||||
const startDateDayJs = dayjs(startDate)
|
||||
return dailyValues.map((y, i) => ({
|
||||
x: startDateDayJs.add(i, 'day').toDate(),
|
||||
y: y,
|
||||
}))
|
||||
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 (
|
||||
<div
|
||||
className={clsx(
|
||||
'h-[250px] w-full overflow-hidden',
|
||||
!small && 'md:h-[400px]'
|
||||
)}
|
||||
>
|
||||
<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>
|
||||
<Row className="items-center gap-2">
|
||||
<span className="font-semibold">{dayjs(d).format('MMM DD')}</span>
|
||||
<span className="text-greyscale-6">{data.y}</span>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
dailyPercent: number[]
|
||||
small?: boolean
|
||||
dailyValues: number[]
|
||||
excludeFirstDays?: number
|
||||
pct?: boolean
|
||||
}) {
|
||||
const { dailyPercent, startDate, small, excludeFirstDays } = props
|
||||
const { width } = useWindowSize()
|
||||
const { dailyValues, startDate, excludeFirstDays, pct } = props
|
||||
|
||||
const dates = dailyPercent.map((_, i) =>
|
||||
dayjs(startDate).add(i, 'day').toDate()
|
||||
const data = useMemo(
|
||||
() => getPoints(startDate, dailyValues).slice(excludeFirstDays ?? 0),
|
||||
[startDate, dailyValues, excludeFirstDays]
|
||||
)
|
||||
|
||||
const points = zip(dates, dailyPercent)
|
||||
.map(([date, percent]) => ({
|
||||
x: date,
|
||||
y: percent,
|
||||
}))
|
||||
.slice(excludeFirstDays ?? 0)
|
||||
const data = [{ id: 'Percent', data: points, color: '#11b981' }]
|
||||
|
||||
const bottomAxisTicks = width && width < 600 ? 6 : undefined
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const maxDate = max(data.map((d) => d.x))!
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const maxValue = max(data.map((d) => d.y))!
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'h-[250px] w-full overflow-hidden',
|
||||
!small && 'md:h-[400px]'
|
||||
<SizedContainer fullHeight={250} mobileHeight={250}>
|
||||
{(width, height) => (
|
||||
<SingleValueHistoryChart
|
||||
w={width}
|
||||
h={height}
|
||||
xScale={scaleTime([startDate, maxDate], [0, width - MARGIN_X])}
|
||||
yScale={scaleLinear([0, maxValue], [height - MARGIN_Y, 0])}
|
||||
data={data}
|
||||
Tooltip={pct ? DailyPercentTooltip : DailyCountTooltip}
|
||||
color="#11b981"
|
||||
pct={pct}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
<ResponsiveLine
|
||||
data={data}
|
||||
yScale={{ type: 'linear', stacked: false }}
|
||||
xScale={{
|
||||
type: 'time',
|
||||
}}
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
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>
|
||||
</SizedContainer>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
DailyCountChart,
|
||||
DailyPercentChart,
|
||||
} from 'web/components/analytics/charts'
|
||||
import { DailyChart } from 'web/components/analytics/charts'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { Spacer } from 'web/components/layout/spacer'
|
||||
import { Tabs } from 'web/components/layout/tabs'
|
||||
|
@ -96,40 +93,36 @@ export function CustomAnalytics(props: Stats) {
|
|||
{
|
||||
title: 'Daily',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={dailyActiveUsers}
|
||||
<DailyChart
|
||||
dailyValues={dailyActiveUsers}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Daily (7d avg)',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={dailyActiveUsersWeeklyAvg}
|
||||
<DailyChart
|
||||
dailyValues={dailyActiveUsersWeeklyAvg}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Weekly',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={weeklyActiveUsers}
|
||||
<DailyChart
|
||||
dailyValues={weeklyActiveUsers}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Monthly',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={monthlyActiveUsers}
|
||||
<DailyChart
|
||||
dailyValues={monthlyActiveUsers}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
@ -149,44 +142,44 @@ export function CustomAnalytics(props: Stats) {
|
|||
{
|
||||
title: 'D1',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={d1}
|
||||
<DailyChart
|
||||
dailyValues={d1}
|
||||
startDate={startDate}
|
||||
small
|
||||
excludeFirstDays={1}
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'D1 (7d avg)',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={d1WeeklyAvg}
|
||||
<DailyChart
|
||||
dailyValues={d1WeeklyAvg}
|
||||
startDate={startDate}
|
||||
small
|
||||
excludeFirstDays={7}
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'W1',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={weekOnWeekRetention}
|
||||
<DailyChart
|
||||
dailyValues={weekOnWeekRetention}
|
||||
startDate={startDate}
|
||||
small
|
||||
excludeFirstDays={14}
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'M1',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={monthlyRetention}
|
||||
<DailyChart
|
||||
dailyValues={monthlyRetention}
|
||||
startDate={startDate}
|
||||
small
|
||||
excludeFirstDays={60}
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
@ -207,33 +200,33 @@ export function CustomAnalytics(props: Stats) {
|
|||
{
|
||||
title: 'ND1',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={nd1}
|
||||
<DailyChart
|
||||
dailyValues={nd1}
|
||||
startDate={startDate}
|
||||
excludeFirstDays={1}
|
||||
small
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'ND1 (7d avg)',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={nd1WeeklyAvg}
|
||||
<DailyChart
|
||||
dailyValues={nd1WeeklyAvg}
|
||||
startDate={startDate}
|
||||
excludeFirstDays={7}
|
||||
small
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'NW1',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={nw1}
|
||||
<DailyChart
|
||||
dailyValues={nw1}
|
||||
startDate={startDate}
|
||||
excludeFirstDays={14}
|
||||
small
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
@ -249,41 +242,31 @@ export function CustomAnalytics(props: Stats) {
|
|||
{
|
||||
title: capitalize(PAST_BETS),
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={dailyBetCounts}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
<DailyChart dailyValues={dailyBetCounts} startDate={startDate} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Markets created',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={dailyContractCounts}
|
||||
<DailyChart
|
||||
dailyValues={dailyContractCounts}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Comments',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={dailyCommentCounts}
|
||||
<DailyChart
|
||||
dailyValues={dailyCommentCounts}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Signups',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={dailySignups}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
<DailyChart dailyValues={dailySignups} startDate={startDate} />
|
||||
),
|
||||
},
|
||||
]}
|
||||
|
@ -304,22 +287,22 @@ export function CustomAnalytics(props: Stats) {
|
|||
{
|
||||
title: 'Daily',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={dailyActivationRate}
|
||||
<DailyChart
|
||||
dailyValues={dailyActivationRate}
|
||||
startDate={startDate}
|
||||
excludeFirstDays={1}
|
||||
small
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Daily (7d avg)',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={dailyActivationRateWeeklyAvg}
|
||||
<DailyChart
|
||||
dailyValues={dailyActivationRateWeeklyAvg}
|
||||
startDate={startDate}
|
||||
excludeFirstDays={7}
|
||||
small
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
@ -335,33 +318,33 @@ export function CustomAnalytics(props: Stats) {
|
|||
{
|
||||
title: 'Daily / Weekly',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={dailyDividedByWeekly}
|
||||
<DailyChart
|
||||
dailyValues={dailyDividedByWeekly}
|
||||
startDate={startDate}
|
||||
small
|
||||
excludeFirstDays={7}
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Daily / Monthly',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={dailyDividedByMonthly}
|
||||
<DailyChart
|
||||
dailyValues={dailyDividedByMonthly}
|
||||
startDate={startDate}
|
||||
small
|
||||
excludeFirstDays={30}
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Weekly / Monthly',
|
||||
content: (
|
||||
<DailyPercentChart
|
||||
dailyPercent={weeklyDividedByMonthly}
|
||||
<DailyChart
|
||||
dailyValues={weeklyDividedByMonthly}
|
||||
startDate={startDate}
|
||||
small
|
||||
excludeFirstDays={30}
|
||||
pct
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
@ -380,31 +363,19 @@ export function CustomAnalytics(props: Stats) {
|
|||
{
|
||||
title: 'Daily',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={manaBet.daily}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
<DailyChart dailyValues={manaBet.daily} startDate={startDate} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Weekly',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={manaBet.weekly}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
<DailyChart dailyValues={manaBet.weekly} startDate={startDate} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Monthly',
|
||||
content: (
|
||||
<DailyCountChart
|
||||
dailyCounts={manaBet.monthly}
|
||||
startDate={startDate}
|
||||
small
|
||||
/>
|
||||
<DailyChart dailyValues={manaBet.monthly} startDate={startDate} />
|
||||
),
|
||||
},
|
||||
]}
|
||||
|
|
Loading…
Reference in New Issue
Block a user