Merge branch 'main' into free-response
This commit is contained in:
commit
26bb872113
|
@ -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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user