BuyPanel & SellPanel with banner above that shows current shares and toggle button
This commit is contained in:
parent
3a22a3237f
commit
fe3ac872c0
|
@ -1,7 +1,7 @@
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { useUser } from '../hooks/use-user'
|
import { useUser } from '../hooks/use-user'
|
||||||
import { formatMoney } from '../../common/util/format'
|
import { formatMoney, formatWithCommas } from '../../common/util/format'
|
||||||
import { Col } from './layout/col'
|
import { Col } from './layout/col'
|
||||||
import { Row } from './layout/row'
|
import { Row } from './layout/row'
|
||||||
import { Bet, MAX_LOAN_PER_CONTRACT } from '../../common/bet'
|
import { Bet, MAX_LOAN_PER_CONTRACT } from '../../common/bet'
|
||||||
|
@ -86,7 +86,7 @@ export function BuyAmountInput(props: {
|
||||||
error: string | undefined
|
error: string | undefined
|
||||||
setError: (error: string | undefined) => void
|
setError: (error: string | undefined) => void
|
||||||
contractIdForLoan: string | undefined
|
contractIdForLoan: string | undefined
|
||||||
userBets: Bet[]
|
userBets?: Bet[]
|
||||||
minimumAmount?: number
|
minimumAmount?: number
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
|
@ -110,7 +110,9 @@ export function BuyAmountInput(props: {
|
||||||
|
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
|
|
||||||
const openUserBets = userBets.filter((bet) => !bet.isSold && !bet.sale)
|
const openUserBets = (userBets ?? []).filter(
|
||||||
|
(bet) => !bet.isSold && !bet.sale
|
||||||
|
)
|
||||||
const prevLoanAmount = _.sumBy(openUserBets, (bet) => bet.loanAmount ?? 0)
|
const prevLoanAmount = _.sumBy(openUserBets, (bet) => bet.loanAmount ?? 0)
|
||||||
|
|
||||||
const loanAmount = contractIdForLoan
|
const loanAmount = contractIdForLoan
|
||||||
|
@ -182,7 +184,6 @@ export function SellAmountInput(props: {
|
||||||
userBets: Bet[]
|
userBets: Bet[]
|
||||||
error: string | undefined
|
error: string | undefined
|
||||||
setError: (error: string | undefined) => void
|
setError: (error: string | undefined) => void
|
||||||
minimumAmount?: number
|
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
inputClassName?: string
|
inputClassName?: string
|
||||||
|
@ -199,7 +200,6 @@ export function SellAmountInput(props: {
|
||||||
disabled,
|
disabled,
|
||||||
className,
|
className,
|
||||||
inputClassName,
|
inputClassName,
|
||||||
minimumAmount,
|
|
||||||
inputRef,
|
inputRef,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
|
@ -216,6 +216,7 @@ export function SellAmountInput(props: {
|
||||||
]
|
]
|
||||||
|
|
||||||
const sellOutcome = yesShares ? 'YES' : noShares ? 'NO' : undefined
|
const sellOutcome = yesShares ? 'YES' : noShares ? 'NO' : undefined
|
||||||
|
const shares = yesShares || noShares
|
||||||
|
|
||||||
const prevLoanAmount = _.sumBy(openUserBets, (bet) => bet.loanAmount ?? 0)
|
const prevLoanAmount = _.sumBy(openUserBets, (bet) => bet.loanAmount ?? 0)
|
||||||
|
|
||||||
|
@ -227,10 +228,24 @@ export function SellAmountInput(props: {
|
||||||
|
|
||||||
const loanRepaid = Math.min(prevLoanAmount, sellAmount)
|
const loanRepaid = Math.min(prevLoanAmount, sellAmount)
|
||||||
|
|
||||||
|
const onAmountChange = (amount: number | undefined) => {
|
||||||
|
onChange(amount)
|
||||||
|
|
||||||
|
// Check for errors.
|
||||||
|
if (amount !== undefined) {
|
||||||
|
console.log(shares, amount)
|
||||||
|
if (amount > shares) {
|
||||||
|
setError(`Maximum ${formatWithCommas(Math.floor(shares))} shares`)
|
||||||
|
} else {
|
||||||
|
setError(undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AmountInput
|
<AmountInput
|
||||||
amount={amount}
|
amount={amount}
|
||||||
onChange={onChange}
|
onChange={onAmountChange}
|
||||||
label="Shares"
|
label="Shares"
|
||||||
error={error}
|
error={error}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -241,7 +256,7 @@ export function SellAmountInput(props: {
|
||||||
{user && (
|
{user && (
|
||||||
<Col className="gap-3 text-sm">
|
<Col className="gap-3 text-sm">
|
||||||
<Row className="items-center justify-between gap-2 text-gray-500">
|
<Row className="items-center justify-between gap-2 text-gray-500">
|
||||||
Sale amount{' '}
|
Sale proceeds{' '}
|
||||||
<span className="text-neutral">{formatMoney(sellAmount)}</span>
|
<span className="text-neutral">{formatMoney(sellAmount)}</span>
|
||||||
</Row>
|
</Row>
|
||||||
{prevLoanAmount && (
|
{prevLoanAmount && (
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
formatWithCommas,
|
formatWithCommas,
|
||||||
} from '../../common/util/format'
|
} from '../../common/util/format'
|
||||||
import { Title } from './title'
|
import { Title } from './title'
|
||||||
import { firebaseLogin } from '../lib/firebase/users'
|
import { firebaseLogin, User } from '../lib/firebase/users'
|
||||||
import { Bet } from '../../common/bet'
|
import { Bet } from '../../common/bet'
|
||||||
import { placeBet } from '../lib/firebase/api-call'
|
import { placeBet } from '../lib/firebase/api-call'
|
||||||
import { BuyAmountInput, SellAmountInput } from './amount-input'
|
import { BuyAmountInput, SellAmountInput } from './amount-input'
|
||||||
|
@ -28,6 +28,10 @@ import {
|
||||||
} from '../../common/calculate'
|
} from '../../common/calculate'
|
||||||
import { useFocus } from '../hooks/use-focus'
|
import { useFocus } from '../hooks/use-focus'
|
||||||
import { useUserContractBets } from '../hooks/use-user-bets'
|
import { useUserContractBets } from '../hooks/use-user-bets'
|
||||||
|
import {
|
||||||
|
calculateCpmmSale,
|
||||||
|
getCpmmProbability,
|
||||||
|
} from '../../common/calculate-cpmm'
|
||||||
|
|
||||||
export function BetPanel(props: {
|
export function BetPanel(props: {
|
||||||
contract: FullContract<DPM | CPMM, Binary>
|
contract: FullContract<DPM | CPMM, Binary>
|
||||||
|
@ -36,15 +40,13 @@ export function BetPanel(props: {
|
||||||
selected?: 'YES' | 'NO'
|
selected?: 'YES' | 'NO'
|
||||||
onBetSuccess?: () => void
|
onBetSuccess?: () => void
|
||||||
}) {
|
}) {
|
||||||
useEffect(() => {
|
|
||||||
// warm up cloud function
|
|
||||||
placeBet({}).catch()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const { contract, className, title, selected, onBetSuccess } = props
|
const { contract, className, title, selected, onBetSuccess } = props
|
||||||
|
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const userBets = useUserContractBets(user?.id, contract.id) ?? []
|
const userBets = useUserContractBets(user?.id, contract.id) ?? []
|
||||||
|
|
||||||
|
const [tradeType, setTradeType] = useState<'BUY' | 'SELL'>('BUY')
|
||||||
|
|
||||||
const [yesBets, noBets] = _.partition(
|
const [yesBets, noBets] = _.partition(
|
||||||
userBets,
|
userBets,
|
||||||
(bet) => bet.outcome === 'YES'
|
(bet) => bet.outcome === 'YES'
|
||||||
|
@ -54,9 +56,93 @@ export function BetPanel(props: {
|
||||||
_.sumBy(noBets, (bet) => bet.shares),
|
_.sumBy(noBets, (bet) => bet.shares),
|
||||||
]
|
]
|
||||||
|
|
||||||
const sellOutcome = yesShares ? 'YES' : noShares ? 'NO' : undefined
|
const sharesOutcome = yesShares ? 'YES' : noShares ? 'NO' : undefined
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Col>
|
||||||
|
{sharesOutcome && (
|
||||||
|
<Col className="rounded-t-md px-6 py-6 bg-gray-100">
|
||||||
|
<Row className="justify-between items-center gap-2">
|
||||||
|
<div>
|
||||||
|
You have {formatWithCommas(Math.floor(yesShares || noShares))}{' '}
|
||||||
|
<OutcomeLabel outcome={sharesOutcome} /> shares
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="btn btn-sm"
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'white',
|
||||||
|
border: '2px solid',
|
||||||
|
color: '#3D4451',
|
||||||
|
}}
|
||||||
|
onClick={() =>
|
||||||
|
tradeType === 'BUY' ? setTradeType('SELL') : setTradeType('BUY')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{tradeType === 'BUY' ? 'Sell' : 'Buy'}
|
||||||
|
</button>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Col
|
||||||
|
className={clsx(
|
||||||
|
'rounded-b-md bg-white px-8 py-6',
|
||||||
|
!sharesOutcome && 'rounded-t-md',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Title
|
||||||
|
className={clsx(
|
||||||
|
'!mt-0',
|
||||||
|
tradeType === 'BUY' && title ? '!text-xl' : ''
|
||||||
|
)}
|
||||||
|
text={tradeType === 'BUY' ? title ?? 'Buy' : 'Sell'}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{tradeType === 'SELL' && user && sharesOutcome && (
|
||||||
|
<SellPanel
|
||||||
|
contract={contract as FullContract<CPMM, Binary>}
|
||||||
|
shares={yesShares || noShares}
|
||||||
|
sharesOutcome={sharesOutcome}
|
||||||
|
user={user}
|
||||||
|
userBets={userBets}
|
||||||
|
onSellSuccess={onBetSuccess}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tradeType === 'BUY' && (
|
||||||
|
<BuyPanel
|
||||||
|
contract={contract}
|
||||||
|
user={user}
|
||||||
|
userBets={userBets}
|
||||||
|
selected={selected}
|
||||||
|
onBuySuccess={onBetSuccess}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{user === null && (
|
||||||
|
<button
|
||||||
|
className="btn flex-1 whitespace-nowrap border-none bg-gradient-to-r from-teal-500 to-green-500 px-10 text-lg font-medium normal-case hover:from-teal-600 hover:to-green-600"
|
||||||
|
onClick={firebaseLogin}
|
||||||
|
>
|
||||||
|
Sign in to trade!
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function BuyPanel(props: {
|
||||||
|
contract: FullContract<DPM | CPMM, Binary>
|
||||||
|
user: User | null | undefined
|
||||||
|
userBets: Bet[]
|
||||||
|
selected?: 'YES' | 'NO'
|
||||||
|
onBuySuccess?: () => void
|
||||||
|
}) {
|
||||||
|
const { contract, user, userBets, selected, onBuySuccess } = props
|
||||||
|
|
||||||
const [tradeType, setTradeType] = useState<'BUY' | 'SELL'>('BUY')
|
|
||||||
const [betChoice, setBetChoice] = useState<'YES' | 'NO' | undefined>(selected)
|
const [betChoice, setBetChoice] = useState<'YES' | 'NO' | undefined>(selected)
|
||||||
const [betAmount, setBetAmount] = useState<number | undefined>(undefined)
|
const [betAmount, setBetAmount] = useState<number | undefined>(undefined)
|
||||||
const [inputRef, focusAmountInput] = useFocus()
|
const [inputRef, focusAmountInput] = useFocus()
|
||||||
|
@ -65,6 +151,11 @@ export function BetPanel(props: {
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
const [wasSubmitted, setWasSubmitted] = useState(false)
|
const [wasSubmitted, setWasSubmitted] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// warm up cloud function
|
||||||
|
placeBet({}).catch()
|
||||||
|
}, [])
|
||||||
|
|
||||||
function onBetChoice(choice: 'YES' | 'NO') {
|
function onBetChoice(choice: 'YES' | 'NO') {
|
||||||
setBetChoice(choice)
|
setBetChoice(choice)
|
||||||
setWasSubmitted(false)
|
setWasSubmitted(false)
|
||||||
|
@ -97,7 +188,7 @@ export function BetPanel(props: {
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
setWasSubmitted(true)
|
setWasSubmitted(true)
|
||||||
setBetAmount(undefined)
|
setBetAmount(undefined)
|
||||||
if (onBetSuccess) onBetSuccess()
|
if (onBuySuccess) onBuySuccess()
|
||||||
} else {
|
} else {
|
||||||
setError(result?.error || 'Error placing bet')
|
setError(result?.error || 'Error placing bet')
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
|
@ -128,10 +219,9 @@ export function BetPanel(props: {
|
||||||
const currentReturn = betAmount ? (currentPayout - betAmount) / betAmount : 0
|
const currentReturn = betAmount ? (currentPayout - betAmount) / betAmount : 0
|
||||||
const currentReturnPercent = formatPercent(currentReturn)
|
const currentReturnPercent = formatPercent(currentReturn)
|
||||||
|
|
||||||
const panelTitle = title ?? 'Place a trade'
|
useEffect(() => {
|
||||||
if (title) {
|
|
||||||
focusAmountInput()
|
focusAmountInput()
|
||||||
}
|
}, [focusAmountInput])
|
||||||
|
|
||||||
const tooltip =
|
const tooltip =
|
||||||
contract.mechanism === 'dpm-2'
|
contract.mechanism === 'dpm-2'
|
||||||
|
@ -143,84 +233,25 @@ export function BetPanel(props: {
|
||||||
: 0)
|
: 0)
|
||||||
)} ${betChoice} shares`
|
)} ${betChoice} shares`
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className={clsx('rounded-md bg-white px-8 py-6', className)}>
|
<>
|
||||||
<Title
|
<YesNoSelector
|
||||||
className={clsx('!mt-0', title ? '!text-xl' : '')}
|
className="mb-4"
|
||||||
text={panelTitle}
|
selected={betChoice}
|
||||||
|
onSelect={(choice) => onBetChoice(choice)}
|
||||||
|
/>
|
||||||
|
<div className="my-3 text-left text-sm text-gray-500">Amount</div>
|
||||||
|
<BuyAmountInput
|
||||||
|
inputClassName="w-full"
|
||||||
|
amount={betAmount}
|
||||||
|
onChange={onBetChange}
|
||||||
|
userBets={userBets}
|
||||||
|
error={error}
|
||||||
|
setError={setError}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
inputRef={inputRef}
|
||||||
|
contractIdForLoan={contract.id}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{contract.mechanism === 'cpmm-1' && (
|
|
||||||
<Row className="gap-2 w-full tabs mb-6">
|
|
||||||
<div
|
|
||||||
className={clsx(
|
|
||||||
'tab gap-2 tab-bordered flex-1',
|
|
||||||
tradeType === 'BUY' && 'tab-active'
|
|
||||||
)}
|
|
||||||
onClick={() => setTradeType('BUY')}
|
|
||||||
>
|
|
||||||
BUY
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={clsx(
|
|
||||||
'tab gap-2 tab-bordered flex-1',
|
|
||||||
tradeType === 'SELL' && 'tab-active'
|
|
||||||
)}
|
|
||||||
onClick={() => setTradeType('SELL')}
|
|
||||||
>
|
|
||||||
SELL
|
|
||||||
</div>
|
|
||||||
</Row>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{tradeType === 'BUY' ? (
|
|
||||||
<>
|
|
||||||
<YesNoSelector
|
|
||||||
className="mb-4"
|
|
||||||
selected={betChoice}
|
|
||||||
onSelect={(choice) => onBetChoice(choice)}
|
|
||||||
/>
|
|
||||||
<div className="my-3 text-left text-sm text-gray-500">Buy amount</div>
|
|
||||||
<BuyAmountInput
|
|
||||||
inputClassName="w-full"
|
|
||||||
amount={betAmount}
|
|
||||||
onChange={onBetChange}
|
|
||||||
userBets={userBets}
|
|
||||||
error={error}
|
|
||||||
setError={setError}
|
|
||||||
disabled={isSubmitting}
|
|
||||||
inputRef={inputRef}
|
|
||||||
contractIdForLoan={contract.id}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : sellOutcome ? (
|
|
||||||
<>
|
|
||||||
<div className="mb-3 text-left ">
|
|
||||||
You have {formatWithCommas(yesShares || noShares)}{' '}
|
|
||||||
<OutcomeLabel outcome={sellOutcome} /> shares
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="my-3 text-left text-sm text-gray-500">
|
|
||||||
Sell quantity
|
|
||||||
</div>
|
|
||||||
<SellAmountInput
|
|
||||||
inputClassName="w-full"
|
|
||||||
contract={contract as FullContract<CPMM, Binary>}
|
|
||||||
amount={betAmount}
|
|
||||||
onChange={onBetChange}
|
|
||||||
userBets={userBets}
|
|
||||||
error={error}
|
|
||||||
setError={setError}
|
|
||||||
disabled={isSubmitting}
|
|
||||||
inputRef={inputRef}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="mb-3 text-left text-gray-500">
|
|
||||||
You have don't have any shares to sell.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Col className="mt-3 w-full gap-3">
|
<Col className="mt-3 w-full gap-3">
|
||||||
<Row className="items-center justify-between text-sm">
|
<Row className="items-center justify-between text-sm">
|
||||||
|
@ -232,23 +263,21 @@ export function BetPanel(props: {
|
||||||
</Row>
|
</Row>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{tradeType === 'BUY' && (
|
<Row className="items-start justify-between gap-2 text-sm">
|
||||||
<Row className="items-start justify-between gap-2 text-sm">
|
<Row className="flex-nowrap items-center gap-2 whitespace-nowrap text-gray-500">
|
||||||
<Row className="flex-nowrap items-center gap-2 whitespace-nowrap text-gray-500">
|
<div>
|
||||||
<div>
|
Payout if <OutcomeLabel outcome={betChoice ?? 'YES'} />
|
||||||
Payout if <OutcomeLabel outcome={betChoice ?? 'YES'} />
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{tooltip && <InfoTooltip text={tooltip} />}
|
{tooltip && <InfoTooltip text={tooltip} />}
|
||||||
</Row>
|
|
||||||
<Row className="flex-wrap items-end justify-end gap-2">
|
|
||||||
<span className="whitespace-nowrap">
|
|
||||||
{formatMoney(currentPayout)}
|
|
||||||
</span>
|
|
||||||
<span>(+{currentReturnPercent})</span>
|
|
||||||
</Row>
|
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
<Row className="flex-wrap items-end justify-end gap-2">
|
||||||
|
<span className="whitespace-nowrap">
|
||||||
|
{formatMoney(currentPayout)}
|
||||||
|
</span>
|
||||||
|
<span>(+{currentReturnPercent})</span>
|
||||||
|
</Row>
|
||||||
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Spacer h={8} />
|
<Spacer h={8} />
|
||||||
|
@ -266,19 +295,107 @@ export function BetPanel(props: {
|
||||||
)}
|
)}
|
||||||
onClick={betDisabled ? undefined : submitBet}
|
onClick={betDisabled ? undefined : submitBet}
|
||||||
>
|
>
|
||||||
{isSubmitting ? 'Submitting...' : 'Submit trade'}
|
{isSubmitting ? 'Submitting...' : 'Submit Buy'}
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{user === null && (
|
|
||||||
<button
|
|
||||||
className="btn flex-1 whitespace-nowrap border-none bg-gradient-to-r from-teal-500 to-green-500 px-10 text-lg font-medium normal-case hover:from-teal-600 hover:to-green-600"
|
|
||||||
onClick={firebaseLogin}
|
|
||||||
>
|
|
||||||
Sign in to trade!
|
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{wasSubmitted && <div className="mt-4">Trade submitted!</div>}
|
{wasSubmitted && <div className="mt-4">Buy submitted!</div>}
|
||||||
</Col>
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SellPanel(props: {
|
||||||
|
contract: FullContract<CPMM, Binary>
|
||||||
|
userBets: Bet[]
|
||||||
|
shares: number
|
||||||
|
sharesOutcome: 'YES' | 'NO'
|
||||||
|
user: User
|
||||||
|
onSellSuccess?: () => void
|
||||||
|
}) {
|
||||||
|
const { contract, shares, sharesOutcome, userBets, user, onSellSuccess } =
|
||||||
|
props
|
||||||
|
|
||||||
|
const [amount, setAmount] = useState<number | undefined>(Math.floor(shares))
|
||||||
|
const [error, setError] = useState<string | undefined>()
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
|
const [wasSubmitted, setWasSubmitted] = useState(false)
|
||||||
|
|
||||||
|
const betDisabled = isSubmitting || !amount || error
|
||||||
|
|
||||||
|
async function submitSell() {
|
||||||
|
if (!user || !amount) return
|
||||||
|
|
||||||
|
setError(undefined)
|
||||||
|
setIsSubmitting(true)
|
||||||
|
|
||||||
|
const result = await placeBet({
|
||||||
|
shares: amount,
|
||||||
|
outcome: sharesOutcome,
|
||||||
|
contractId: contract.id,
|
||||||
|
}).then((r) => r.data as any)
|
||||||
|
|
||||||
|
console.log('placed bet. Result:', result)
|
||||||
|
|
||||||
|
if (result?.status === 'success') {
|
||||||
|
setIsSubmitting(false)
|
||||||
|
setWasSubmitted(true)
|
||||||
|
setAmount(undefined)
|
||||||
|
if (onSellSuccess) onSellSuccess()
|
||||||
|
} else {
|
||||||
|
setError(result?.error || 'Error selling')
|
||||||
|
setIsSubmitting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialProb = getProbability(contract)
|
||||||
|
const { newPool } = calculateCpmmSale(contract, {
|
||||||
|
shares: amount ?? 0,
|
||||||
|
outcome: sharesOutcome,
|
||||||
|
} as Bet)
|
||||||
|
const resultProb = getCpmmProbability(newPool, contract.p)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SellAmountInput
|
||||||
|
inputClassName="w-full"
|
||||||
|
contract={contract}
|
||||||
|
amount={amount}
|
||||||
|
onChange={setAmount}
|
||||||
|
userBets={userBets}
|
||||||
|
error={error}
|
||||||
|
setError={setError}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Col className="mt-3 w-full gap-3">
|
||||||
|
<Row className="items-center justify-between text-sm">
|
||||||
|
<div className="text-gray-500">Probability</div>
|
||||||
|
<Row>
|
||||||
|
<div>{formatPercent(initialProb)}</div>
|
||||||
|
<div className="mx-2">→</div>
|
||||||
|
<div>{formatPercent(resultProb)}</div>
|
||||||
|
</Row>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Spacer h={8} />
|
||||||
|
|
||||||
|
<button
|
||||||
|
className={clsx(
|
||||||
|
'btn flex-1',
|
||||||
|
betDisabled
|
||||||
|
? 'btn-disabled'
|
||||||
|
: sharesOutcome === 'YES'
|
||||||
|
? 'btn-primary'
|
||||||
|
: 'border-none bg-red-400 hover:bg-red-500',
|
||||||
|
isSubmitting ? 'loading' : ''
|
||||||
|
)}
|
||||||
|
onClick={betDisabled ? undefined : submitSell}
|
||||||
|
>
|
||||||
|
{isSubmitting ? 'Submitting...' : 'Submit sell'}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{wasSubmitted && <div className="mt-4">Sell submitted!</div>}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ export default function BetRow(props: {
|
||||||
</div>
|
</div>
|
||||||
<YesNoSelector
|
<YesNoSelector
|
||||||
btnClassName="btn-sm w-20"
|
btnClassName="btn-sm w-20"
|
||||||
|
showBuyLabel
|
||||||
onSelect={(choice) => {
|
onSelect={(choice) => {
|
||||||
setOpen(true)
|
setOpen(true)
|
||||||
setBetChoice(choice)
|
setBetChoice(choice)
|
||||||
|
|
|
@ -7,10 +7,11 @@ import { Row } from './layout/row'
|
||||||
export function YesNoSelector(props: {
|
export function YesNoSelector(props: {
|
||||||
selected?: 'YES' | 'NO'
|
selected?: 'YES' | 'NO'
|
||||||
onSelect: (selected: 'YES' | 'NO') => void
|
onSelect: (selected: 'YES' | 'NO') => void
|
||||||
|
showBuyLabel?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
btnClassName?: string
|
btnClassName?: string
|
||||||
}) {
|
}) {
|
||||||
const { selected, onSelect, className, btnClassName } = props
|
const { selected, onSelect, showBuyLabel, className, btnClassName } = props
|
||||||
|
|
||||||
const commonClassNames =
|
const commonClassNames =
|
||||||
'inline-flex flex-1 items-center justify-center rounded-3xl border-2 p-2'
|
'inline-flex flex-1 items-center justify-center rounded-3xl border-2 p-2'
|
||||||
|
@ -28,7 +29,7 @@ export function YesNoSelector(props: {
|
||||||
)}
|
)}
|
||||||
onClick={() => onSelect('YES')}
|
onClick={() => onSelect('YES')}
|
||||||
>
|
>
|
||||||
YES
|
{showBuyLabel ? 'Buy' : ''} YES
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -41,7 +42,7 @@ export function YesNoSelector(props: {
|
||||||
)}
|
)}
|
||||||
onClick={() => onSelect('NO')}
|
onClick={() => onSelect('NO')}
|
||||||
>
|
>
|
||||||
NO
|
{showBuyLabel ? 'Buy' : ''} NO
|
||||||
</button>
|
</button>
|
||||||
</Row>
|
</Row>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user