Clean up some stuff with SellPanel and AmountInput (#232)
* Hoist SellAmountInput logic into SellPanel * Ditch now-unnecessary SellAmountInput * Clean up sale proceeds markup * Clean unused imports * BuyPanel doesn't need userBets
This commit is contained in:
parent
d5cc6d5067
commit
aafd2a226f
|
@ -1,13 +1,8 @@
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import _ from 'lodash'
|
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
import { formatMoney, formatWithCommas } from 'common/util/format'
|
import { formatMoney } from 'common/util/format'
|
||||||
import { Col } from './layout/col'
|
import { Col } from './layout/col'
|
||||||
import { Row } from './layout/row'
|
|
||||||
import { Bet } from 'common/bet'
|
|
||||||
import { Spacer } from './layout/spacer'
|
import { Spacer } from './layout/spacer'
|
||||||
import { calculateCpmmSale } from 'common/calculate-cpmm'
|
|
||||||
import { Binary, CPMM, FullContract } from 'common/contract'
|
|
||||||
import { SiteLink } from './site-link'
|
import { SiteLink } from './site-link'
|
||||||
|
|
||||||
export function AmountInput(props: {
|
export function AmountInput(props: {
|
||||||
|
@ -20,7 +15,6 @@ export function AmountInput(props: {
|
||||||
inputClassName?: string
|
inputClassName?: string
|
||||||
// Needed to focus the amount input
|
// Needed to focus the amount input
|
||||||
inputRef?: React.MutableRefObject<any>
|
inputRef?: React.MutableRefObject<any>
|
||||||
children?: any
|
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
amount,
|
amount,
|
||||||
|
@ -31,7 +25,6 @@ export function AmountInput(props: {
|
||||||
className,
|
className,
|
||||||
inputClassName,
|
inputClassName,
|
||||||
inputRef,
|
inputRef,
|
||||||
children,
|
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const onAmountChange = (str: string) => {
|
const onAmountChange = (str: string) => {
|
||||||
|
@ -78,8 +71,6 @@ export function AmountInput(props: {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{children}
|
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -138,88 +129,3 @@ export function BuyAmountInput(props: {
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SellAmountInput(props: {
|
|
||||||
contract: FullContract<CPMM, Binary>
|
|
||||||
amount: number | undefined
|
|
||||||
onChange: (newAmount: number | undefined) => void
|
|
||||||
userBets: Bet[]
|
|
||||||
error: string | undefined
|
|
||||||
setError: (error: string | undefined) => void
|
|
||||||
disabled?: boolean
|
|
||||||
className?: string
|
|
||||||
inputClassName?: string
|
|
||||||
// Needed to focus the amount input
|
|
||||||
inputRef?: React.MutableRefObject<any>
|
|
||||||
}) {
|
|
||||||
const {
|
|
||||||
contract,
|
|
||||||
amount,
|
|
||||||
onChange,
|
|
||||||
userBets,
|
|
||||||
error,
|
|
||||||
setError,
|
|
||||||
disabled,
|
|
||||||
className,
|
|
||||||
inputClassName,
|
|
||||||
inputRef,
|
|
||||||
} = props
|
|
||||||
|
|
||||||
const user = useUser()
|
|
||||||
|
|
||||||
const openUserBets = userBets.filter((bet) => !bet.isSold && !bet.sale)
|
|
||||||
const [yesBets, noBets] = _.partition(
|
|
||||||
openUserBets,
|
|
||||||
(bet) => bet.outcome === 'YES'
|
|
||||||
)
|
|
||||||
const [yesShares, noShares] = [
|
|
||||||
_.sumBy(yesBets, (bet) => bet.shares),
|
|
||||||
_.sumBy(noBets, (bet) => bet.shares),
|
|
||||||
]
|
|
||||||
|
|
||||||
const sellOutcome = yesShares ? 'YES' : noShares ? 'NO' : undefined
|
|
||||||
const shares = Math.round(yesShares) || Math.round(noShares)
|
|
||||||
|
|
||||||
const sharesSold = Math.min(amount ?? 0, shares)
|
|
||||||
|
|
||||||
const { saleValue } = calculateCpmmSale(
|
|
||||||
contract,
|
|
||||||
sharesSold,
|
|
||||||
sellOutcome as 'YES' | 'NO'
|
|
||||||
)
|
|
||||||
|
|
||||||
const onAmountChange = (amount: number | undefined) => {
|
|
||||||
onChange(amount)
|
|
||||||
|
|
||||||
// Check for errors.
|
|
||||||
if (amount !== undefined) {
|
|
||||||
if (amount > shares) {
|
|
||||||
setError(`Maximum ${formatWithCommas(Math.floor(shares))} shares`)
|
|
||||||
} else {
|
|
||||||
setError(undefined)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AmountInput
|
|
||||||
amount={amount}
|
|
||||||
onChange={onAmountChange}
|
|
||||||
label="Qty"
|
|
||||||
error={error}
|
|
||||||
disabled={disabled}
|
|
||||||
className={className}
|
|
||||||
inputClassName={inputClassName}
|
|
||||||
inputRef={inputRef}
|
|
||||||
>
|
|
||||||
{user && (
|
|
||||||
<Col className="gap-3 text-sm">
|
|
||||||
<Row className="items-center justify-between gap-2 text-gray-500">
|
|
||||||
Sale proceeds{' '}
|
|
||||||
<span className="text-neutral">{formatMoney(saleValue)}</span>
|
|
||||||
</Row>
|
|
||||||
</Col>
|
|
||||||
)}
|
|
||||||
</AmountInput>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
import _ from 'lodash'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
|
@ -16,7 +17,7 @@ import { Title } from './title'
|
||||||
import { firebaseLogin, User } from 'web/lib/firebase/users'
|
import { firebaseLogin, User } from 'web/lib/firebase/users'
|
||||||
import { Bet } from 'common/bet'
|
import { Bet } from 'common/bet'
|
||||||
import { placeBet, sellShares } from 'web/lib/firebase/api-call'
|
import { placeBet, sellShares } from 'web/lib/firebase/api-call'
|
||||||
import { BuyAmountInput, SellAmountInput } from './amount-input'
|
import { AmountInput, BuyAmountInput } from './amount-input'
|
||||||
import { InfoTooltip } from './info-tooltip'
|
import { InfoTooltip } from './info-tooltip'
|
||||||
import { BinaryOutcomeLabel } from './outcome-label'
|
import { BinaryOutcomeLabel } from './outcome-label'
|
||||||
import {
|
import {
|
||||||
|
@ -66,7 +67,7 @@ export function BetPanel(props: {
|
||||||
<div className="mb-6 text-2xl">Place your bet</div>
|
<div className="mb-6 text-2xl">Place your bet</div>
|
||||||
{/* <Title className={clsx('!mt-0 text-neutral')} text="Place a trade" /> */}
|
{/* <Title className={clsx('!mt-0 text-neutral')} text="Place a trade" /> */}
|
||||||
|
|
||||||
<BuyPanel contract={contract} user={user} userBets={userBets ?? []} />
|
<BuyPanel contract={contract} user={user} />
|
||||||
|
|
||||||
{user === null && (
|
{user === null && (
|
||||||
<button
|
<button
|
||||||
|
@ -177,7 +178,6 @@ export function BetPanelSwitcher(props: {
|
||||||
<BuyPanel
|
<BuyPanel
|
||||||
contract={contract}
|
contract={contract}
|
||||||
user={user}
|
user={user}
|
||||||
userBets={userBets ?? []}
|
|
||||||
selected={selected}
|
selected={selected}
|
||||||
onBuySuccess={onBetSuccess}
|
onBuySuccess={onBetSuccess}
|
||||||
/>
|
/>
|
||||||
|
@ -199,11 +199,10 @@ export function BetPanelSwitcher(props: {
|
||||||
function BuyPanel(props: {
|
function BuyPanel(props: {
|
||||||
contract: FullContract<DPM | CPMM, Binary>
|
contract: FullContract<DPM | CPMM, Binary>
|
||||||
user: User | null | undefined
|
user: User | null | undefined
|
||||||
userBets: Bet[]
|
|
||||||
selected?: 'YES' | 'NO'
|
selected?: 'YES' | 'NO'
|
||||||
onBuySuccess?: () => void
|
onBuySuccess?: () => void
|
||||||
}) {
|
}) {
|
||||||
const { contract, user, userBets, selected, onBuySuccess } = props
|
const { contract, user, selected, onBuySuccess } = props
|
||||||
|
|
||||||
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)
|
||||||
|
@ -437,11 +436,43 @@ export function SellPanel(props: {
|
||||||
)
|
)
|
||||||
const resultProb = getCpmmProbability(newPool, contract.p)
|
const resultProb = getCpmmProbability(newPool, contract.p)
|
||||||
|
|
||||||
|
const openUserBets = userBets.filter((bet) => !bet.isSold && !bet.sale)
|
||||||
|
const [yesBets, noBets] = _.partition(
|
||||||
|
openUserBets,
|
||||||
|
(bet) => bet.outcome === 'YES'
|
||||||
|
)
|
||||||
|
const [yesShares, noShares] = [
|
||||||
|
_.sumBy(yesBets, (bet) => bet.shares),
|
||||||
|
_.sumBy(noBets, (bet) => bet.shares),
|
||||||
|
]
|
||||||
|
|
||||||
|
const sellOutcome = yesShares ? 'YES' : noShares ? 'NO' : undefined
|
||||||
|
const ownedShares = Math.round(yesShares) || Math.round(noShares)
|
||||||
|
|
||||||
|
const sharesSold = Math.min(amount ?? 0, ownedShares)
|
||||||
|
|
||||||
|
const { saleValue } = calculateCpmmSale(
|
||||||
|
contract,
|
||||||
|
sharesSold,
|
||||||
|
sellOutcome as 'YES' | 'NO'
|
||||||
|
)
|
||||||
|
|
||||||
|
const onAmountChange = (amount: number | undefined) => {
|
||||||
|
setAmount(amount)
|
||||||
|
|
||||||
|
// Check for errors.
|
||||||
|
if (amount !== undefined) {
|
||||||
|
if (amount > ownedShares) {
|
||||||
|
setError(`Maximum ${formatWithCommas(Math.floor(ownedShares))} shares`)
|
||||||
|
} else {
|
||||||
|
setError(undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SellAmountInput
|
<AmountInput
|
||||||
inputClassName="w-full"
|
|
||||||
contract={contract}
|
|
||||||
amount={
|
amount={
|
||||||
amount
|
amount
|
||||||
? Math.round(amount) === 0
|
? Math.round(amount) === 0
|
||||||
|
@ -449,15 +480,19 @@ export function SellPanel(props: {
|
||||||
: Math.floor(amount)
|
: Math.floor(amount)
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
onChange={setAmount}
|
onChange={onAmountChange}
|
||||||
userBets={userBets}
|
label="Qty"
|
||||||
error={error}
|
error={error}
|
||||||
setError={setError}
|
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
|
inputClassName="w-full"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Col className="mt-3 w-full gap-3">
|
<Col className="mt-3 w-full gap-3 text-sm">
|
||||||
<Row className="items-center justify-between text-sm">
|
<Row className="items-center justify-between gap-2 text-gray-500">
|
||||||
|
Sale proceeds
|
||||||
|
<span className="text-neutral">{formatMoney(saleValue)}</span>
|
||||||
|
</Row>
|
||||||
|
<Row className="items-center justify-between">
|
||||||
<div className="text-gray-500">Probability</div>
|
<div className="text-gray-500">Probability</div>
|
||||||
<div>
|
<div>
|
||||||
{formatPercent(initialProb)}
|
{formatPercent(initialProb)}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user