diff --git a/web/components/analytics/charts.tsx b/web/components/analytics/charts.tsx new file mode 100644 index 00000000..c628c071 --- /dev/null +++ b/web/components/analytics/charts.tsx @@ -0,0 +1,48 @@ +import { ResponsiveLine } from '@nivo/line' +import dayjs from 'dayjs' +import _ from 'lodash' +import { useWindowSize } from '../../hooks/use-window-size' + +export function DailyCountChart(props: { + startDate: number + dailyCounts: number[] +}) { + const { dailyCounts, startDate } = props + const { width } = useWindowSize() + + const dates = dailyCounts.map((_, i) => + dayjs(startDate).add(i, 'day').toDate() + ) + + const points = _.zip(dates, dailyCounts).map(([date, betCount]) => ({ + x: date, + y: betCount, + })) + const data = [{ id: 'Yes', data: points, color: '#11b981' }] + + return ( +
= 800 ? 400 : 250 }} + > + dayjs(date).format('MMM DD'), + }} + colors={{ datum: 'color' }} + pointSize={10} + pointBorderWidth={1} + pointBorderColor="#fff" + enableSlices="x" + enableGridX={!!width && width >= 800} + enableArea + margin={{ top: 20, right: 28, bottom: 22, left: 40 }} + /> +
+ ) +} diff --git a/web/lib/firebase/bets.ts b/web/lib/firebase/bets.ts index f03b293b..4056e114 100644 --- a/web/lib/firebase/bets.ts +++ b/web/lib/firebase/bets.ts @@ -103,3 +103,24 @@ export function withoutAnteBets(contract: Contract, bets?: Bet[]) { return bets?.filter((bet) => !bet.isAnte) ?? [] } + +const getBetsQuery = (startTime: number, endTime: number) => + query( + collectionGroup(db, 'bets'), + where('createdTime', '>=', startTime), + where('createdTime', '<', endTime), + orderBy('createdTime', 'asc') + ) + +export async function getDailyBets(startTime: number, numberOfDays: number) { + const query = getBetsQuery(startTime, startTime + DAY_IN_MS * numberOfDays) + const bets = await getValues(query) + + const betsByDay = _.range(0, numberOfDays).map(() => [] as Bet[]) + for (const bet of bets) { + const dayIndex = Math.floor((bet.createdTime - startTime) / DAY_IN_MS) + betsByDay[dayIndex].push(bet) + } + + return betsByDay +} diff --git a/web/lib/firebase/contracts.ts b/web/lib/firebase/contracts.ts index eb1b65e1..e75a34fb 100644 --- a/web/lib/firebase/contracts.ts +++ b/web/lib/firebase/contracts.ts @@ -209,3 +209,32 @@ export async function getClosingSoonContracts() { (contract) => contract.closeTime ) } + +const getContractsQuery = (startTime: number, endTime: number) => + query( + collection(db, 'contracts'), + where('createdTime', '>=', startTime), + where('createdTime', '<', endTime), + orderBy('createdTime', 'asc') + ) + +const DAY_IN_MS = 24 * 60 * 60 * 1000 + +export async function getDailyContracts( + startTime: number, + numberOfDays: number +) { + const query = getContractsQuery( + startTime, + startTime + DAY_IN_MS * numberOfDays + ) + const contracts = await getValues(query) + + const contractsByDay = _.range(0, numberOfDays).map(() => [] as Contract[]) + for (const contract of contracts) { + const dayIndex = Math.floor((contract.createdTime - startTime) / DAY_IN_MS) + contractsByDay[dayIndex].push(contract) + } + + return contractsByDay +} diff --git a/web/pages/analytics.tsx b/web/pages/analytics.tsx index 7f905a46..e4ce95fc 100644 --- a/web/pages/analytics.tsx +++ b/web/pages/analytics.tsx @@ -1,17 +1,81 @@ +import dayjs from 'dayjs' +import _ from 'lodash' +import { DailyCountChart } from '../components/analytics/charts' +import { Col } from '../components/layout/col' import { Page } from '../components/page' +import { Title } from '../components/title' +import { getDailyBets } from '../lib/firebase/bets' +import { getDailyContracts } from '../lib/firebase/contracts' -export default function Analytics() { - // Edit dashboard at https://datastudio.google.com/u/0/reporting/faeaf3a4-c8da-4275-b157-98dad017d305/page/Gg3/edit +export async function getStaticProps() { + const numberOfDays = 80 + const today = dayjs(dayjs().format('YYYY-MM-DD')) + const startDate = today.subtract(numberOfDays, 'day') + + const dailyBets = await getDailyBets(startDate.valueOf(), numberOfDays) + const dailyBetCounts = dailyBets.map((bets) => bets.length) + + const dailyContracts = await getDailyContracts( + startDate.valueOf(), + numberOfDays + ) + const dailyContractCounts = dailyContracts.map( + (contracts) => contracts.length + ) + + return { + props: { + startDate: startDate.valueOf(), + dailyBetCounts, + dailyContractCounts, + }, + revalidate: 12 * 60 * 60, // regenerate after half a day + } +} + +export default function Analytics(props: { + startDate: number + dailyBetCounts: number[] + dailyContractCounts: number[] +}) { return ( - + + ) } + +function CustomAnalytics(props: { + startDate: number + dailyBetCounts: number[] + dailyContractCounts: number[] +}) { + const { startDate, dailyBetCounts, dailyContractCounts } = props + return ( + + + <DailyCountChart dailyCounts={dailyBetCounts} startDate={startDate} /> + + <Title text="Markets count" /> + <DailyCountChart + dailyCounts={dailyContractCounts} + startDate={startDate} + /> + </Col> + ) +} + +function FirebaseAnalytics() { + // Edit dashboard at https://datastudio.google.com/u/0/reporting/faeaf3a4-c8da-4275-b157-98dad017d305/page/Gg3/edit + return ( + <iframe + className="w-full" + height={2200} + src="https://datastudio.google.com/embed/reporting/faeaf3a4-c8da-4275-b157-98dad017d305/page/Gg3" + frameBorder="0" + style={{ border: 0 }} + allowFullScreen + /> + ) +}