Advanced metrics for bet panel
This commit is contained in:
parent
3302cbddbd
commit
5eaf50612d
35
web/components/advanced-panel.tsx
Normal file
35
web/components/advanced-panel.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import clsx from 'clsx'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
export function AdvancedPanel(props: { children: any }) {
|
||||||
|
const { children } = props
|
||||||
|
const [collapsed, setCollapsed] = useState(true)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
tabIndex={0}
|
||||||
|
className={clsx(
|
||||||
|
'cursor-pointer relative collapse collapse-arrow',
|
||||||
|
collapsed ? 'collapse-close' : 'collapse-open'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div onClick={() => setCollapsed((collapsed) => !collapsed)}>
|
||||||
|
<div className="mt-4 mr-6 text-sm text-gray-400 text-right">
|
||||||
|
Advanced
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="collapse-title p-0 absolute w-0 h-0 min-h-0"
|
||||||
|
style={{
|
||||||
|
top: -2,
|
||||||
|
right: -15,
|
||||||
|
color: '#9ca3af' /* gray-400 */,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="collapse-content !p-0 m-0 !bg-transparent">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -8,14 +8,22 @@ import { Col } from './layout/col'
|
||||||
import { Row } from './layout/row'
|
import { Row } from './layout/row'
|
||||||
import { Spacer } from './layout/spacer'
|
import { Spacer } from './layout/spacer'
|
||||||
import { YesNoSelector } from './yes-no-selector'
|
import { YesNoSelector } from './yes-no-selector'
|
||||||
import { formatMoney, formatPercent } from '../lib/util/format'
|
import {
|
||||||
|
formatMoney,
|
||||||
|
formatPercent,
|
||||||
|
formatWithCommas,
|
||||||
|
} from '../lib/util/format'
|
||||||
import { Title } from './title'
|
import { Title } from './title'
|
||||||
import {
|
import {
|
||||||
getProbability,
|
getProbability,
|
||||||
calculateShares,
|
calculateShares,
|
||||||
getProbabilityAfterBet,
|
getProbabilityAfterBet,
|
||||||
|
calculatePayout,
|
||||||
} from '../lib/calculate'
|
} from '../lib/calculate'
|
||||||
import { firebaseLogin } from '../lib/firebase/users'
|
import { firebaseLogin } from '../lib/firebase/users'
|
||||||
|
import { OutcomeLabel } from './outcome-label'
|
||||||
|
import { AdvancedPanel } from './advanced-panel'
|
||||||
|
import { Bet } from '../lib/firebase/bets'
|
||||||
|
|
||||||
export function BetPanel(props: { contract: Contract; className?: string }) {
|
export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||||
const { contract, className } = props
|
const { contract, className } = props
|
||||||
|
@ -151,6 +159,29 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||||
{formatMoney(estimatedWinnings)} (+{estimatedReturnPercent})
|
{formatMoney(estimatedWinnings)} (+{estimatedReturnPercent})
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<AdvancedPanel>
|
||||||
|
<div className="mt-2 mb-1 text-sm text-gray-400">
|
||||||
|
<OutcomeLabel outcome={betChoice} /> shares
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{formatWithCommas(shares)} of{' '}
|
||||||
|
{formatWithCommas(shares + contract.totalShares[betChoice])}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-2 mb-1 text-sm text-gray-400">
|
||||||
|
Current payout if <OutcomeLabel outcome={betChoice} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{formatMoney(
|
||||||
|
calculatePayout(
|
||||||
|
contract,
|
||||||
|
{ outcome: betChoice, amount: betAmount ?? 0, shares } as Bet,
|
||||||
|
betChoice
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</AdvancedPanel>
|
||||||
|
|
||||||
<Spacer h={6} />
|
<Spacer h={6} />
|
||||||
|
|
||||||
{user ? (
|
{user ? (
|
||||||
|
|
|
@ -11,6 +11,7 @@ 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 { formatMoney } from '../lib/util/format'
|
||||||
|
import { AdvancedPanel } from '../components/advanced-panel'
|
||||||
|
|
||||||
// Allow user to create a new contract
|
// Allow user to create a new contract
|
||||||
export default function NewContract() {
|
export default function NewContract() {
|
||||||
|
@ -29,7 +30,6 @@ export default function NewContract() {
|
||||||
const [closeDate, setCloseDate] = useState('')
|
const [closeDate, setCloseDate] = useState('')
|
||||||
|
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
const [collapsed, setCollapsed] = useState(true)
|
|
||||||
|
|
||||||
const closeTime = dateToMillis(closeDate) || undefined
|
const closeTime = dateToMillis(closeDate) || undefined
|
||||||
// We'd like this to look like "Apr 2, 2022, 23:59:59 PM PT" but timezones are hard with dayjs
|
// We'd like this to look like "Apr 2, 2022, 23:59:59 PM PT" but timezones are hard with dayjs
|
||||||
|
@ -141,82 +141,59 @@ export default function NewContract() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Collapsible "Advanced" section */}
|
<AdvancedPanel>
|
||||||
<div
|
<div className="form-control mb-1">
|
||||||
tabIndex={0}
|
<label className="label">
|
||||||
className={clsx(
|
<span className="label-text">Subsidize your market</span>
|
||||||
'cursor-pointer relative collapse collapse-arrow',
|
</label>
|
||||||
collapsed ? 'collapse-close' : 'collapse-open'
|
|
||||||
)}
|
<label className="input-group">
|
||||||
>
|
<span className="text-sm bg-gray-200">M$</span>
|
||||||
<div onClick={() => setCollapsed((collapsed) => !collapsed)}>
|
<input
|
||||||
<div className="mt-4 mr-6 text-sm text-gray-400 text-right">
|
className={clsx(
|
||||||
Advanced
|
'input input-bordered',
|
||||||
|
anteError && 'input-error'
|
||||||
|
)}
|
||||||
|
type="text"
|
||||||
|
placeholder="0"
|
||||||
|
maxLength={9}
|
||||||
|
value={ante ?? ''}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
onChange={(e) => onAnteChange(e.target.value)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className="mt-3 mb-1 text-sm text-gray-400">
|
||||||
|
Remaining balance
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div>
|
||||||
className="collapse-title p-0 absolute w-0 h-0 min-h-0"
|
{formatMoney(remainingBalance > 0 ? remainingBalance : 0)}
|
||||||
style={{
|
</div>
|
||||||
top: -2,
|
</div>
|
||||||
right: -15,
|
|
||||||
color: '#9ca3af' /* gray-400 */,
|
<Spacer h={4} />
|
||||||
}}
|
|
||||||
|
<div className="form-control">
|
||||||
|
<label className="label">
|
||||||
|
<span className="label-text">Close date (optional)</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
className="input input-bordered"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
onChange={(e) => setCloseDate(e.target.value || '')}
|
||||||
|
min={new Date().toISOString().split('T')[0]}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
value={closeDate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<label>
|
||||||
<div className="collapse-content !p-0 m-0 !bg-transparent">
|
<span className="label-text text-gray-400 ml-2">
|
||||||
<div className="form-control mb-1">
|
No new trades will be allowed after{' '}
|
||||||
<label className="label">
|
{closeDate ? formattedCloseTime : 'this time'}
|
||||||
<span className="label-text">Subsidize your market</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
</AdvancedPanel>
|
||||||
<label className="input-group">
|
|
||||||
<span className="text-sm bg-gray-200">M$</span>
|
|
||||||
<input
|
|
||||||
className={clsx(
|
|
||||||
'input input-bordered',
|
|
||||||
anteError && 'input-error'
|
|
||||||
)}
|
|
||||||
type="text"
|
|
||||||
placeholder="0"
|
|
||||||
maxLength={9}
|
|
||||||
value={ante ?? ''}
|
|
||||||
disabled={isSubmitting}
|
|
||||||
onChange={(e) => onAnteChange(e.target.value)}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div className="mt-3 mb-1 text-sm text-gray-400">
|
|
||||||
Remaining balance
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{formatMoney(remainingBalance > 0 ? remainingBalance : 0)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Spacer h={4} />
|
|
||||||
|
|
||||||
<div className="form-control">
|
|
||||||
<label className="label">
|
|
||||||
<span className="label-text">Close date (optional)</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="date"
|
|
||||||
className="input input-bordered"
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
onChange={(e) => setCloseDate(e.target.value || '')}
|
|
||||||
min={new Date().toISOString().split('T')[0]}
|
|
||||||
disabled={isSubmitting}
|
|
||||||
value={closeDate}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<label>
|
|
||||||
<span className="label-text text-gray-400 ml-2">
|
|
||||||
No new trades will be allowed after{' '}
|
|
||||||
{closeDate ? formattedCloseTime : 'this time'}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Spacer h={4} />
|
<Spacer h={4} />
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user