Merge branch 'main' into free-response

This commit is contained in:
James Grugett 2022-02-15 23:56:57 -06:00
commit 26bb872113
6 changed files with 137 additions and 81 deletions

View File

@ -123,31 +123,34 @@ export function BetsList(props: { user: User }) {
const totalPortfolio = currentBetsValue + user.balance const totalPortfolio = currentBetsValue + user.balance
const pnl = totalPortfolio - user.totalDeposits const totalPnl = totalPortfolio - user.totalDeposits
const totalReturn = const totalProfit = (totalPnl / user.totalDeposits) * 100
(pnl > 0 ? '+' : '') + ((pnl / user.totalDeposits) * 100).toFixed() + '%' const investedProfit =
((currentBetsValue - currentInvestment) / currentInvestment) * 100
return ( return (
<Col className="mt-6 gap-6"> <Col className="mt-6 gap-4 sm:gap-6">
<Col className="mx-4 gap-4 sm:flex-row sm:justify-between md:mx-0"> <Col className="mx-4 gap-4 sm:flex-row sm:justify-between md:mx-0">
<Row className="gap-8"> <Row className="gap-8">
<Col> <Col>
<div className="text-sm text-gray-500">Total portfolio</div> <div className="text-sm text-gray-500">Invested</div>
<div>{formatMoney(totalPortfolio)}</div> <div className="text-lg">
</Col> {formatMoney(currentBetsValue)}{' '}
<Col> <ProfitBadge profitPercent={investedProfit} />
<div className="text-sm text-gray-500">Total profits & losses</div>
<div>
{formatMoney(pnl)} ({totalReturn})
</div> </div>
</Col> </Col>
<Col> <Col>
<div className="text-sm text-gray-500">Currently invested</div> <div className="text-sm text-gray-500">Balance</div>
<div>{formatMoney(currentInvestment)}</div> <div className="whitespace-nowrap text-lg">
{formatMoney(user.balance)}{' '}
</div>
</Col> </Col>
<Col> <Col>
<div className="text-sm text-gray-500">Current market value</div> <div className="text-sm text-gray-500">Total portfolio</div>
<div>{formatMoney(currentBetsValue)}</div> <div className="text-lg">
{formatMoney(totalPortfolio)}{' '}
<ProfitBadge profitPercent={totalProfit} />
</div>
</Col> </Col>
</Row> </Row>
@ -187,9 +190,9 @@ function MyContractBets(props: { contract: Contract; bets: Bet[] }) {
)} )}
onClick={() => setCollapsed((collapsed) => !collapsed)} onClick={() => setCollapsed((collapsed) => !collapsed)}
> >
<Row className="flex-wrap gap-4"> <Row className="flex-wrap gap-2">
<Col className="flex-[2] gap-1"> <Col className="flex-[2] gap-1">
<Row className="mr-6"> <Row className="mr-2 max-w-lg">
<Link href={contractPath(contract)}> <Link href={contractPath(contract)}>
<a <a
className="font-medium text-indigo-700 hover:underline hover:decoration-indigo-400 hover:decoration-2" className="font-medium text-indigo-700 hover:underline hover:decoration-indigo-400 hover:decoration-2"
@ -223,9 +226,10 @@ function MyContractBets(props: { contract: Contract; bets: Bet[] }) {
</Col> </Col>
<MyBetsSummary <MyBetsSummary
className="mr-5 flex-1 justify-end sm:mr-8" className="mr-5 justify-end sm:mr-8"
contract={contract} contract={contract}
bets={bets} bets={bets}
onlyMKT
/> />
</Row> </Row>
@ -235,6 +239,14 @@ function MyContractBets(props: { contract: Contract; bets: Bet[] }) {
> >
<Spacer h={8} /> <Spacer h={8} />
<MyBetsSummary
className="mr-5 flex-1 sm:mr-8"
contract={contract}
bets={bets}
/>
<Spacer h={8} />
<ContractBetsTable contract={contract} bets={bets} /> <ContractBetsTable contract={contract} bets={bets} />
</div> </div>
</div> </div>
@ -244,10 +256,10 @@ function MyContractBets(props: { contract: Contract; bets: Bet[] }) {
export function MyBetsSummary(props: { export function MyBetsSummary(props: {
contract: Contract contract: Contract
bets: Bet[] bets: Bet[]
showMKT?: boolean onlyMKT?: boolean
className?: string className?: string
}) { }) {
const { bets, contract, showMKT, className } = props const { bets, contract, onlyMKT, className } = props
const { resolution } = contract const { resolution } = contract
calculateCancelPayout calculateCancelPayout
@ -269,49 +281,80 @@ export function MyBetsSummary(props: {
calculatePayout(contract, bet, 'MKT') calculatePayout(contract, bet, 'MKT')
) )
const currentValue = resolution ? betsPayout : marketWinnings
const pnl = currentValue - betsTotal
const profit = (pnl / betsTotal) * 100
const valueCol = (
<Col>
<div className="whitespace-nowrap text-right text-lg">
{formatMoney(currentValue)}
</div>
<div className="text-right">
<ProfitBadge profitPercent={profit} />
</div>
</Col>
)
const payoutCol = (
<Col>
<div className="text-sm text-gray-500">Payout</div>
<div className="whitespace-nowrap">
{formatMoney(betsPayout)} <ProfitBadge profitPercent={profit} />
</div>
</Col>
)
return ( return (
<Row <Row
className={clsx( className={clsx(
'gap-4 sm:gap-6', 'gap-4 sm:gap-6',
showMKT && 'flex-wrap sm:flex-nowrap', !onlyMKT && 'flex-wrap sm:flex-nowrap',
className className
)} )}
> >
<Col> {onlyMKT ? (
<div className="whitespace-nowrap text-sm text-gray-500">Invested</div> <Row className="gap-4 sm:gap-6">{valueCol}</Row>
<div className="whitespace-nowrap">{formatMoney(betsTotal)}</div>
</Col>
{resolution ? (
<Col>
<div className="text-sm text-gray-500">Payout</div>
<div className="whitespace-nowrap">{formatMoney(betsPayout)}</div>
</Col>
) : ( ) : (
<Row className="gap-4 sm:gap-6"> <Row className="gap-4 sm:gap-6">
<Col> <Col>
<div className="whitespace-nowrap text-sm text-gray-500"> <div className="whitespace-nowrap text-sm text-gray-500">
Payout if <YesLabel /> Invested
</div> </div>
<div className="whitespace-nowrap">{formatMoney(yesWinnings)}</div> <div className="whitespace-nowrap">{formatMoney(betsTotal)}</div>
</Col> </Col>
<Col> {resolution ? (
<div className="whitespace-nowrap text-sm text-gray-500"> payoutCol
Payout if <NoLabel /> ) : (
</div> <>
<div className="whitespace-nowrap">{formatMoney(noWinnings)}</div> <Col>
</Col> <div className="whitespace-nowrap text-sm text-gray-500">
{showMKT && ( Payout if <YesLabel />
<Col> </div>
<div className="whitespace-nowrap text-sm text-gray-500"> <div className="whitespace-nowrap">
Payout at{' '} {formatMoney(yesWinnings)}
<span className="text-blue-400"> </div>
{formatPercent(getProbability(contract.totalShares))} </Col>
</span> <Col>
</div> <div className="whitespace-nowrap text-sm text-gray-500">
<div className="whitespace-nowrap"> Payout if <NoLabel />
{formatMoney(marketWinnings)} </div>
</div> <div className="whitespace-nowrap">
</Col> {formatMoney(noWinnings)}
</div>
</Col>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout at{' '}
<span className="text-blue-400">
{formatPercent(getProbability(contract.totalShares))}
</span>
</div>
<div className="whitespace-nowrap">
{formatMoney(marketWinnings)}
</div>
</Col>
</>
)} )}
</Row> </Row>
)} )}
@ -448,3 +491,23 @@ function SellButton(props: { contract: Contract; bet: Bet }) {
</ConfirmationButton> </ConfirmationButton>
) )
} }
function ProfitBadge(props: { profitPercent: number }) {
const { profitPercent } = props
if (!profitPercent) return null
const colors =
profitPercent > 0
? 'bg-green-100 text-green-800'
: 'bg-red-100 text-red-800'
return (
<span
className={clsx(
'ml-1 inline-flex items-center rounded-full px-3 py-0.5 text-sm font-medium',
colors
)}
>
{(profitPercent > 0 ? '+' : '') + profitPercent.toFixed(1) + '%'}
</span>
)
}

View File

@ -48,12 +48,13 @@ export function ContractCard(props: {
<Spacer h={3} /> <Spacer h={3} />
<Row className="justify-between gap-4"> <Row className="justify-between gap-4">
<p className="font-medium text-indigo-700">{question}</p> <p
<ResolutionOrChance className="font-medium text-indigo-700 break-words"
className="items-center" style={{ /* For iOS safari */ wordBreak: 'break-word' }}
resolution={resolution} >
probPercent={probPercent} {question}
/> </p>
<ResolutionOrChance className="items-center" contract={contract} />
</Row> </Row>
</div> </div>
</div> </div>
@ -61,12 +62,13 @@ export function ContractCard(props: {
} }
export function ResolutionOrChance(props: { export function ResolutionOrChance(props: {
resolution?: 'YES' | 'NO' | 'MKT' | 'CANCEL' | string contract: Contract
probPercent: string
large?: boolean large?: boolean
className?: string className?: string
}) { }) {
const { resolution, probPercent, large, className } = props const { contract, large, className } = props
const { resolution } = contract
const marketClosed = (contract.closeTime || Infinity) < Date.now()
const resolutionColor = const resolutionColor =
{ {
@ -77,11 +79,13 @@ export function ResolutionOrChance(props: {
'': '', // Empty if unresolved '': '', // Empty if unresolved
}[resolution || ''] ?? 'text-primary' }[resolution || ''] ?? 'text-primary'
const probColor = marketClosed ? 'text-gray-400' : 'text-primary'
const resolutionText = const resolutionText =
{ {
YES: 'YES', YES: 'YES',
NO: 'NO', NO: 'NO',
MKT: probPercent, MKT: getBinaryProbPercent(contract),
CANCEL: 'N/A', CANCEL: 'N/A',
'': '', '': '',
}[resolution || ''] ?? `#${resolution}` }[resolution || ''] ?? `#${resolution}`
@ -99,10 +103,8 @@ export function ResolutionOrChance(props: {
</> </>
) : ( ) : (
<> <>
<div className="text-primary">{probPercent}</div> <div className={probColor}>{getBinaryProbPercent(contract)}</div>
<div <div className={clsx(probColor, large ? 'text-xl' : 'text-base')}>
className={clsx('text-primary', large ? 'text-xl' : 'text-base')}
>
chance chance
</div> </div>
</> </>

View File

@ -342,11 +342,7 @@ function FeedQuestion(props: { contract: Contract }) {
{question} {question}
</SiteLink> </SiteLink>
{(isBinary || resolution) && ( {(isBinary || resolution) && (
<ResolutionOrChance <ResolutionOrChance className="items-center" contract={contract} />
className="items-center"
resolution={resolution}
probPercent={getBinaryProbPercent(contract)}
/>
)} )}
</Col> </Col>
<TruncatedComment <TruncatedComment

View File

@ -52,8 +52,7 @@ export const ContractOverview = (props: {
{(isBinary || resolution) && ( {(isBinary || resolution) && (
<ResolutionOrChance <ResolutionOrChance
className="md:hidden" className="md:hidden"
resolution={resolution} contract={contract}
probPercent={getBinaryProbPercent(contract)}
large large
/> />
)} )}
@ -74,8 +73,7 @@ export const ContractOverview = (props: {
<Col className="hidden items-end justify-between md:flex"> <Col className="hidden items-end justify-between md:flex">
<ResolutionOrChance <ResolutionOrChance
className="items-end" className="items-end"
resolution={resolution} contract={contract}
probPercent={getBinaryProbPercent(contract)}
large large
/> />
</Col> </Col>

View File

@ -12,9 +12,10 @@ export const SiteLink = (props: {
<a <a
href={href} href={href}
className={clsx( className={clsx(
'z-10 hover:underline hover:decoration-indigo-400 hover:decoration-2', 'break-words z-10 hover:underline hover:decoration-indigo-400 hover:decoration-2',
className className
)} )}
style={{ /* For iOS safari */ wordBreak: 'break-word' }}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
{children} {children}
@ -23,9 +24,10 @@ export const SiteLink = (props: {
<Link href={href}> <Link href={href}>
<a <a
className={clsx( className={clsx(
'z-10 hover:underline hover:decoration-indigo-400 hover:decoration-2', 'break-words z-10 hover:underline hover:decoration-indigo-400 hover:decoration-2',
className className
)} )}
style={{ /* For iOS safari */ wordBreak: 'break-word' }}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
{children} {children}

View File

@ -176,12 +176,7 @@ function BetsSection(props: {
<Title className="px-2" text="Your trades" /> <Title className="px-2" text="Your trades" />
{isBinary && ( {isBinary && (
<> <>
<MyBetsSummary <MyBetsSummary className="px-2" contract={contract} bets={userBets} />
className="px-2"
contract={contract}
bets={userBets}
showMKT
/>
<Spacer h={6} /> <Spacer h={6} />
</> </>
)} )}