Clean up rendering of user bets list (#694)

* Clean up crufty markup in bets list

* Don't render bet tables in bets list until expanded

* Don't look up unfilled bets for every sell button
This commit is contained in:
Marshall Polaris 2022-07-26 00:10:22 -07:00 committed by GitHub
parent 7e4f4b9a87
commit ad46a60c4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3,6 +3,7 @@ import { groupBy, mapValues, sortBy, partition, sumBy } from 'lodash'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import clsx from 'clsx' import clsx from 'clsx'
import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/solid'
import { Bet } from 'web/lib/firebase/bets' import { Bet } from 'web/lib/firebase/bets'
import { User } from 'web/lib/firebase/users' import { User } from 'web/lib/firebase/users'
@ -277,13 +278,7 @@ function ContractBets(props: {
bets bets
) )
return ( return (
<div <div tabIndex={0} className="relative bg-white p-4 pr-6">
tabIndex={0}
className={clsx(
'collapse collapse-arrow relative bg-white p-4 pr-6',
collapsed ? 'collapse-close' : 'collapse-open pb-2'
)}
>
<Row <Row
className="cursor-pointer flex-wrap gap-2" className="cursor-pointer flex-wrap gap-2"
onClick={() => setCollapsed((collapsed) => !collapsed)} onClick={() => setCollapsed((collapsed) => !collapsed)}
@ -300,10 +295,11 @@ function ContractBets(props: {
</Link> </Link>
{/* Show carrot for collapsing. Hack the positioning. */} {/* Show carrot for collapsing. Hack the positioning. */}
<div {collapsed ? (
className="collapse-title absolute h-0 min-h-0 w-0 p-0" <ChevronDownIcon className="absolute top-5 right-4 h-6 w-6" />
style={{ top: -10, right: 0 }} ) : (
/> <ChevronUpIcon className="absolute top-5 right-4 h-6 w-6" />
)}
</Row> </Row>
<Row className="flex-1 items-center gap-2 text-sm text-gray-500"> <Row className="flex-1 items-center gap-2 text-sm text-gray-500">
@ -335,55 +331,42 @@ function ContractBets(props: {
</Row> </Row>
</Col> </Col>
<Row className="mr-5 justify-end sm:mr-8"> <Col className="mr-5 sm:mr-8">
<Col> <div className="whitespace-nowrap text-right text-lg">
<div className="whitespace-nowrap text-right text-lg"> {formatMoney(metric === 'profit' ? profit : payout)}
{formatMoney(metric === 'profit' ? profit : payout)} </div>
</div> <ProfitBadge className="text-right" profitPercent={profitPercent} />
<div className="text-right"> </Col>
<ProfitBadge profitPercent={profitPercent} />
</div>
</Col>
</Row>
</Row> </Row>
<div {!collapsed && (
className="collapse-content !px-0" <div className="bg-white">
style={{ backgroundColor: 'white' }} <BetsSummary
> className="mt-8 mr-5 flex-1 sm:mr-8"
<Spacer h={8} /> contract={contract}
bets={bets}
isYourBets={isYourBets}
/>
<BetsSummary {contract.mechanism === 'cpmm-1' && limitBets.length > 0 && (
className="mr-5 flex-1 sm:mr-8"
contract={contract}
bets={bets}
isYourBets={isYourBets}
/>
<Spacer h={4} />
{contract.mechanism === 'cpmm-1' && limitBets.length > 0 && (
<>
<div className="max-w-md"> <div className="max-w-md">
<div className="bg-gray-50 px-4 py-2">Limit orders</div> <div className="mt-4 bg-gray-50 px-4 py-2">Limit orders</div>
<LimitOrderTable <LimitOrderTable
contract={contract} contract={contract}
limitBets={limitBets} limitBets={limitBets}
isYou={true} isYou={true}
/> />
</div> </div>
</> )}
)}
<Spacer h={4} /> <div className="mt-4 bg-gray-50 px-4 py-2">Bets</div>
<ContractBetsTable
<div className="bg-gray-50 px-4 py-2">Bets</div> contract={contract}
<ContractBetsTable bets={bets}
contract={contract} isYourBets={isYourBets}
bets={bets} />
isYourBets={isYourBets} </div>
/> )}
</div>
</div> </div>
) )
} }
@ -427,107 +410,92 @@ export function BetsSummary(props: {
return ( return (
<Row className={clsx('flex-wrap gap-4 sm:flex-nowrap sm:gap-6', className)}> <Row className={clsx('flex-wrap gap-4 sm:flex-nowrap sm:gap-6', className)}>
<Row className="flex-wrap gap-4 sm:gap-6"> {!isCpmm && (
{!isCpmm && (
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Invested
</div>
<div className="whitespace-nowrap">{formatMoney(invested)}</div>
</Col>
)}
{resolution ? (
<Col>
<div className="text-sm text-gray-500">Payout</div>
<div className="whitespace-nowrap">
{formatMoney(payout)}{' '}
<ProfitBadge profitPercent={profitPercent} />
</div>
</Col>
) : (
<>
{isBinary ? (
<>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout if <YesLabel />
</div>
<div className="whitespace-nowrap">
{formatMoney(yesWinnings)}
</div>
</Col>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout if <NoLabel />
</div>
<div className="whitespace-nowrap">
{formatMoney(noWinnings)}
</div>
</Col>
</>
) : isPseudoNumeric ? (
<>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout if {'>='} {formatLargeNumber(contract.max)}
</div>
<div className="whitespace-nowrap">
{formatMoney(yesWinnings)}
</div>
</Col>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout if {'<='} {formatLargeNumber(contract.min)}
</div>
<div className="whitespace-nowrap">
{formatMoney(noWinnings)}
</div>
</Col>
</>
) : (
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Current value
</div>
<div className="whitespace-nowrap">{formatMoney(payout)}</div>
</Col>
)}
</>
)}
<Col> <Col>
<div className="whitespace-nowrap text-sm text-gray-500">Profit</div> <div className="whitespace-nowrap text-sm text-gray-500">
Invested
</div>
<div className="whitespace-nowrap">{formatMoney(invested)}</div>
</Col>
)}
{resolution ? (
<Col>
<div className="text-sm text-gray-500">Payout</div>
<div className="whitespace-nowrap"> <div className="whitespace-nowrap">
{formatMoney(profit)} <ProfitBadge profitPercent={profitPercent} /> {formatMoney(payout)} <ProfitBadge profitPercent={profitPercent} />
{isYourBets &&
isCpmm &&
(isBinary || isPseudoNumeric) &&
!isClosed &&
!resolution &&
hasShares &&
sharesOutcome &&
user && (
<>
<button
className="btn btn-sm ml-2"
onClick={() => setShowSellModal(true)}
>
Sell
</button>
{showSellModal && (
<SellSharesModal
contract={contract}
user={user}
userBets={bets}
shares={totalShares[sharesOutcome]}
sharesOutcome={sharesOutcome}
setOpen={setShowSellModal}
/>
)}
</>
)}
</div> </div>
</Col> </Col>
</Row> ) : isBinary ? (
<>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout if <YesLabel />
</div>
<div className="whitespace-nowrap">{formatMoney(yesWinnings)}</div>
</Col>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout if <NoLabel />
</div>
<div className="whitespace-nowrap">{formatMoney(noWinnings)}</div>
</Col>
</>
) : isPseudoNumeric ? (
<>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout if {'>='} {formatLargeNumber(contract.max)}
</div>
<div className="whitespace-nowrap">{formatMoney(yesWinnings)}</div>
</Col>
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Payout if {'<='} {formatLargeNumber(contract.min)}
</div>
<div className="whitespace-nowrap">{formatMoney(noWinnings)}</div>
</Col>
</>
) : (
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">
Current value
</div>
<div className="whitespace-nowrap">{formatMoney(payout)}</div>
</Col>
)}
<Col>
<div className="whitespace-nowrap text-sm text-gray-500">Profit</div>
<div className="whitespace-nowrap">
{formatMoney(profit)} <ProfitBadge profitPercent={profitPercent} />
{isYourBets &&
isCpmm &&
(isBinary || isPseudoNumeric) &&
!isClosed &&
!resolution &&
hasShares &&
sharesOutcome &&
user && (
<>
<button
className="btn btn-sm ml-2"
onClick={() => setShowSellModal(true)}
>
Sell
</button>
{showSellModal && (
<SellSharesModal
contract={contract}
user={user}
userBets={bets}
shares={totalShares[sharesOutcome]}
sharesOutcome={sharesOutcome}
setOpen={setShowSellModal}
/>
)}
</>
)}
</div>
</Col>
</Row> </Row>
) )
} }
@ -689,7 +657,13 @@ function BetRow(props: {
!isClosed && !isClosed &&
!isSold && !isSold &&
!isAnte && !isAnte &&
!isNumeric && <SellButton contract={contract} bet={bet} />} !isNumeric && (
<SellButton
contract={contract}
bet={bet}
unfilledBets={unfilledBets}
/>
)}
</td> </td>
{isCPMM && <td>{shares >= 0 ? 'BUY' : 'SELL'}</td>} {isCPMM && <td>{shares >= 0 ? 'BUY' : 'SELL'}</td>}
<td> <td>
@ -729,8 +703,12 @@ function BetRow(props: {
) )
} }
function SellButton(props: { contract: Contract; bet: Bet }) { function SellButton(props: {
const { contract, bet } = props contract: Contract
bet: Bet
unfilledBets: LimitBet[]
}) {
const { contract, bet, unfilledBets } = props
const { outcome, shares, loanAmount } = bet const { outcome, shares, loanAmount } = bet
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
@ -740,8 +718,6 @@ function SellButton(props: { contract: Contract; bet: Bet }) {
outcome === 'NO' ? 'YES' : outcome outcome === 'NO' ? 'YES' : outcome
) )
const unfilledBets = useUnfilledBets(contract.id) ?? []
const outcomeProb = getProbabilityAfterSale( const outcomeProb = getProbabilityAfterSale(
contract, contract,
outcome, outcome,
@ -787,8 +763,8 @@ function SellButton(props: { contract: Contract; bet: Bet }) {
) )
} }
function ProfitBadge(props: { profitPercent: number }) { function ProfitBadge(props: { profitPercent: number; className?: string }) {
const { profitPercent } = props const { profitPercent, className } = props
if (!profitPercent) return null if (!profitPercent) return null
const colors = const colors =
profitPercent > 0 profitPercent > 0
@ -799,7 +775,8 @@ function ProfitBadge(props: { profitPercent: number }) {
<span <span
className={clsx( className={clsx(
'ml-1 inline-flex items-center rounded-full px-3 py-0.5 text-sm font-medium', 'ml-1 inline-flex items-center rounded-full px-3 py-0.5 text-sm font-medium',
colors colors,
className
)} )}
> >
{(profitPercent > 0 ? '+' : '') + profitPercent.toFixed(1) + '%'} {(profitPercent > 0 ? '+' : '') + profitPercent.toFixed(1) + '%'}