Can bet. More layout tweaks!

This commit is contained in:
James Grugett 2022-02-14 23:21:44 -06:00
parent f06709c20f
commit fbdc6eacad
3 changed files with 60 additions and 32 deletions

View File

@ -3,7 +3,7 @@ import * as admin from 'firebase-admin'
import { Contract } from '../../common/contract'
import { User } from '../../common/user'
import { getNewBinaryBetInfo } from '../../common/new-bet'
import { getNewBinaryBetInfo, getNewMultiBetInfo } from '../../common/new-bet'
export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
async (
@ -22,7 +22,7 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
if (amount <= 0 || isNaN(amount) || !isFinite(amount))
return { status: 'error', message: 'Invalid amount' }
if (outcome !== 'YES' && outcome !== 'NO')
if (outcome !== 'YES' && outcome !== 'NO' && isNaN(+outcome))
return { status: 'error', message: 'Invalid outcome' }
// run as transaction to prevent race conditions
@ -42,16 +42,39 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
return { status: 'error', message: 'Invalid contract' }
const contract = contractSnap.data() as Contract
const { closeTime } = contract
const { closeTime, outcomes } = contract
if (closeTime && Date.now() > closeTime)
return { status: 'error', message: 'Trading is closed' }
const isFreeAnswer = outcomes === 'FREE_ANSWER'
if (isFreeAnswer) {
const answerSnap = await transaction.get(
contractDoc.collection('answers').doc(outcome)
)
if (!answerSnap.exists)
return { status: 'error', message: 'Invalid contract' }
}
const newBetDoc = firestore
.collection(`contracts/${contractId}/bets`)
.doc()
const { newBet, newPool, newTotalShares, newTotalBets, newBalance } =
getNewBinaryBetInfo(user, outcome, amount, contract, newBetDoc.id)
isFreeAnswer
? getNewMultiBetInfo(
user,
outcome,
amount,
contract as any,
newBetDoc.id
)
: getNewBinaryBetInfo(
user,
outcome as 'YES' | 'NO',
amount,
contract,
newBetDoc.id
)
transaction.create(newBetDoc, newBet)
transaction.update(contractDoc, {

View File

@ -46,7 +46,7 @@ export function AnswersPanel(props: {
)
return (
<Col className="gap-4">
<Col className="gap-3">
{sortedAnswers.map((answer) => (
<AnswerItem key={answer.id} answer={answer} contract={contract} />
))}
@ -66,7 +66,7 @@ function AnswerItem(props: { answer: Answer; contract: Contract<'MULTI'> }) {
const [isBetting, setIsBetting] = useState(false)
return (
<Col className="px-4 py-2 sm:flex-row bg-gray-50 rounded">
<Col className="p-4 sm:flex-row bg-gray-50 rounded">
<Col className="gap-3 flex-1">
<div>{text}</div>
@ -150,6 +150,7 @@ function AnswerBetPanel(props: {
console.log('placed bet. Result:', result)
if (result?.status === 'success') {
setIsSubmitting(false)
closePanel()
} else {
setError(result?.error || 'Error placing bet')
@ -184,7 +185,7 @@ function AnswerBetPanel(props: {
const currentReturnPercent = (currentReturn * 100).toFixed() + '%'
return (
<Col className="items-start px-2 pb-2">
<Col className="items-start px-2 pb-2 pt-4 sm:pt-0">
<Row className="self-stretch items-center justify-between">
<div className="text-xl">Buy this answer</div>
@ -266,14 +267,12 @@ function CreateAnswerInput(props: { contract: Contract<'MULTI'> }) {
const submitAnswer = async () => {
if (canSubmit) {
setIsSubmitting(true)
console.log('submitting', { text, betAmount })
const result = await createAnswer({
contractId: contract.id,
text,
amount: betAmount,
}).then((r) => r.data)
console.log('submit complte', result)
setIsSubmitting(false)
if (result.status === 'success') {
@ -285,18 +284,34 @@ function CreateAnswerInput(props: { contract: Contract<'MULTI'> }) {
}
return (
<Col className="gap-4 mt-2 px-2">
<Col className="sm:flex-row gap-8">
<Col className="flex-1 gap-2">
<div className="text-gray-500 text-sm mb-1">Add your answer</div>
<Textarea
value={text}
onChange={(e) => setText(e.target.value)}
className="textarea textarea-bordered w-full"
placeholder="Type your answer..."
rows={1}
maxLength={10000}
/>
<Col className="gap-4 p-4 bg-gray-50 rounded">
<Col className="flex-1 gap-2">
<div className="mb-1">Add your answer</div>
<Textarea
value={text}
onChange={(e) => setText(e.target.value)}
className="textarea textarea-bordered w-full"
placeholder="Type your answer..."
rows={1}
maxLength={10000}
/>
<div />
<Col
className={clsx('sm:flex-row', text ? 'justify-between' : 'self-end')}
>
{text && (
<Col className="gap-2 mt-1">
<div className="text-gray-500 text-sm">Bet amount</div>
<AmountInput
amount={betAmount}
onChange={setBetAmount}
error={amountError}
setError={setAmountError}
minimumAmount={10}
disabled={isSubmitting}
/>
</Col>
)}
<button
className={clsx(
'btn btn-sm self-end mt-2',
@ -308,17 +323,6 @@ function CreateAnswerInput(props: { contract: Contract<'MULTI'> }) {
Submit answer & bet
</button>
</Col>
<Col className="gap-2">
<div className="text-gray-500 text-sm">Bet amount</div>
<AmountInput
amount={betAmount}
onChange={setBetAmount}
error={amountError}
setError={setAmountError}
minimumAmount={10}
disabled={isSubmitting}
/>
</Col>
</Col>
</Col>
)

View File

@ -127,6 +127,7 @@ export default function ContractPage(props: {
contract={contract as any}
answers={props.answers}
/>
<Spacer h={4} />
<div className="divider before:bg-gray-300 after:bg-gray-300" />
</>
)}