Can bet. More layout tweaks!
This commit is contained in:
parent
f06709c20f
commit
fbdc6eacad
|
@ -3,7 +3,7 @@ import * as admin from 'firebase-admin'
|
||||||
|
|
||||||
import { Contract } from '../../common/contract'
|
import { Contract } from '../../common/contract'
|
||||||
import { User } from '../../common/user'
|
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(
|
export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
async (
|
async (
|
||||||
|
@ -22,7 +22,7 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
if (amount <= 0 || isNaN(amount) || !isFinite(amount))
|
if (amount <= 0 || isNaN(amount) || !isFinite(amount))
|
||||||
return { status: 'error', message: 'Invalid 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' }
|
return { status: 'error', message: 'Invalid outcome' }
|
||||||
|
|
||||||
// run as transaction to prevent race conditions
|
// 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' }
|
return { status: 'error', message: 'Invalid contract' }
|
||||||
const contract = contractSnap.data() as Contract
|
const contract = contractSnap.data() as Contract
|
||||||
|
|
||||||
const { closeTime } = contract
|
const { closeTime, outcomes } = contract
|
||||||
if (closeTime && Date.now() > closeTime)
|
if (closeTime && Date.now() > closeTime)
|
||||||
return { status: 'error', message: 'Trading is closed' }
|
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
|
const newBetDoc = firestore
|
||||||
.collection(`contracts/${contractId}/bets`)
|
.collection(`contracts/${contractId}/bets`)
|
||||||
.doc()
|
.doc()
|
||||||
|
|
||||||
const { newBet, newPool, newTotalShares, newTotalBets, newBalance } =
|
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.create(newBetDoc, newBet)
|
||||||
transaction.update(contractDoc, {
|
transaction.update(contractDoc, {
|
||||||
|
|
|
@ -46,7 +46,7 @@ export function AnswersPanel(props: {
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className="gap-4">
|
<Col className="gap-3">
|
||||||
{sortedAnswers.map((answer) => (
|
{sortedAnswers.map((answer) => (
|
||||||
<AnswerItem key={answer.id} answer={answer} contract={contract} />
|
<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)
|
const [isBetting, setIsBetting] = useState(false)
|
||||||
|
|
||||||
return (
|
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">
|
<Col className="gap-3 flex-1">
|
||||||
<div>{text}</div>
|
<div>{text}</div>
|
||||||
|
|
||||||
|
@ -150,6 +150,7 @@ function AnswerBetPanel(props: {
|
||||||
console.log('placed bet. Result:', result)
|
console.log('placed bet. Result:', result)
|
||||||
|
|
||||||
if (result?.status === 'success') {
|
if (result?.status === 'success') {
|
||||||
|
setIsSubmitting(false)
|
||||||
closePanel()
|
closePanel()
|
||||||
} else {
|
} else {
|
||||||
setError(result?.error || 'Error placing bet')
|
setError(result?.error || 'Error placing bet')
|
||||||
|
@ -184,7 +185,7 @@ function AnswerBetPanel(props: {
|
||||||
const currentReturnPercent = (currentReturn * 100).toFixed() + '%'
|
const currentReturnPercent = (currentReturn * 100).toFixed() + '%'
|
||||||
|
|
||||||
return (
|
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">
|
<Row className="self-stretch items-center justify-between">
|
||||||
<div className="text-xl">Buy this answer</div>
|
<div className="text-xl">Buy this answer</div>
|
||||||
|
|
||||||
|
@ -266,14 +267,12 @@ function CreateAnswerInput(props: { contract: Contract<'MULTI'> }) {
|
||||||
const submitAnswer = async () => {
|
const submitAnswer = async () => {
|
||||||
if (canSubmit) {
|
if (canSubmit) {
|
||||||
setIsSubmitting(true)
|
setIsSubmitting(true)
|
||||||
console.log('submitting', { text, betAmount })
|
|
||||||
const result = await createAnswer({
|
const result = await createAnswer({
|
||||||
contractId: contract.id,
|
contractId: contract.id,
|
||||||
text,
|
text,
|
||||||
amount: betAmount,
|
amount: betAmount,
|
||||||
}).then((r) => r.data)
|
}).then((r) => r.data)
|
||||||
|
|
||||||
console.log('submit complte', result)
|
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
|
|
||||||
if (result.status === 'success') {
|
if (result.status === 'success') {
|
||||||
|
@ -285,18 +284,34 @@ function CreateAnswerInput(props: { contract: Contract<'MULTI'> }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className="gap-4 mt-2 px-2">
|
<Col className="gap-4 p-4 bg-gray-50 rounded">
|
||||||
<Col className="sm:flex-row gap-8">
|
<Col className="flex-1 gap-2">
|
||||||
<Col className="flex-1 gap-2">
|
<div className="mb-1">Add your answer</div>
|
||||||
<div className="text-gray-500 text-sm mb-1">Add your answer</div>
|
<Textarea
|
||||||
<Textarea
|
value={text}
|
||||||
value={text}
|
onChange={(e) => setText(e.target.value)}
|
||||||
onChange={(e) => setText(e.target.value)}
|
className="textarea textarea-bordered w-full"
|
||||||
className="textarea textarea-bordered w-full"
|
placeholder="Type your answer..."
|
||||||
placeholder="Type your answer..."
|
rows={1}
|
||||||
rows={1}
|
maxLength={10000}
|
||||||
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
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'btn btn-sm self-end mt-2',
|
'btn btn-sm self-end mt-2',
|
||||||
|
@ -308,17 +323,6 @@ function CreateAnswerInput(props: { contract: Contract<'MULTI'> }) {
|
||||||
Submit answer & bet
|
Submit answer & bet
|
||||||
</button>
|
</button>
|
||||||
</Col>
|
</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>
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
|
|
|
@ -127,6 +127,7 @@ export default function ContractPage(props: {
|
||||||
contract={contract as any}
|
contract={contract as any}
|
||||||
answers={props.answers}
|
answers={props.answers}
|
||||||
/>
|
/>
|
||||||
|
<Spacer h={4} />
|
||||||
<div className="divider before:bg-gray-300 after:bg-gray-300" />
|
<div className="divider before:bg-gray-300 after:bg-gray-300" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user