diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index afb5bfd2..bcb18b47 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -64,7 +64,7 @@ export function BetPanel(props: { contract: Contract; className?: string }) { return ( diff --git a/web/components/contract-overview.tsx b/web/components/contract-overview.tsx index 41fea05b..659e62f9 100644 --- a/web/components/contract-overview.tsx +++ b/web/components/contract-overview.tsx @@ -1,51 +1,22 @@ import React from 'react' -import { Line } from 'react-chartjs-2' -import { - CategoryScale, - Chart, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend, -} from 'chart.js' import { Contract } from '../lib/firebase/contracts' import { Col } from './layout/col' import { Row } from './layout/row' import { Spacer } from './layout/spacer' import { formatWithCommas } from '../lib/util/format' +import { ContractProbGraph } from './contract-prob-graph' -// Auto import doesn't work for some reason... -// So we manually register ChartJS components instead: -Chart.register( - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend -) -const chartData = { - labels: Array.from({ length: 0 }, (_, i) => i + 1), - datasets: [ - { - label: 'Implied probability', - data: [], - borderColor: 'rgb(75, 192, 192)', - }, - ], -} - -export const ContractOverview = (props: { contract: Contract }) => { - const { contract } = props +export const ContractOverview = (props: { + contract: Contract + className?: string +}) => { + const { contract, className } = props const { pot, seedAmounts } = contract const volume = pot.YES + pot.NO - seedAmounts.YES - seedAmounts.NO return ( - +
{contract.question}
@@ -53,12 +24,14 @@ export const ContractOverview = (props: { contract: Contract }) => {
Dec 9
-
{formatWithCommas(volume)} volume
+
+ {formatWithCommas(volume)} volume +
- + diff --git a/web/components/contract-prob-graph.tsx b/web/components/contract-prob-graph.tsx new file mode 100644 index 00000000..ad05ec6d --- /dev/null +++ b/web/components/contract-prob-graph.tsx @@ -0,0 +1,52 @@ +import { Line } from 'react-chartjs-2' +import { + CategoryScale, + Chart, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, +} from 'chart.js' + +import { useBets } from '../hooks/use-bets' +import { Contract } from '../lib/firebase/contracts' + +// Auto import doesn't work for some reason... +// So we manually register ChartJS components instead: +Chart.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend +) + +export function ContractProbGraph(props: { contract: Contract }) { + const { contract } = props + const { id, seedAmounts } = contract + + let bets = useBets(id) + if (bets === 'loading') bets = [] + + const seedProb = + seedAmounts.YES ** 2 / (seedAmounts.YES ** 2 + seedAmounts.NO ** 2) + + const probs = [seedProb, ...bets.map((bet) => bet.probAfter)] + + const chartData = { + labels: Array.from({ length: probs.length }, (_, i) => i + 1), + datasets: [ + { + label: 'Implied probability', + data: probs, + borderColor: 'rgb(75, 192, 192)', + }, + ], + } + + return +} diff --git a/web/hooks/use-bets.ts b/web/hooks/use-bets.ts new file mode 100644 index 00000000..0a35ba53 --- /dev/null +++ b/web/hooks/use-bets.ts @@ -0,0 +1,12 @@ +import { useEffect, useState } from 'react' +import { Bet, listenForBets } from '../lib/firebase/bets' + +export const useBets = (contractId: string) => { + const [bets, setBets] = useState('loading') + + useEffect(() => { + if (contractId) return listenForBets(contractId, setBets) + }, [contractId]) + + return bets +} diff --git a/web/lib/firebase/bets.ts b/web/lib/firebase/bets.ts index dbfd6f2b..79036c44 100644 --- a/web/lib/firebase/bets.ts +++ b/web/lib/firebase/bets.ts @@ -1,22 +1,32 @@ -import { doc, setDoc } from 'firebase/firestore' +import { collection, onSnapshot } from 'firebase/firestore' import { db } from './init' export type Bet = { id: string userId: string contractId: string - - amount: number // Amount of USD bid + amount: number // Amount of bet outcome: 'YES' | 'NO' // Chosen outcome - - // Calculate and replace these on server? - createdTime: number dpmWeight: number // Dynamic Parimutuel weight + probBefore: number + probAverage: number + probAfter: number + createdTime: number } -// Push bet to Firestore -// TODO: Should bets be subcollections under its contract? -export async function saveBet(bet: Bet) { - const docRef = doc(db, 'contracts', bet.contractId, 'bets', bet.id) - await setDoc(docRef, bet) +function getBetsCollection(contractId: string) { + return collection(db, 'contracts', contractId, 'bets') +} + +export function listenForBets( + contractId: string, + setBets: (bets: Bet[]) => void +) { + return onSnapshot(getBetsCollection(contractId), (snap) => { + const bets = snap.docs.map((doc) => doc.data() as Bet) + + bets.sort((bet1, bet2) => bet1.createdTime - bet2.createdTime) + + setBets(bets) + }) } diff --git a/web/pages/contract/[contractId].tsx b/web/pages/contract/[contractId].tsx index bcde85fa..365a5a77 100644 --- a/web/pages/contract/[contractId].tsx +++ b/web/pages/contract/[contractId].tsx @@ -24,15 +24,13 @@ export default function ContractPage() {
-
- - + + -
+
- - -
+ +
) }