Simple limit order UI
This commit is contained in:
parent
dcaddd6a1a
commit
c4cec29c62
|
@ -1,6 +1,7 @@
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { partition, sumBy } from 'lodash'
|
import { partition, sumBy } from 'lodash'
|
||||||
|
import { SwitchHorizontalIcon } from '@heroicons/react/solid'
|
||||||
|
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
import { BinaryContract, CPMMBinaryContract } from 'common/contract'
|
import { BinaryContract, CPMMBinaryContract } from 'common/contract'
|
||||||
|
@ -38,6 +39,7 @@ import { SellRow } from './sell-row'
|
||||||
import { useSaveShares } from './use-save-shares'
|
import { useSaveShares } from './use-save-shares'
|
||||||
import { SignUpPrompt } from './sign-up-prompt'
|
import { SignUpPrompt } from './sign-up-prompt'
|
||||||
import { isIOS } from 'web/lib/util/device'
|
import { isIOS } from 'web/lib/util/device'
|
||||||
|
import { ProbabilityInput } from './probability-input'
|
||||||
|
|
||||||
export function BetPanel(props: {
|
export function BetPanel(props: {
|
||||||
contract: BinaryContract
|
contract: BinaryContract
|
||||||
|
@ -53,6 +55,8 @@ export function BetPanel(props: {
|
||||||
? 'NO'
|
? 'NO'
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
|
const [isLimitOrder, setIsLimitOrder] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className={className}>
|
<Col className={className}>
|
||||||
<SellRow
|
<SellRow
|
||||||
|
@ -62,15 +66,23 @@ export function BetPanel(props: {
|
||||||
/>
|
/>
|
||||||
<Col
|
<Col
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'rounded-b-md bg-white px-8 py-6',
|
'relative rounded-b-md bg-white px-8 py-6 pt-12',
|
||||||
!sharesOutcome && 'rounded-t-md',
|
!sharesOutcome && 'rounded-t-md',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="mb-6 text-2xl">Place your bet</div>
|
<button
|
||||||
{/* <Title className={clsx('!mt-0 text-neutral')} text="Place a trade" /> */}
|
className="btn btn-ghost btn-sm absolute right-3 top-1 mt-1 gap-2 self-end text-sm normal-case"
|
||||||
|
onClick={() => setIsLimitOrder(!isLimitOrder)}
|
||||||
|
>
|
||||||
|
<SwitchHorizontalIcon className="inline h-4 w-4" />
|
||||||
|
{isLimitOrder ? <>Simple bet</> : <>Limit bet</>}
|
||||||
|
</button>
|
||||||
|
<div className="mb-6 text-2xl">
|
||||||
|
{isLimitOrder ? <>Bet to a probability</> : <>Place your bet</>}
|
||||||
|
</div>
|
||||||
|
|
||||||
<BuyPanel contract={contract} user={user} />
|
<BuyPanel contract={contract} user={user} isLimitOrder={isLimitOrder} />
|
||||||
|
|
||||||
<SignUpPrompt />
|
<SignUpPrompt />
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -190,13 +202,19 @@ export function BetPanelSwitcher(props: {
|
||||||
function BuyPanel(props: {
|
function BuyPanel(props: {
|
||||||
contract: BinaryContract
|
contract: BinaryContract
|
||||||
user: User | null | undefined
|
user: User | null | undefined
|
||||||
|
isLimitOrder?: boolean
|
||||||
selected?: 'YES' | 'NO'
|
selected?: 'YES' | 'NO'
|
||||||
onBuySuccess?: () => void
|
onBuySuccess?: () => void
|
||||||
}) {
|
}) {
|
||||||
const { contract, user, selected, onBuySuccess } = props
|
const { contract, user, isLimitOrder, selected, onBuySuccess } = props
|
||||||
|
|
||||||
|
const initialProb = getProbability(contract)
|
||||||
|
|
||||||
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 [betProb, setBetProb] = useState<number | undefined>(
|
||||||
|
Math.round(100 * initialProb)
|
||||||
|
)
|
||||||
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 [wasSubmitted, setWasSubmitted] = useState(false)
|
||||||
|
@ -255,8 +273,6 @@ function BuyPanel(props: {
|
||||||
|
|
||||||
const betDisabled = isSubmitting || !betAmount || error
|
const betDisabled = isSubmitting || !betAmount || error
|
||||||
|
|
||||||
const initialProb = getProbability(contract)
|
|
||||||
|
|
||||||
const outcomeProb = getOutcomeProbabilityAfterBet(
|
const outcomeProb = getOutcomeProbabilityAfterBet(
|
||||||
contract,
|
contract,
|
||||||
betChoice || 'YES',
|
betChoice || 'YES',
|
||||||
|
@ -309,16 +325,32 @@ function BuyPanel(props: {
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
inputRef={inputRef}
|
inputRef={inputRef}
|
||||||
/>
|
/>
|
||||||
|
{isLimitOrder && (
|
||||||
<Col className="mt-3 w-full gap-3">
|
<>
|
||||||
<Row className="items-center justify-between text-sm">
|
<div className="my-3 text-left text-sm text-gray-500">
|
||||||
<div className="text-gray-500">Probability</div>
|
Probability
|
||||||
<div>
|
|
||||||
{formatPercent(initialProb)}
|
|
||||||
<span className="mx-2">→</span>
|
|
||||||
{formatPercent(resultProb)}
|
|
||||||
</div>
|
</div>
|
||||||
</Row>
|
<ProbabilityInput
|
||||||
|
inputClassName="w-full max-w-none"
|
||||||
|
prob={betProb}
|
||||||
|
onChange={setBetProb}
|
||||||
|
error={error}
|
||||||
|
setError={setError}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Col className="mt-3 w-full gap-3">
|
||||||
|
{!isLimitOrder && (
|
||||||
|
<Row className="items-center justify-between text-sm">
|
||||||
|
<div className="text-gray-500">Probability</div>
|
||||||
|
<div>
|
||||||
|
{formatPercent(initialProb)}
|
||||||
|
<span className="mx-2">→</span>
|
||||||
|
{formatPercent(resultProb)}
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
|
||||||
<Row className="items-center justify-between gap-2 text-sm">
|
<Row className="items-center 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">
|
||||||
|
|
55
web/components/probability-input.tsx
Normal file
55
web/components/probability-input.tsx
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import clsx from 'clsx'
|
||||||
|
import { Col } from './layout/col'
|
||||||
|
import { Spacer } from './layout/spacer'
|
||||||
|
|
||||||
|
export function ProbabilityInput(props: {
|
||||||
|
prob: number | undefined
|
||||||
|
onChange: (newProb: number | undefined) => void
|
||||||
|
error: string | undefined
|
||||||
|
setError: (error: string | undefined) => void
|
||||||
|
disabled?: boolean
|
||||||
|
className?: string
|
||||||
|
inputClassName?: string
|
||||||
|
}) {
|
||||||
|
const { prob, onChange, error, disabled, className, inputClassName } = props
|
||||||
|
|
||||||
|
const onProbChange = (str: string) => {
|
||||||
|
let prob = parseInt(str.replace(/\D/g, ''))
|
||||||
|
const isInvalid = !str || isNaN(prob)
|
||||||
|
if (prob.toString().length > 2) prob = +prob.toString().slice(0, 2)
|
||||||
|
onChange(isInvalid ? undefined : prob)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Col className={className}>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
className={clsx(
|
||||||
|
'input input-bordered max-w-[200px] text-lg',
|
||||||
|
error && 'input-error',
|
||||||
|
inputClassName
|
||||||
|
)}
|
||||||
|
type="number"
|
||||||
|
max={100}
|
||||||
|
min={0}
|
||||||
|
pattern="[0-9]*"
|
||||||
|
inputMode="numeric"
|
||||||
|
placeholder="0"
|
||||||
|
maxLength={2}
|
||||||
|
value={prob ?? ''}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={(e) => onProbChange(e.target.value)}
|
||||||
|
/>
|
||||||
|
<span className="bg-gray-200 text-sm">%</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<Spacer h={4} />
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="mb-2 mr-auto self-center whitespace-nowrap text-xs font-medium tracking-wide text-red-500">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user