parent
2fe9fe593d
commit
e17a59ae23
|
@ -5,7 +5,8 @@ import { formatMoney } from 'common/util/format'
|
||||||
import { Col } from './layout/col'
|
import { Col } from './layout/col'
|
||||||
import { SiteLink } from './site-link'
|
import { SiteLink } from './site-link'
|
||||||
import { ENV_CONFIG } from 'common/envs/constants'
|
import { ENV_CONFIG } from 'common/envs/constants'
|
||||||
import { useIsMobile } from 'web/hooks/use-is-mobile'
|
import { useWindowSize } from 'web/hooks/use-window-size'
|
||||||
|
import { Row } from './layout/row'
|
||||||
|
|
||||||
export function AmountInput(props: {
|
export function AmountInput(props: {
|
||||||
amount: number | undefined
|
amount: number | undefined
|
||||||
|
@ -34,15 +35,22 @@ export function AmountInput(props: {
|
||||||
const isInvalid = !str || isNaN(amount)
|
const isInvalid = !str || isNaN(amount)
|
||||||
onChange(isInvalid ? undefined : amount)
|
onChange(isInvalid ? undefined : amount)
|
||||||
}
|
}
|
||||||
const isMobile = useIsMobile(768)
|
|
||||||
|
const { width } = useWindowSize()
|
||||||
|
const isMobile = (width ?? 0) < 768
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Col className={className}>
|
<Col className={className}>
|
||||||
<label className="input-group mb-4">
|
<label className="font-sm md:font-lg">
|
||||||
<span className="bg-gray-200 text-sm">{label}</span>
|
<span className={clsx('text-greyscale-4 absolute ml-2 mt-[9px]')}>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
<input
|
<input
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'input input-bordered max-w-[200px] text-lg placeholder:text-gray-400',
|
'placeholder:text-greyscale-4 border-greyscale-2 rounded-md pl-9',
|
||||||
error && 'input-error',
|
error && 'input-error',
|
||||||
|
isMobile ? 'w-24' : '',
|
||||||
inputClassName
|
inputClassName
|
||||||
)}
|
)}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
|
@ -59,7 +67,7 @@ export function AmountInput(props: {
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mb-2 mr-auto self-center whitespace-nowrap text-xs font-medium tracking-wide text-red-500">
|
<div className="absolute mt-11 whitespace-nowrap text-xs font-medium tracking-wide text-red-500">
|
||||||
{error === 'Insufficient balance' ? (
|
{error === 'Insufficient balance' ? (
|
||||||
<>
|
<>
|
||||||
Not enough funds.
|
Not enough funds.
|
||||||
|
@ -73,6 +81,7 @@ export function AmountInput(props: {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +144,7 @@ export function BuyAmountInput(props: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Row className="gap-4">
|
||||||
<AmountInput
|
<AmountInput
|
||||||
amount={amount}
|
amount={amount}
|
||||||
onChange={onAmountChange}
|
onChange={onAmountChange}
|
||||||
|
@ -152,10 +162,11 @@ export function BuyAmountInput(props: {
|
||||||
max="205"
|
max="205"
|
||||||
value={getRaw(amount ?? 0)}
|
value={getRaw(amount ?? 0)}
|
||||||
onChange={(e) => onAmountChange(parseRaw(parseInt(e.target.value)))}
|
onChange={(e) => onAmountChange(parseRaw(parseInt(e.target.value)))}
|
||||||
className="range range-lg only-thumb z-40 mb-2 xl:hidden"
|
className="range range-lg only-thumb z-40 my-auto align-middle xl:hidden"
|
||||||
step="5"
|
step="5"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
</Row>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,9 +182,9 @@ export function AnswerBetPanel(props: {
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Spacer h={6} />
|
<Spacer h={6} />
|
||||||
|
|
||||||
{user ? (
|
{user ? (
|
||||||
<WarningConfirmationButton
|
<WarningConfirmationButton
|
||||||
|
amount={betAmount}
|
||||||
warning={warning}
|
warning={warning}
|
||||||
onSubmit={submitBet}
|
onSubmit={submitBet}
|
||||||
isSubmitting={isSubmitting}
|
isSubmitting={isSubmitting}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
import { SimpleBetPanel } from './bet-panel'
|
import { BuyPanel, SimpleBetPanel } from './bet-panel'
|
||||||
import { CPMMBinaryContract, PseudoNumericContract } from 'common/contract'
|
import {
|
||||||
|
BinaryContract,
|
||||||
|
CPMMBinaryContract,
|
||||||
|
PseudoNumericContract,
|
||||||
|
} from 'common/contract'
|
||||||
import { Modal } from './layout/modal'
|
import { Modal } from './layout/modal'
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
import { useUserContractBets } from 'web/hooks/use-user-bets'
|
import { useUserContractBets } from 'web/hooks/use-user-bets'
|
||||||
|
@ -10,6 +14,9 @@ import { useSaveBinaryShares } from './use-save-binary-shares'
|
||||||
import { Col } from './layout/col'
|
import { Col } from './layout/col'
|
||||||
import { Button } from 'web/components/button'
|
import { Button } from 'web/components/button'
|
||||||
import { BetSignUpPrompt } from './sign-up-prompt'
|
import { BetSignUpPrompt } from './sign-up-prompt'
|
||||||
|
import { User } from 'web/lib/firebase/users'
|
||||||
|
import { SellRow } from './sell-row'
|
||||||
|
import { useUnfilledBets } from 'web/hooks/use-bets'
|
||||||
|
|
||||||
/** Button that opens BetPanel in a new modal */
|
/** Button that opens BetPanel in a new modal */
|
||||||
export default function BetButton(props: {
|
export default function BetButton(props: {
|
||||||
|
@ -64,7 +71,6 @@ export default function BetButton(props: {
|
||||||
<SimpleBetPanel
|
<SimpleBetPanel
|
||||||
className={betPanelClassName}
|
className={betPanelClassName}
|
||||||
contract={contract}
|
contract={contract}
|
||||||
selected="YES"
|
|
||||||
onBetSuccess={() => setOpen(false)}
|
onBetSuccess={() => setOpen(false)}
|
||||||
hasShares={hasYesShares || hasNoShares}
|
hasShares={hasYesShares || hasNoShares}
|
||||||
/>
|
/>
|
||||||
|
@ -72,3 +78,44 @@ export default function BetButton(props: {
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function BinaryMobileBetting(props: { contract: BinaryContract }) {
|
||||||
|
const { contract } = props
|
||||||
|
const user = useUser()
|
||||||
|
if (user) {
|
||||||
|
return <SignedInBinaryMobileBetting contract={contract} user={user} />
|
||||||
|
} else {
|
||||||
|
return <BetSignUpPrompt className="w-full" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignedInBinaryMobileBetting(props: {
|
||||||
|
contract: BinaryContract
|
||||||
|
user: User
|
||||||
|
}) {
|
||||||
|
const { contract, user } = props
|
||||||
|
const unfilledBets = useUnfilledBets(contract.id) ?? []
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Col className="w-full gap-2 px-1">
|
||||||
|
<Col>
|
||||||
|
<BuyPanel
|
||||||
|
hidden={false}
|
||||||
|
contract={contract as CPMMBinaryContract}
|
||||||
|
user={user}
|
||||||
|
unfilledBets={unfilledBets}
|
||||||
|
mobileView={true}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<SellRow
|
||||||
|
contract={contract}
|
||||||
|
user={user}
|
||||||
|
className={
|
||||||
|
'border-greyscale-3 bg-greyscale-1 rounded-md border-2 px-4 py-2'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -43,6 +43,11 @@ import { PlayMoneyDisclaimer } from './play-money-disclaimer'
|
||||||
import { isAndroid, isIOS } from 'web/lib/util/device'
|
import { isAndroid, isIOS } from 'web/lib/util/device'
|
||||||
import { WarningConfirmationButton } from './warning-confirmation-button'
|
import { WarningConfirmationButton } from './warning-confirmation-button'
|
||||||
import { MarketIntroPanel } from './market-intro-panel'
|
import { MarketIntroPanel } from './market-intro-panel'
|
||||||
|
import { Modal } from './layout/modal'
|
||||||
|
import { Title } from './title'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
import { CheckIcon } from '@heroicons/react/solid'
|
||||||
|
import { useWindowSize } from 'web/hooks/use-window-size'
|
||||||
|
|
||||||
export function BetPanel(props: {
|
export function BetPanel(props: {
|
||||||
contract: CPMMBinaryContract | PseudoNumericContract
|
contract: CPMMBinaryContract | PseudoNumericContract
|
||||||
|
@ -105,11 +110,10 @@ export function BetPanel(props: {
|
||||||
export function SimpleBetPanel(props: {
|
export function SimpleBetPanel(props: {
|
||||||
contract: CPMMBinaryContract | PseudoNumericContract
|
contract: CPMMBinaryContract | PseudoNumericContract
|
||||||
className?: string
|
className?: string
|
||||||
selected?: 'YES' | 'NO'
|
|
||||||
hasShares?: boolean
|
hasShares?: boolean
|
||||||
onBetSuccess?: () => void
|
onBetSuccess?: () => void
|
||||||
}) {
|
}) {
|
||||||
const { contract, className, selected, hasShares, onBetSuccess } = props
|
const { contract, className, hasShares, onBetSuccess } = props
|
||||||
|
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const [isLimitOrder, setIsLimitOrder] = useState(false)
|
const [isLimitOrder, setIsLimitOrder] = useState(false)
|
||||||
|
@ -139,7 +143,6 @@ export function SimpleBetPanel(props: {
|
||||||
contract={contract}
|
contract={contract}
|
||||||
user={user}
|
user={user}
|
||||||
unfilledBets={unfilledBets}
|
unfilledBets={unfilledBets}
|
||||||
selected={selected}
|
|
||||||
onBuySuccess={onBetSuccess}
|
onBuySuccess={onBetSuccess}
|
||||||
/>
|
/>
|
||||||
<LimitOrderPanel
|
<LimitOrderPanel
|
||||||
|
@ -162,38 +165,52 @@ export function SimpleBetPanel(props: {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function BuyPanel(props: {
|
export function BuyPanel(props: {
|
||||||
contract: CPMMBinaryContract | PseudoNumericContract
|
contract: CPMMBinaryContract | PseudoNumericContract
|
||||||
user: User | null | undefined
|
user: User | null | undefined
|
||||||
unfilledBets: Bet[]
|
unfilledBets: Bet[]
|
||||||
hidden: boolean
|
hidden: boolean
|
||||||
selected?: 'YES' | 'NO'
|
|
||||||
onBuySuccess?: () => void
|
onBuySuccess?: () => void
|
||||||
|
mobileView?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { contract, user, unfilledBets, hidden, selected, onBuySuccess } = props
|
const { contract, user, unfilledBets, hidden, onBuySuccess, mobileView } =
|
||||||
|
props
|
||||||
|
|
||||||
const initialProb = getProbability(contract)
|
const initialProb = getProbability(contract)
|
||||||
const isPseudoNumeric = contract.outcomeType === 'PSEUDO_NUMERIC'
|
const isPseudoNumeric = contract.outcomeType === 'PSEUDO_NUMERIC'
|
||||||
|
|
||||||
const [outcome, setOutcome] = useState<'YES' | 'NO' | undefined>(selected)
|
const windowSize = useWindowSize()
|
||||||
const [betAmount, setBetAmount] = useState<number | undefined>(undefined)
|
const initialOutcome =
|
||||||
|
windowSize.width && windowSize.width >= 1280 ? 'YES' : undefined
|
||||||
|
const [outcome, setOutcome] = useState<'YES' | 'NO' | undefined>(
|
||||||
|
initialOutcome
|
||||||
|
)
|
||||||
|
const [betAmount, setBetAmount] = useState<number | undefined>(10)
|
||||||
const [error, setError] = useState<string | undefined>()
|
const [error, setError] = useState<string | undefined>()
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
const [wasSubmitted, setWasSubmitted] = useState(false)
|
|
||||||
|
|
||||||
const [inputRef, focusAmountInput] = useFocus()
|
const [inputRef, focusAmountInput] = useFocus()
|
||||||
|
|
||||||
function onBetChoice(choice: 'YES' | 'NO') {
|
function onBetChoice(choice: 'YES' | 'NO') {
|
||||||
setOutcome(choice)
|
setOutcome(choice)
|
||||||
setWasSubmitted(false)
|
|
||||||
|
|
||||||
if (!isIOS() && !isAndroid()) {
|
if (!isIOS() && !isAndroid()) {
|
||||||
focusAmountInput()
|
focusAmountInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mobileOnBetChoice(choice: 'YES' | 'NO' | undefined) {
|
||||||
|
if (outcome === choice) {
|
||||||
|
setOutcome(undefined)
|
||||||
|
} else {
|
||||||
|
setOutcome(choice)
|
||||||
|
}
|
||||||
|
if (!isIOS() && !isAndroid()) {
|
||||||
|
focusAmountInput()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onBetChange(newAmount: number | undefined) {
|
function onBetChange(newAmount: number | undefined) {
|
||||||
setWasSubmitted(false)
|
|
||||||
setBetAmount(newAmount)
|
setBetAmount(newAmount)
|
||||||
if (!outcome) {
|
if (!outcome) {
|
||||||
setOutcome('YES')
|
setOutcome('YES')
|
||||||
|
@ -214,9 +231,13 @@ function BuyPanel(props: {
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
console.log('placed bet. Result:', r)
|
console.log('placed bet. Result:', r)
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
setWasSubmitted(true)
|
|
||||||
setBetAmount(undefined)
|
setBetAmount(undefined)
|
||||||
if (onBuySuccess) onBuySuccess()
|
if (onBuySuccess) onBuySuccess()
|
||||||
|
else {
|
||||||
|
toast('Trade submitted!', {
|
||||||
|
icon: <CheckIcon className={'text-primary h-5 w-5'} />,
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (e instanceof APIError) {
|
if (e instanceof APIError) {
|
||||||
|
@ -249,6 +270,7 @@ function BuyPanel(props: {
|
||||||
unfilledBets as LimitBet[]
|
unfilledBets as LimitBet[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const [seeLimit, setSeeLimit] = useState(false)
|
||||||
const resultProb = getCpmmProbability(newPool, newP)
|
const resultProb = getCpmmProbability(newPool, newP)
|
||||||
const probStayedSame =
|
const probStayedSame =
|
||||||
formatPercent(resultProb) === formatPercent(initialProb)
|
formatPercent(resultProb) === formatPercent(initialProb)
|
||||||
|
@ -281,22 +303,79 @@ function BuyPanel(props: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className={hidden ? 'hidden' : ''}>
|
<Col className={hidden ? 'hidden' : ''}>
|
||||||
<div className="my-3 text-left text-sm text-gray-500">
|
|
||||||
{isPseudoNumeric ? 'Direction' : 'Outcome'}
|
|
||||||
</div>
|
|
||||||
<YesNoSelector
|
<YesNoSelector
|
||||||
className="mb-4"
|
className="mb-4"
|
||||||
btnClassName="flex-1"
|
btnClassName="flex-1"
|
||||||
selected={outcome}
|
selected={outcome}
|
||||||
onSelect={(choice) => onBetChoice(choice)}
|
onSelect={(choice) => {
|
||||||
|
if (mobileView) {
|
||||||
|
mobileOnBetChoice(choice)
|
||||||
|
} else {
|
||||||
|
onBetChoice(choice)
|
||||||
|
}
|
||||||
|
}}
|
||||||
isPseudoNumeric={isPseudoNumeric}
|
isPseudoNumeric={isPseudoNumeric}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Row className="my-3 justify-between text-left text-sm text-gray-500">
|
<Col
|
||||||
Amount
|
className={clsx(
|
||||||
<span className={'xl:hidden'}>
|
mobileView
|
||||||
Balance: {formatMoney(user?.balance ?? 0)}
|
? outcome === 'NO'
|
||||||
|
? 'bg-red-25'
|
||||||
|
: outcome === 'YES'
|
||||||
|
? 'bg-teal-50'
|
||||||
|
: 'hidden'
|
||||||
|
: 'bg-white',
|
||||||
|
mobileView ? 'rounded-lg px-4 py-2' : 'px-0'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Row className="mt-3 w-full gap-3">
|
||||||
|
<Col className="w-1/2 text-sm">
|
||||||
|
<Col className="text-greyscale-4 flex-nowrap whitespace-nowrap text-xs">
|
||||||
|
<div>
|
||||||
|
{isPseudoNumeric ? (
|
||||||
|
'Max payout'
|
||||||
|
) : (
|
||||||
|
<>Payout if {outcome ?? 'YES'}</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<div>
|
||||||
|
<span className="whitespace-nowrap text-xl">
|
||||||
|
{formatMoney(currentPayout)}
|
||||||
</span>
|
</span>
|
||||||
|
<span className="text-greyscale-4 text-xs">
|
||||||
|
{' '}
|
||||||
|
+{currentReturnPercent}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col className="w-1/2 text-sm">
|
||||||
|
<div className="text-greyscale-4 text-xs">
|
||||||
|
{isPseudoNumeric ? 'Estimated value' : 'New Probability'}
|
||||||
|
</div>
|
||||||
|
{probStayedSame ? (
|
||||||
|
<div className="text-xl">{format(initialProb)}</div>
|
||||||
|
) : (
|
||||||
|
<div className="text-xl">
|
||||||
|
{format(resultProb)}
|
||||||
|
<span className={clsx('text-greyscale-4 text-xs')}>
|
||||||
|
{isPseudoNumeric ? (
|
||||||
|
<></>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{' '}
|
||||||
|
{outcome != 'NO' && '+'}
|
||||||
|
{format(resultProb - initialProb)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row className="text-greyscale-4 mt-4 mb-1 justify-between text-left text-xs">
|
||||||
|
Amount
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<BuyAmountInput
|
<BuyAmountInput
|
||||||
|
@ -310,63 +389,46 @@ function BuyPanel(props: {
|
||||||
showSliderOnMobile
|
showSliderOnMobile
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Col className="mt-3 w-full gap-3">
|
|
||||||
<Row className="items-center justify-between text-sm">
|
|
||||||
<div className="text-gray-500">
|
|
||||||
{isPseudoNumeric ? 'Estimated value' : 'Probability'}
|
|
||||||
</div>
|
|
||||||
{probStayedSame ? (
|
|
||||||
<div>{format(initialProb)}</div>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
{format(initialProb)}
|
|
||||||
<span className="mx-2">→</span>
|
|
||||||
{format(resultProb)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Row className="items-center justify-between gap-2 text-sm">
|
|
||||||
<Row className="flex-nowrap items-center gap-2 whitespace-nowrap text-gray-500">
|
|
||||||
<div>
|
|
||||||
{isPseudoNumeric ? (
|
|
||||||
'Max payout'
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
Payout if <BinaryOutcomeLabel outcome={outcome ?? 'YES'} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Row>
|
|
||||||
<div>
|
|
||||||
<span className="mr-2 whitespace-nowrap">
|
|
||||||
{formatMoney(currentPayout)}
|
|
||||||
</span>
|
|
||||||
(+{currentReturnPercent})
|
|
||||||
</div>
|
|
||||||
</Row>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Spacer h={8} />
|
<Spacer h={8} />
|
||||||
|
|
||||||
{user && (
|
{user && (
|
||||||
<WarningConfirmationButton
|
<WarningConfirmationButton
|
||||||
|
amount={betAmount}
|
||||||
|
outcome={outcome}
|
||||||
warning={warning}
|
warning={warning}
|
||||||
onSubmit={submitBet}
|
onSubmit={submitBet}
|
||||||
isSubmitting={isSubmitting}
|
isSubmitting={isSubmitting}
|
||||||
disabled={!!betDisabled}
|
|
||||||
openModalButtonClass={clsx(
|
openModalButtonClass={clsx(
|
||||||
'btn mb-2 flex-1',
|
'btn mb-2 flex-1',
|
||||||
betDisabled
|
betDisabled
|
||||||
? 'btn-disabled'
|
? 'btn-disabled bg-greyscale-1'
|
||||||
: outcome === 'YES'
|
: outcome === 'NO'
|
||||||
? 'btn-primary'
|
? 'border-none bg-red-400 hover:bg-red-500'
|
||||||
: 'border-none bg-red-400 hover:bg-red-500'
|
: 'border-none bg-teal-500 hover:bg-teal-600'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<button
|
||||||
{wasSubmitted && <div className="mt-4">Trade submitted!</div>}
|
className="text-greyscale-6 mx-auto select-none text-sm underline xl:hidden"
|
||||||
|
onClick={() => setSeeLimit(true)}
|
||||||
|
>
|
||||||
|
Advanced
|
||||||
|
</button>
|
||||||
|
<Modal
|
||||||
|
open={seeLimit}
|
||||||
|
setOpen={setSeeLimit}
|
||||||
|
position="center"
|
||||||
|
className="rounded-lg bg-white px-4 pb-8"
|
||||||
|
>
|
||||||
|
<Title text="Limit Order" />
|
||||||
|
<LimitOrderPanel
|
||||||
|
hidden={!seeLimit}
|
||||||
|
contract={contract}
|
||||||
|
user={user}
|
||||||
|
unfilledBets={unfilledBets}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
</Col>
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -389,7 +451,6 @@ function LimitOrderPanel(props: {
|
||||||
const betChoice = 'YES'
|
const betChoice = 'YES'
|
||||||
const [error, setError] = useState<string | undefined>()
|
const [error, setError] = useState<string | undefined>()
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
const [wasSubmitted, setWasSubmitted] = useState(false)
|
|
||||||
|
|
||||||
const rangeError =
|
const rangeError =
|
||||||
lowLimitProb !== undefined &&
|
lowLimitProb !== undefined &&
|
||||||
|
@ -437,7 +498,6 @@ function LimitOrderPanel(props: {
|
||||||
const noAmount = shares * (1 - (noLimitProb ?? 0))
|
const noAmount = shares * (1 - (noLimitProb ?? 0))
|
||||||
|
|
||||||
function onBetChange(newAmount: number | undefined) {
|
function onBetChange(newAmount: number | undefined) {
|
||||||
setWasSubmitted(false)
|
|
||||||
setBetAmount(newAmount)
|
setBetAmount(newAmount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,7 +542,6 @@ function LimitOrderPanel(props: {
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
console.log('placed bet. Result:', r)
|
console.log('placed bet. Result:', r)
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
setWasSubmitted(true)
|
|
||||||
setBetAmount(undefined)
|
setBetAmount(undefined)
|
||||||
setLowLimitProb(undefined)
|
setLowLimitProb(undefined)
|
||||||
setHighLimitProb(undefined)
|
setHighLimitProb(undefined)
|
||||||
|
@ -718,8 +777,6 @@ function LimitOrderPanel(props: {
|
||||||
: `Submit order${hasTwoBets ? 's' : ''}`}
|
: `Submit order${hasTwoBets ? 's' : ''}`}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{wasSubmitted && <div className="mt-4">Order submitted!</div>}
|
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -866,11 +923,7 @@ export function SellPanel(props: {
|
||||||
<>
|
<>
|
||||||
<AmountInput
|
<AmountInput
|
||||||
amount={
|
amount={
|
||||||
amount
|
amount ? (Math.round(amount) === 0 ? 0 : Math.floor(amount)) : 0
|
||||||
? Math.round(amount) === 0
|
|
||||||
? 0
|
|
||||||
: Math.floor(amount)
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
onChange={onAmountChange}
|
onChange={onAmountChange}
|
||||||
label="Qty"
|
label="Qty"
|
||||||
|
|
|
@ -13,17 +13,16 @@ import {
|
||||||
PseudoNumericResolutionOrExpectation,
|
PseudoNumericResolutionOrExpectation,
|
||||||
} from './contract-card'
|
} from './contract-card'
|
||||||
import { Bet } from 'common/bet'
|
import { Bet } from 'common/bet'
|
||||||
import BetButton from '../bet-button'
|
import BetButton, { BinaryMobileBetting } from '../bet-button'
|
||||||
import { AnswersGraph } from '../answers/answers-graph'
|
import { AnswersGraph } from '../answers/answers-graph'
|
||||||
import {
|
import {
|
||||||
Contract,
|
Contract,
|
||||||
BinaryContract,
|
|
||||||
CPMMContract,
|
CPMMContract,
|
||||||
CPMMBinaryContract,
|
|
||||||
FreeResponseContract,
|
FreeResponseContract,
|
||||||
MultipleChoiceContract,
|
MultipleChoiceContract,
|
||||||
NumericContract,
|
NumericContract,
|
||||||
PseudoNumericContract,
|
PseudoNumericContract,
|
||||||
|
BinaryContract,
|
||||||
} from 'common/contract'
|
} from 'common/contract'
|
||||||
import { ContractDetails } from './contract-details'
|
import { ContractDetails } from './contract-details'
|
||||||
import { NumericGraph } from './numeric-graph'
|
import { NumericGraph } from './numeric-graph'
|
||||||
|
@ -78,19 +77,18 @@ const BinaryOverview = (props: { contract: BinaryContract; bets: Bet[] }) => {
|
||||||
<Row className="justify-between gap-4">
|
<Row className="justify-between gap-4">
|
||||||
<OverviewQuestion text={contract.question} />
|
<OverviewQuestion text={contract.question} />
|
||||||
<BinaryResolutionOrChance
|
<BinaryResolutionOrChance
|
||||||
className="hidden items-end xl:flex"
|
className="flex items-end"
|
||||||
contract={contract}
|
contract={contract}
|
||||||
large
|
large
|
||||||
/>
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
<Row className="items-center justify-between gap-4 xl:hidden">
|
|
||||||
<BinaryResolutionOrChance contract={contract} />
|
|
||||||
{tradingAllowed(contract) && (
|
|
||||||
<BetWidget contract={contract as CPMMBinaryContract} />
|
|
||||||
)}
|
|
||||||
</Row>
|
|
||||||
</Col>
|
</Col>
|
||||||
<ContractProbGraph contract={contract} bets={[...bets].reverse()} />
|
<ContractProbGraph contract={contract} bets={[...bets].reverse()} />
|
||||||
|
<Row className="items-center justify-between gap-4 xl:hidden">
|
||||||
|
{tradingAllowed(contract) && (
|
||||||
|
<BinaryMobileBetting contract={contract} />
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -344,7 +344,7 @@ export function getColor(contract: Contract) {
|
||||||
return (
|
return (
|
||||||
OUTCOME_TO_COLOR[resolution as resolution] ??
|
OUTCOME_TO_COLOR[resolution as resolution] ??
|
||||||
// If resolved to a FR answer, use 'primary'
|
// If resolved to a FR answer, use 'primary'
|
||||||
'primary'
|
'teal-500'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,5 +355,5 @@ export function getColor(contract: Contract) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Not sure why eg green-400 doesn't work here; try upgrading Tailwind
|
// TODO: Not sure why eg green-400 doesn't work here; try upgrading Tailwind
|
||||||
return 'primary'
|
return 'teal-500'
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ export const OUTCOME_TO_COLOR = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function YesLabel() {
|
export function YesLabel() {
|
||||||
return <span className="text-primary">YES</span>
|
return <span className="text-teal-500">YES</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HigherLabel() {
|
export function HigherLabel() {
|
||||||
|
|
|
@ -4,8 +4,11 @@ import React from 'react'
|
||||||
import { Row } from './layout/row'
|
import { Row } from './layout/row'
|
||||||
import { ConfirmationButton } from './confirmation-button'
|
import { ConfirmationButton } from './confirmation-button'
|
||||||
import { ExclamationIcon } from '@heroicons/react/solid'
|
import { ExclamationIcon } from '@heroicons/react/solid'
|
||||||
|
import { formatMoney } from 'common/util/format'
|
||||||
|
|
||||||
export function WarningConfirmationButton(props: {
|
export function WarningConfirmationButton(props: {
|
||||||
|
amount: number | undefined
|
||||||
|
outcome?: 'YES' | 'NO' | undefined
|
||||||
warning?: string
|
warning?: string
|
||||||
onSubmit: () => void
|
onSubmit: () => void
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
|
@ -14,12 +17,14 @@ export function WarningConfirmationButton(props: {
|
||||||
submitButtonClassName?: string
|
submitButtonClassName?: string
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
|
amount,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
warning,
|
warning,
|
||||||
disabled,
|
disabled,
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
openModalButtonClass,
|
openModalButtonClass,
|
||||||
submitButtonClassName,
|
submitButtonClassName,
|
||||||
|
outcome,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
if (!warning) {
|
if (!warning) {
|
||||||
|
@ -28,12 +33,15 @@ export function WarningConfirmationButton(props: {
|
||||||
className={clsx(
|
className={clsx(
|
||||||
openModalButtonClass,
|
openModalButtonClass,
|
||||||
isSubmitting ? 'loading' : '',
|
isSubmitting ? 'loading' : '',
|
||||||
disabled && 'btn-disabled'
|
(disabled || !outcome) && 'btn-disabled bg-greyscale-2'
|
||||||
)}
|
)}
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
disabled={disabled}
|
|
||||||
>
|
>
|
||||||
{isSubmitting ? 'Submitting...' : 'Submit'}
|
{isSubmitting
|
||||||
|
? 'Submitting...'
|
||||||
|
: amount
|
||||||
|
? `Wager ${formatMoney(amount)}`
|
||||||
|
: 'Wager'}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -45,7 +53,7 @@ export function WarningConfirmationButton(props: {
|
||||||
openModalButtonClass,
|
openModalButtonClass,
|
||||||
isSubmitting && 'btn-disabled loading'
|
isSubmitting && 'btn-disabled loading'
|
||||||
),
|
),
|
||||||
label: 'Submit',
|
label: amount ? `Wager ${formatMoney(amount)}` : 'Wager',
|
||||||
}}
|
}}
|
||||||
cancelBtn={{
|
cancelBtn={{
|
||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
|
|
|
@ -35,10 +35,11 @@ export function YesNoSelector(props: {
|
||||||
<button
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
commonClassNames,
|
commonClassNames,
|
||||||
'hover:bg-primary-focus border-primary hover:border-primary-focus hover:text-white',
|
|
||||||
selected == 'YES'
|
selected == 'YES'
|
||||||
? 'bg-primary text-white'
|
? 'border-teal-500 bg-teal-500 text-white'
|
||||||
: 'text-primary bg-white',
|
: selected == 'NO'
|
||||||
|
? 'border-greyscale-3 text-greyscale-3 bg-white hover:border-teal-500 hover:text-teal-500'
|
||||||
|
: 'border-teal-500 bg-white text-teal-500 hover:bg-teal-50',
|
||||||
btnClassName
|
btnClassName
|
||||||
)}
|
)}
|
||||||
onClick={() => onSelect('YES')}
|
onClick={() => onSelect('YES')}
|
||||||
|
@ -52,10 +53,11 @@ export function YesNoSelector(props: {
|
||||||
<button
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
commonClassNames,
|
commonClassNames,
|
||||||
'border-red-400 hover:border-red-500 hover:bg-red-500 hover:text-white',
|
|
||||||
selected == 'NO'
|
selected == 'NO'
|
||||||
? 'bg-red-400 text-white'
|
? 'border-red-400 bg-red-400 text-white'
|
||||||
: 'bg-white text-red-400',
|
: selected == 'YES'
|
||||||
|
? 'border-greyscale-3 text-greyscale-3 bg-white hover:border-red-400 hover:text-red-400'
|
||||||
|
: 'border-red-400 bg-white text-red-400 hover:bg-red-50',
|
||||||
btnClassName
|
btnClassName
|
||||||
)}
|
)}
|
||||||
onClick={() => onSelect('NO')}
|
onClick={() => onSelect('NO')}
|
||||||
|
|
|
@ -16,6 +16,7 @@ module.exports = {
|
||||||
),
|
),
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
|
'red-25': '#FDF7F6',
|
||||||
'greyscale-1': '#FBFBFF',
|
'greyscale-1': '#FBFBFF',
|
||||||
'greyscale-2': '#E7E7F4',
|
'greyscale-2': '#E7E7F4',
|
||||||
'greyscale-3': '#D8D8EB',
|
'greyscale-3': '#D8D8EB',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user