Submit bets to firestore
This commit is contained in:
parent
b8b5868eb8
commit
77ce27f45f
|
@ -1,4 +1,7 @@
|
|||
import clsx from 'clsx'
|
||||
import React, { useState } from 'react'
|
||||
import { useUser } from '../hooks/use-user'
|
||||
import { Bet, saveBet } from '../lib/firebase/bets'
|
||||
import { Contract } from '../lib/firebase/contracts'
|
||||
import { Col } from './layout/col'
|
||||
import { Row } from './layout/row'
|
||||
|
@ -8,14 +11,51 @@ import { YesNoSelector } from './yes-no-selector'
|
|||
export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||
const { contract, className } = props
|
||||
|
||||
const user = useUser()
|
||||
|
||||
const [betChoice, setBetChoice] = useState<'YES' | 'NO'>('YES')
|
||||
const [betAmount, setBetAmount] = useState<number | undefined>(undefined)
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [wasSubmitted, setWasSubmitted] = useState(false)
|
||||
|
||||
function onBetChange(str: string) {
|
||||
const amount = parseInt(str)
|
||||
setBetAmount(isNaN(amount) ? undefined : amount)
|
||||
}
|
||||
|
||||
async function submitBet() {
|
||||
if (!user || !betAmount) return
|
||||
|
||||
const now = Date.now()
|
||||
|
||||
const bet: Bet = {
|
||||
id: `${now}-${user.id}`,
|
||||
userId: user.id,
|
||||
contractId: contract.id,
|
||||
createdTime: now,
|
||||
outcome: betChoice,
|
||||
amount: betAmount,
|
||||
|
||||
// Placeholder.
|
||||
dpmWeight: betAmount,
|
||||
}
|
||||
|
||||
setIsSubmitting(true)
|
||||
|
||||
await saveBet(bet)
|
||||
|
||||
setIsSubmitting(false)
|
||||
setWasSubmitted(true)
|
||||
}
|
||||
|
||||
function newBet() {
|
||||
setBetAmount(undefined)
|
||||
setWasSubmitted(false)
|
||||
}
|
||||
|
||||
const betDisabled = isSubmitting || wasSubmitted
|
||||
|
||||
return (
|
||||
<Col className={'bg-gray-600 p-6 rounded ' + className}>
|
||||
<div className="p-2 font-medium">Pick outcome</div>
|
||||
|
@ -47,9 +87,7 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
|
|||
<Spacer h={4} />
|
||||
|
||||
<div className="p-2 font-medium">Average price</div>
|
||||
<div className="px-2">
|
||||
{betChoice === 'YES' ? 0.57 : 0.43} points
|
||||
</div>
|
||||
<div className="px-2">{betChoice === 'YES' ? 0.57 : 0.43} points</div>
|
||||
|
||||
<Spacer h={2} />
|
||||
|
||||
|
@ -60,7 +98,29 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
|
|||
|
||||
<Spacer h={6} />
|
||||
|
||||
<button className="btn btn-primary">Place bet</button>
|
||||
<button
|
||||
className={clsx(
|
||||
'btn',
|
||||
betDisabled ? 'btn-disabled' : 'btn-primary'
|
||||
)}
|
||||
onClick={betDisabled ? undefined : submitBet}
|
||||
>
|
||||
Place bet
|
||||
</button>
|
||||
|
||||
{wasSubmitted && (
|
||||
<Col>
|
||||
<Spacer h={4} />
|
||||
|
||||
<div>Bet submitted!</div>
|
||||
|
||||
<Spacer h={4} />
|
||||
|
||||
<button className="btn btn-primary btn-xs" onClick={newBet}>
|
||||
New bet
|
||||
</button>
|
||||
</Col>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Col>
|
||||
|
|
22
web/lib/firebase/bets.ts
Normal file
22
web/lib/firebase/bets.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { doc, setDoc } from 'firebase/firestore'
|
||||
import { db } from './init'
|
||||
|
||||
export type Bet = {
|
||||
id: string
|
||||
userId: string
|
||||
contractId: string
|
||||
|
||||
amount: number // Amount of USD bid
|
||||
outcome: 'YES' | 'NO' // Chosen outcome
|
||||
|
||||
// Calculate and replace these on server?
|
||||
createdTime: number
|
||||
dpmWeight: number // Dynamic Parimutuel weight
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
|
@ -32,18 +32,6 @@ export type Contract = {
|
|||
resolution?: 'YES' | 'NO' | 'CANCEL' // Chosen by creator; must be one of outcomes
|
||||
}
|
||||
|
||||
export type Bet = {
|
||||
id: string
|
||||
userId: string
|
||||
contractId: string
|
||||
|
||||
size: number // Amount of USD bid
|
||||
outcome: 'YES' | 'NO' // Chosen outcome
|
||||
createdTime: number
|
||||
|
||||
dpmWeight: number // Dynamic Parimutuel weight
|
||||
}
|
||||
|
||||
const db = getFirestore(app)
|
||||
const contractCollection = collection(db, 'contracts')
|
||||
|
||||
|
@ -79,10 +67,3 @@ export function listenForContract(
|
|||
setContract(contractSnap.data() as Contract)
|
||||
})
|
||||
}
|
||||
|
||||
// Push bet to Firestore
|
||||
// TODO: Should bets be subcollections under its contract?
|
||||
export async function setBet(bet: Bet) {
|
||||
const docRef = doc(db, 'bets', bet.id)
|
||||
await setDoc(docRef, bet)
|
||||
}
|
||||
|
|
14
web/package-lock.json
generated
14
web/package-lock.json
generated
|
@ -9,6 +9,7 @@
|
|||
"@headlessui/react": "1.4.2",
|
||||
"@heroicons/react": "1.0.5",
|
||||
"chart.js": "3.6.1",
|
||||
"clsx": "^1.1.1",
|
||||
"daisyui": "1.16.2",
|
||||
"firebase": "9.6.0",
|
||||
"next": "12.0.4",
|
||||
|
@ -2879,6 +2880,14 @@
|
|||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
|
||||
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||
|
@ -9908,6 +9917,11 @@
|
|||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"clsx": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
|
||||
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
|
||||
},
|
||||
"color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"@headlessui/react": "1.4.2",
|
||||
"@heroicons/react": "1.0.5",
|
||||
"chart.js": "3.6.1",
|
||||
"clsx": "^1.1.1",
|
||||
"daisyui": "1.16.2",
|
||||
"firebase": "9.6.0",
|
||||
"next": "12.0.4",
|
||||
|
|
Loading…
Reference in New Issue
Block a user