Compare commits
1 Commits
main
...
no-bet-pan
Author | SHA1 | Date | |
---|---|---|---|
|
96d7f27819 |
|
@ -7,12 +7,27 @@ const formatter = new Intl.NumberFormat('en-US', {
|
||||||
minimumFractionDigits: 0,
|
minimumFractionDigits: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const formatterCents = new Intl.NumberFormat('en-US', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'USD',
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
})
|
||||||
|
|
||||||
export function formatMoney(amount: number) {
|
export function formatMoney(amount: number) {
|
||||||
const newAmount = Math.round(amount) === 0 ? 0 : amount // handle -0 case
|
const newAmount = Math.round(amount) === 0 ? 0 : amount // handle -0 case
|
||||||
return (
|
return (
|
||||||
ENV_CONFIG.moneyMoniker + ' ' + formatter.format(newAmount).replace('$', '')
|
ENV_CONFIG.moneyMoniker + ' ' + formatter.format(newAmount).replace('$', '')
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
export function formatCents(probability: number) {
|
||||||
|
const newAmount = Math.round(probability * 100) === 0 ? 0 : probability // handle -0 case
|
||||||
|
return (
|
||||||
|
ENV_CONFIG.moneyMoniker +
|
||||||
|
' ' +
|
||||||
|
formatterCents.format(newAmount).replace('$', '')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function formatWithCommas(amount: number) {
|
export function formatWithCommas(amount: number) {
|
||||||
return formatter.format(amount).replace('$', '')
|
return formatter.format(amount).replace('$', '')
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { InfoTooltip } from './info-tooltip'
|
||||||
import { Spacer } from './layout/spacer'
|
import { Spacer } from './layout/spacer'
|
||||||
import { calculateCpmmSale } from '../../common/calculate-cpmm'
|
import { calculateCpmmSale } from '../../common/calculate-cpmm'
|
||||||
import { Binary, CPMM, FullContract } from '../../common/contract'
|
import { Binary, CPMM, FullContract } from '../../common/contract'
|
||||||
|
import { ENV_CONFIG } from '../../common/envs/constants'
|
||||||
|
|
||||||
export function AmountInput(props: {
|
export function AmountInput(props: {
|
||||||
amount: number | undefined
|
amount: number | undefined
|
||||||
|
@ -50,10 +51,10 @@ export function AmountInput(props: {
|
||||||
return (
|
return (
|
||||||
<Col className={className}>
|
<Col className={className}>
|
||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<span className="bg-gray-200 text-sm">{label}</span>
|
<span className="bg-gray-200 text-lg">{label}</span>
|
||||||
<input
|
<input
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'input input-bordered',
|
'input input-bordered text-lg',
|
||||||
error && 'input-error',
|
error && 'input-error',
|
||||||
inputClassName
|
inputClassName
|
||||||
)}
|
)}
|
||||||
|
@ -119,6 +120,10 @@ export function BuyAmountInput(props: {
|
||||||
? Math.min(amount ?? 0, MAX_LOAN_PER_CONTRACT - prevLoanAmount)
|
? Math.min(amount ?? 0, MAX_LOAN_PER_CONTRACT - prevLoanAmount)
|
||||||
: 0
|
: 0
|
||||||
|
|
||||||
|
const remainingBalance = Math.floor(
|
||||||
|
(user?.balance ?? 0) - (amount ?? 0) + loanAmount
|
||||||
|
)
|
||||||
|
|
||||||
const onAmountChange = (amount: number | undefined) => {
|
const onAmountChange = (amount: number | undefined) => {
|
||||||
onChange(amount)
|
onChange(amount)
|
||||||
|
|
||||||
|
@ -140,7 +145,7 @@ export function BuyAmountInput(props: {
|
||||||
<AmountInput
|
<AmountInput
|
||||||
amount={amount}
|
amount={amount}
|
||||||
onChange={onAmountChange}
|
onChange={onAmountChange}
|
||||||
label="M$"
|
label={ENV_CONFIG.moneyMoniker}
|
||||||
error={error}
|
error={error}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={className}
|
className={className}
|
||||||
|
@ -148,10 +153,10 @@ export function BuyAmountInput(props: {
|
||||||
inputRef={inputRef}
|
inputRef={inputRef}
|
||||||
>
|
>
|
||||||
{user && (
|
{user && (
|
||||||
<Col className="gap-3 text-sm">
|
<Col className="gap-3">
|
||||||
{contractIdForLoan && (
|
{contractIdForLoan && (
|
||||||
<Row className="items-center justify-between gap-2 text-gray-500">
|
<Row className="items-center justify-between gap-2 text-gray-500">
|
||||||
<Row className="items-center gap-2">
|
<Row className="items-center gap-2 text-sm">
|
||||||
Amount loaned{' '}
|
Amount loaned{' '}
|
||||||
<InfoTooltip
|
<InfoTooltip
|
||||||
text={`In every market, you get an interest-free loan on the first ${formatMoney(
|
text={`In every market, you get an interest-free loan on the first ${formatMoney(
|
||||||
|
|
|
@ -103,7 +103,7 @@ export function AnswerBetPanel(props: {
|
||||||
<Col className={clsx('px-2 pb-2 pt-4 sm:pt-0', className)}>
|
<Col className={clsx('px-2 pb-2 pt-4 sm:pt-0', className)}>
|
||||||
<Row className="items-center justify-between self-stretch">
|
<Row className="items-center justify-between self-stretch">
|
||||||
<div className="text-xl">
|
<div className="text-xl">
|
||||||
Buy {isModal ? `"${answer.text}"` : 'this answer'}
|
Bet on {isModal ? `"${answer.text}"` : 'this answer'}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isModal && (
|
{!isModal && (
|
||||||
|
|
|
@ -94,7 +94,7 @@ export function BetPanel(props: {
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Title className={clsx('!mt-0')} text="Place a trade" />
|
<div className={clsx('mb-6 text-2xl')}> Place a trade</div>
|
||||||
|
|
||||||
<BuyPanel contract={contract} user={user} userBets={userBets ?? []} />
|
<BuyPanel contract={contract} user={user} userBets={userBets ?? []} />
|
||||||
|
|
||||||
|
@ -304,6 +304,12 @@ function BuyPanel(props: {
|
||||||
const currentReturn = betAmount ? (currentPayout - betAmount) / betAmount : 0
|
const currentReturn = betAmount ? (currentPayout - betAmount) / betAmount : 0
|
||||||
const currentReturnPercent = formatPercent(currentReturn)
|
const currentReturnPercent = formatPercent(currentReturn)
|
||||||
|
|
||||||
|
const averagePrice = betAmount
|
||||||
|
? betAmount / currentPayout
|
||||||
|
: betChoice === 'NO'
|
||||||
|
? 1 - initialProb
|
||||||
|
: initialProb
|
||||||
|
|
||||||
const dpmTooltip =
|
const dpmTooltip =
|
||||||
contract.mechanism === 'dpm-2'
|
contract.mechanism === 'dpm-2'
|
||||||
? `Current payout for ${formatWithCommas(shares)} / ${formatWithCommas(
|
? `Current payout for ${formatWithCommas(shares)} / ${formatWithCommas(
|
||||||
|
@ -335,8 +341,15 @@ function BuyPanel(props: {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<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">
|
||||||
<div className="text-gray-500">Probability</div>
|
<div className="text-sm text-gray-500">Average price</div>
|
||||||
|
<Row>
|
||||||
|
<div>{formatCents(averagePrice)}</div>
|
||||||
|
</Row>
|
||||||
|
</Row> */}
|
||||||
|
|
||||||
|
<Row className="items-center justify-between">
|
||||||
|
<div className="text-sm text-gray-500">Probability change</div>
|
||||||
<Row>
|
<Row>
|
||||||
<div>{formatPercent(initialProb)}</div>
|
<div>{formatPercent(initialProb)}</div>
|
||||||
<div className="mx-2">→</div>
|
<div className="mx-2">→</div>
|
||||||
|
@ -344,9 +357,9 @@ function BuyPanel(props: {
|
||||||
</Row>
|
</Row>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row className="items-center justify-between gap-2 text-sm">
|
<Row className="items-center justify-between gap-2">
|
||||||
<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 className="text-sm">
|
||||||
{contract.mechanism === 'dpm-2' ? (
|
{contract.mechanism === 'dpm-2' ? (
|
||||||
<>
|
<>
|
||||||
Estimated
|
Estimated
|
||||||
|
|
|
@ -10,10 +10,11 @@ import { Modal } from './layout/modal'
|
||||||
// Inline version of a bet panel. Opens BetPanel in a new modal.
|
// Inline version of a bet panel. Opens BetPanel in a new modal.
|
||||||
export default function BetRow(props: {
|
export default function BetRow(props: {
|
||||||
contract: FullContract<DPM | CPMM, Binary>
|
contract: FullContract<DPM | CPMM, Binary>
|
||||||
|
large?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
labelClassName?: string
|
labelClassName?: string
|
||||||
}) {
|
}) {
|
||||||
const { className, labelClassName } = props
|
const { large, className, labelClassName } = props
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [betChoice, setBetChoice] = useState<'YES' | 'NO' | undefined>(
|
const [betChoice, setBetChoice] = useState<'YES' | 'NO' | undefined>(
|
||||||
undefined
|
undefined
|
||||||
|
@ -27,7 +28,8 @@ export default function BetRow(props: {
|
||||||
Place a trade
|
Place a trade
|
||||||
</div>
|
</div>
|
||||||
<YesNoSelector
|
<YesNoSelector
|
||||||
btnClassName="btn-sm w-24"
|
btnClassName={clsx('btn-sm w-20', large && 'w-32 h-10')}
|
||||||
|
large={large}
|
||||||
onSelect={(choice) => {
|
onSelect={(choice) => {
|
||||||
setOpen(true)
|
setOpen(true)
|
||||||
setBetChoice(choice)
|
setBetChoice(choice)
|
||||||
|
|
|
@ -31,6 +31,7 @@ export const ContractOverview = (props: {
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const isCreator = user?.id === creatorId
|
const isCreator = user?.id === creatorId
|
||||||
const isBinary = outcomeType === 'BINARY'
|
const isBinary = outcomeType === 'BINARY'
|
||||||
|
const allowTrade = tradingAllowed(contract)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className={clsx('mb-6', className)}>
|
<Col className={clsx('mb-6', className)}>
|
||||||
|
@ -42,28 +43,29 @@ export const ContractOverview = (props: {
|
||||||
|
|
||||||
{(isBinary || resolution) && (
|
{(isBinary || resolution) && (
|
||||||
<ResolutionOrChance
|
<ResolutionOrChance
|
||||||
className="hidden items-end xl:flex"
|
className="items-end xl:flex"
|
||||||
contract={contract}
|
contract={contract}
|
||||||
large
|
large
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row className="items-center justify-between gap-4 xl:hidden">
|
|
||||||
{(isBinary || resolution) && (
|
|
||||||
<ResolutionOrChance contract={contract} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isBinary && tradingAllowed(contract) && (
|
|
||||||
<BetRow contract={contract} labelClassName="hidden" />
|
|
||||||
)}
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<ContractDetails contract={contract} isCreator={isCreator} />
|
<ContractDetails contract={contract} isCreator={isCreator} />
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Spacer h={4} />
|
<Spacer h={4} />
|
||||||
|
|
||||||
|
{isBinary && allowTrade && (
|
||||||
|
<Row className="my-6 items-center justify-between gap-4 lg:justify-center">
|
||||||
|
{(isBinary || resolution) && (
|
||||||
|
<ResolutionOrChance contract={contract} className="lg:hidden" />
|
||||||
|
)}
|
||||||
|
{isBinary && tradingAllowed(contract) && (
|
||||||
|
<BetRow large contract={contract} labelClassName="hidden" />
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
|
||||||
{isBinary ? (
|
{isBinary ? (
|
||||||
<ContractProbGraph contract={contract} bets={bets} />
|
<ContractProbGraph contract={contract} bets={bets} />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -7,41 +7,40 @@ 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
|
||||||
|
large?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
btnClassName?: string
|
btnClassName?: string
|
||||||
}) {
|
}) {
|
||||||
const { selected, onSelect, className, btnClassName } = props
|
const { selected, onSelect, large, className, btnClassName } = props
|
||||||
|
|
||||||
const commonClassNames =
|
const commonClassNames = clsx(
|
||||||
'inline-flex flex-1 items-center justify-center rounded-3xl border-2 p-2'
|
'inline-flex flex-1 items-center justify-center rounded-3xl p-2 border-2 border-gray-300 shadow',
|
||||||
|
large && 'text-lg w-32'
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row className={clsx('space-x-3', className)}>
|
<Row className={clsx('space-x-3', className)}>
|
||||||
<button
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
commonClassNames,
|
commonClassNames,
|
||||||
'hover:bg-primary-focus border-primary hover:border-primary-focus hover:text-white',
|
'border-primary hover:bg-primary-focus hover:border-primary-focus hover:text-white',
|
||||||
selected == 'YES'
|
selected == 'YES' ? 'bg-primary text-white' : 'text-primary bg-white',
|
||||||
? 'bg-primary text-white'
|
|
||||||
: 'text-primary bg-transparent',
|
|
||||||
btnClassName
|
btnClassName
|
||||||
)}
|
)}
|
||||||
onClick={() => onSelect('YES')}
|
onClick={() => onSelect('YES')}
|
||||||
>
|
>
|
||||||
Buy YES
|
Bet YES
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
commonClassNames,
|
commonClassNames,
|
||||||
'border-red-400 hover:border-red-500 hover:bg-red-500 hover:text-white',
|
'border-red-400 hover:border-red-500 hover:bg-red-500 hover:text-white',
|
||||||
selected == 'NO'
|
selected == 'NO' ? 'bg-red-400 text-white' : 'bg-white text-red-400',
|
||||||
? 'bg-red-400 text-white'
|
|
||||||
: 'bg-transparent text-red-400',
|
|
||||||
btnClassName
|
btnClassName
|
||||||
)}
|
)}
|
||||||
onClick={() => onSelect('NO')}
|
onClick={() => onSelect('NO')}
|
||||||
>
|
>
|
||||||
Buy NO
|
Bet NO
|
||||||
</button>
|
</button>
|
||||||
</Row>
|
</Row>
|
||||||
)
|
)
|
||||||
|
@ -173,7 +172,7 @@ export function BuyButton(props: { className?: string; onClick?: () => void }) {
|
||||||
)}
|
)}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
Buy
|
Bet
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,18 +115,14 @@ export default function ContractPage(props: {
|
||||||
|
|
||||||
const isCreator = user?.id === creatorId
|
const isCreator = user?.id === creatorId
|
||||||
const isBinary = outcomeType === 'BINARY'
|
const isBinary = outcomeType === 'BINARY'
|
||||||
const allowTrade = tradingAllowed(contract)
|
|
||||||
const allowResolve = !isResolved && isCreator && !!user
|
const allowResolve = !isResolved && isCreator && !!user
|
||||||
const hasSidePanel = isBinary && (allowTrade || allowResolve)
|
const hasSidePanel = isBinary && allowResolve
|
||||||
|
|
||||||
const ogCardProps = getOpenGraphProps(contract)
|
const ogCardProps = getOpenGraphProps(contract)
|
||||||
|
|
||||||
const rightSidebar = hasSidePanel ? (
|
const rightSidebar = hasSidePanel ? (
|
||||||
<Col className="gap-4">
|
<Col className="gap-4">
|
||||||
{allowTrade && (
|
<ResolutionPanel creator={user} contract={contract} />
|
||||||
<BetPanel className="hidden xl:flex" contract={contract} />
|
|
||||||
)}
|
|
||||||
{allowResolve && <ResolutionPanel creator={user} contract={contract} />}
|
|
||||||
</Col>
|
</Col>
|
||||||
) : null
|
) : null
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user