Extract bet amount input to component.
This commit is contained in:
parent
6ef48af085
commit
7fbecbc102
|
@ -18,7 +18,7 @@ export function AddFundsButton(props: { className?: string }) {
|
||||||
<label
|
<label
|
||||||
htmlFor="add-funds"
|
htmlFor="add-funds"
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'btn btn-sm normal-case modal-button bg-gradient-to-r from-teal-500 to-green-500 hover:from-teal-600 hover:to-green-600 font-normal border-none',
|
'btn btn-xs normal-case modal-button bg-gradient-to-r from-teal-500 to-green-500 hover:from-teal-600 hover:to-green-600 font-normal border-none',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
79
web/components/amount-input.tsx
Normal file
79
web/components/amount-input.tsx
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import clsx from 'clsx'
|
||||||
|
import { useUser } from '../hooks/use-user'
|
||||||
|
import { formatMoney } from '../lib/util/format'
|
||||||
|
import { AddFundsButton } from './add-funds-button'
|
||||||
|
import { Col } from './layout/col'
|
||||||
|
import { Row } from './layout/row'
|
||||||
|
|
||||||
|
export function AmountInput(props: {
|
||||||
|
amount: number | undefined
|
||||||
|
onChange: (newAmount: number | undefined) => void
|
||||||
|
error: string | undefined
|
||||||
|
setError: (error: string | undefined) => void
|
||||||
|
disabled?: boolean
|
||||||
|
className?: string
|
||||||
|
inputClassName?: string
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
amount,
|
||||||
|
onChange,
|
||||||
|
error,
|
||||||
|
setError,
|
||||||
|
disabled,
|
||||||
|
className,
|
||||||
|
inputClassName,
|
||||||
|
} = props
|
||||||
|
|
||||||
|
const user = useUser()
|
||||||
|
|
||||||
|
const onAmountChange = (str: string) => {
|
||||||
|
const amount = parseInt(str.replace(/[^\d]/, ''))
|
||||||
|
|
||||||
|
if (str && isNaN(amount)) return
|
||||||
|
|
||||||
|
onChange(str ? amount : undefined)
|
||||||
|
|
||||||
|
if (user && user.balance < amount) setError('Insufficient balance')
|
||||||
|
else setError(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingBalance = (user?.balance ?? 0) - (amount ?? 0)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Col className={className}>
|
||||||
|
<label className="input-group">
|
||||||
|
<span className="text-sm bg-gray-200">M$</span>
|
||||||
|
<input
|
||||||
|
className={clsx(
|
||||||
|
'input input-bordered',
|
||||||
|
error && 'input-error',
|
||||||
|
inputClassName
|
||||||
|
)}
|
||||||
|
type="text"
|
||||||
|
placeholder="0"
|
||||||
|
maxLength={9}
|
||||||
|
value={amount ?? ''}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={(e) => onAmountChange(e.target.value)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
{user && (
|
||||||
|
<Row className="text-sm text-gray-500 justify-between mt-3 gap-4 items-end">
|
||||||
|
{error ? (
|
||||||
|
<div className="font-medium tracking-wide text-red-500 text-xs whitespace-nowrap mr-auto self-center">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Col>
|
||||||
|
<div className="whitespace-nowrap">Remaining balance</div>
|
||||||
|
<div className="text-neutral mt-1">
|
||||||
|
{formatMoney(Math.floor(remainingBalance))}
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
|
{user.balance !== 1000 && <AddFundsButton className="mt-1" />}
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
}
|
|
@ -20,11 +20,11 @@ import {
|
||||||
calculatePayoutAfterCorrectBet,
|
calculatePayoutAfterCorrectBet,
|
||||||
} from '../../common/calculate'
|
} from '../../common/calculate'
|
||||||
import { firebaseLogin } from '../lib/firebase/users'
|
import { firebaseLogin } from '../lib/firebase/users'
|
||||||
import { AddFundsButton } from './add-funds-button'
|
|
||||||
import { OutcomeLabel } from './outcome-label'
|
import { OutcomeLabel } from './outcome-label'
|
||||||
import { AdvancedPanel } from './advanced-panel'
|
import { AdvancedPanel } from './advanced-panel'
|
||||||
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 { AmountInput } from './amount-input'
|
||||||
|
|
||||||
export function BetPanel(props: { contract: Contract; className?: string }) {
|
export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -48,17 +48,9 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||||
setWasSubmitted(false)
|
setWasSubmitted(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBetChange(str: string) {
|
function onBetChange(newAmount: number | undefined) {
|
||||||
setWasSubmitted(false)
|
setWasSubmitted(false)
|
||||||
|
setBetAmount(newAmount)
|
||||||
const amount = parseInt(str.replace(/[^\d]/, ''))
|
|
||||||
|
|
||||||
if (str && isNaN(amount)) return
|
|
||||||
|
|
||||||
setBetAmount(str ? amount : undefined)
|
|
||||||
|
|
||||||
if (user && user.balance < amount) setError('Insufficient balance')
|
|
||||||
else setError(undefined)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitBet() {
|
async function submitBet() {
|
||||||
|
@ -106,8 +98,6 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||||
: 0
|
: 0
|
||||||
const estimatedReturnPercent = (estimatedReturn * 100).toFixed() + '%'
|
const estimatedReturnPercent = (estimatedReturn * 100).toFixed() + '%'
|
||||||
|
|
||||||
const remainingBalance = (user?.balance || 0) - (betAmount || 0)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col
|
<Col
|
||||||
className={clsx('bg-gray-100 shadow-md px-8 py-6 rounded-md', className)}
|
className={clsx('bg-gray-100 shadow-md px-8 py-6 rounded-md', className)}
|
||||||
|
@ -121,41 +111,17 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||||
onSelect={(choice) => onBetChoice(choice)}
|
onSelect={(choice) => onBetChoice(choice)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="mt-3 mb-1 text-sm text-gray-500">
|
<div className="my-3 text-sm text-gray-500">Amount </div>
|
||||||
Amount{' '}
|
<AmountInput
|
||||||
{user && (
|
inputClassName="w-full"
|
||||||
<span className="float-right">
|
amount={betAmount}
|
||||||
{formatMoney(
|
onChange={onBetChange}
|
||||||
remainingBalance > 0 ? Math.floor(remainingBalance) : 0
|
error={error}
|
||||||
)}{' '}
|
setError={setError}
|
||||||
left
|
disabled={isSubmitting}
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<Col className="my-2">
|
|
||||||
<label className="input-group">
|
|
||||||
<span className="text-sm bg-gray-200">M$</span>
|
|
||||||
<input
|
|
||||||
className={clsx(
|
|
||||||
'input input-bordered w-full',
|
|
||||||
error && 'input-error'
|
|
||||||
)}
|
|
||||||
type="text"
|
|
||||||
placeholder="0"
|
|
||||||
maxLength={9}
|
|
||||||
value={betAmount ?? ''}
|
|
||||||
onChange={(e) => onBetChange(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
|
||||||
{error && (
|
<Spacer h={4} />
|
||||||
<div className="font-medium tracking-wide text-red-500 text-xs mt-3">
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{user && user.balance !== 1000 && (
|
|
||||||
<AddFundsButton className="self-end mt-3" />
|
|
||||||
)}
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<div className="mt-2 mb-1 text-sm text-gray-500">Implied probability</div>
|
<div className="mt-2 mb-1 text-sm text-gray-500">Implied probability</div>
|
||||||
<Row>
|
<Row>
|
||||||
|
|
|
@ -10,10 +10,10 @@ import { Title } from '../components/title'
|
||||||
import { useUser } from '../hooks/use-user'
|
import { useUser } from '../hooks/use-user'
|
||||||
import { Contract, path } from '../lib/firebase/contracts'
|
import { Contract, path } from '../lib/firebase/contracts'
|
||||||
import { Page } from '../components/page'
|
import { Page } from '../components/page'
|
||||||
import { formatMoney } from '../lib/util/format'
|
|
||||||
import { AdvancedPanel } from '../components/advanced-panel'
|
import { AdvancedPanel } from '../components/advanced-panel'
|
||||||
import { createContract } from '../lib/firebase/api-call'
|
import { createContract } from '../lib/firebase/api-call'
|
||||||
import { Row } from '../components/layout/row'
|
import { Row } from '../components/layout/row'
|
||||||
|
import { AmountInput } from '../components/amount-input'
|
||||||
|
|
||||||
// Allow user to create a new contract
|
// Allow user to create a new contract
|
||||||
export default function NewContract() {
|
export default function NewContract() {
|
||||||
|
@ -33,7 +33,7 @@ export default function NewContract() {
|
||||||
const [description, setDescription] = useState('')
|
const [description, setDescription] = useState('')
|
||||||
|
|
||||||
const [ante, setAnte] = useState<number | undefined>(0)
|
const [ante, setAnte] = useState<number | undefined>(0)
|
||||||
const [anteError, setAnteError] = useState('')
|
const [anteError, setAnteError] = useState<string | undefined>()
|
||||||
const [closeDate, setCloseDate] = useState('')
|
const [closeDate, setCloseDate] = useState('')
|
||||||
|
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
|
@ -75,17 +75,6 @@ export default function NewContract() {
|
||||||
await router.push(path(result.contract as Contract))
|
await router.push(path(result.contract as Contract))
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAnteChange(str: string) {
|
|
||||||
const amount = parseInt(str.replace(/[^\d]/, ''))
|
|
||||||
|
|
||||||
if (str && isNaN(amount)) return
|
|
||||||
|
|
||||||
setAnte(str ? amount : undefined)
|
|
||||||
|
|
||||||
if (user && user.balance < amount) setAnteError('Insufficient balance')
|
|
||||||
else setAnteError('')
|
|
||||||
}
|
|
||||||
|
|
||||||
const descriptionPlaceholder = `e.g. This market will resolve to “Yes” if, by June 2, 2021, 11:59:59 PM ET, Paxlovid (also known under PF-07321332)...`
|
const descriptionPlaceholder = `e.g. This market will resolve to “Yes” if, by June 2, 2021, 11:59:59 PM ET, Paxlovid (also known under PF-07321332)...`
|
||||||
|
|
||||||
if (!creator) return <></>
|
if (!creator) return <></>
|
||||||
|
@ -166,33 +155,19 @@ export default function NewContract() {
|
||||||
<label className="label">
|
<label className="label">
|
||||||
<span className="mb-1">Subsidize your market</span>
|
<span className="mb-1">Subsidize your market</span>
|
||||||
</label>
|
</label>
|
||||||
|
<AmountInput
|
||||||
<label className="input-group">
|
className="items-start"
|
||||||
<span className="text-sm ">M$</span>
|
amount={ante}
|
||||||
<input
|
onChange={setAnte}
|
||||||
className={clsx(
|
error={anteError}
|
||||||
'input input-bordered',
|
setError={setAnteError}
|
||||||
anteError && 'input-error'
|
|
||||||
)}
|
|
||||||
type="text"
|
|
||||||
placeholder="0"
|
|
||||||
maxLength={9}
|
|
||||||
value={ante ?? ''}
|
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
onChange={(e) => onAnteChange(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<span className="label-text text-gray-500 ml-1">
|
|
||||||
Remaining balance:{' '}
|
|
||||||
{formatMoney(remainingBalance > 0 ? remainingBalance : 0)}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Spacer h={4} />
|
<Spacer h={4} />
|
||||||
|
|
||||||
<div className="form-control">
|
<div className="form-control items-start mb-1">
|
||||||
<label className="label">
|
<label className="label">
|
||||||
<span className="mb-1">Close date</span>
|
<span className="mb-1">Close date</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -208,8 +183,8 @@ export default function NewContract() {
|
||||||
</div>
|
</div>
|
||||||
<label>
|
<label>
|
||||||
<span className="label-text text-gray-500 ml-1">
|
<span className="label-text text-gray-500 ml-1">
|
||||||
No new trades will be allowed after{' '}
|
No trades allowed after this date
|
||||||
{closeDate ? formattedCloseTime : 'this time'}
|
{/* {closeDate ? formattedCloseTime : 'this date'} */}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</AdvancedPanel>
|
</AdvancedPanel>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user