diff --git a/web/components/contract/contract-card.tsx b/web/components/contract/contract-card.tsx index 71e3ddbd..87186743 100644 --- a/web/components/contract/contract-card.tsx +++ b/web/components/contract/contract-card.tsx @@ -6,6 +6,7 @@ import { Contract, contractPath, getBinaryProbPercent, + getBinaryProb, } from 'web/lib/firebase/contracts' import { Col } from '../layout/col' import { @@ -20,11 +21,42 @@ import { AnswerLabel, BinaryContractOutcomeLabel, FreeResponseOutcomeLabel, + OUTCOME_TO_COLOR, } from '../outcome-label' import { getOutcomeProbability, getTopAnswer } from 'common/calculate' import { AbbrContractDetails } from './contract-details' -import { TagsList } from '../tags-list' -import { CATEGORY_LIST } from 'common/categories' + +// Return a number from 0 to 1 for this contract +// Resolved contracts are set to 1, for coloring purposes (even if NO) +function getProb(contract: Contract) { + const { outcomeType, resolution } = contract + return resolution + ? 1 + : outcomeType === 'BINARY' + ? getBinaryProb(contract) + : outcomeType === 'FREE_RESPONSE' + ? getOutcomeProbability(contract, getTopAnswer(contract)?.id || '') + : 1 // Should not happen +} + +function getColor(contract: Contract) { + const { resolution } = contract + if (resolution) { + return ( + // @ts-ignore; TODO: Have better typing for contract.resolution? + OUTCOME_TO_COLOR[resolution] || + // If resolved to a FR answer, use 'primary' + 'primary' + ) + } + + const marketClosed = (contract.closeTime || Infinity) < Date.now() + return marketClosed + ? 'gray-400' + : getProb(contract) >= 0.5 + ? 'primary' + : 'red-400' +} export function ContractCard(props: { contract: Contract @@ -33,18 +65,18 @@ export function ContractCard(props: { className?: string }) { const { contract, showHotVolume, showCloseTime, className } = props - const { question, outcomeType, resolution } = contract + const { question, outcomeType } = contract - const { tags } = contract - const categories = tags.filter((tag) => - CATEGORY_LIST.includes(tag.toLowerCase()) - ) + const prob = getProb(contract) + const color = getColor(contract) + const marketClosed = (contract.closeTime || Infinity) < Date.now() + const showTopBar = prob >= 0.5 || marketClosed return (
@@ -66,9 +98,6 @@ export function ContractCard(props: { > {question}

- {outcomeType !== 'FREE_RESPONSE' && categories.length > 0 && ( - - )} {outcomeType === 'BINARY' && ( )} - {outcomeType === 'FREE_RESPONSE' && categories.length > 0 && ( - - )} +
+
) @@ -101,9 +143,7 @@ export function BinaryResolutionOrChance(props: { }) { const { contract, large, className } = props const { resolution } = contract - - const marketClosed = (contract.closeTime || Infinity) < Date.now() - const probColor = marketClosed ? 'text-gray-400' : 'text-primary' + const textColor = `text-${getColor(contract)}` return ( @@ -121,8 +161,8 @@ export function BinaryResolutionOrChance(props: { ) : ( <> -
{getBinaryProbPercent(contract)}
-
+
{getBinaryProbPercent(contract)}
+
chance
@@ -140,6 +180,7 @@ export function FreeResponseResolutionOrChance(props: { const { resolution } = contract const topAnswer = getTopAnswer(contract) + const textColor = `text-${getColor(contract)}` return ( @@ -161,7 +202,7 @@ export function FreeResponseResolutionOrChance(props: { answer={topAnswer} truncate={truncate} /> - +
{formatPercent(getOutcomeProbability(contract, topAnswer.id))}
diff --git a/web/components/contract/contract-details.tsx b/web/components/contract/contract-details.tsx index f4619e26..17b44795 100644 --- a/web/components/contract/contract-details.tsx +++ b/web/components/contract/contract-details.tsx @@ -1,6 +1,11 @@ import clsx from 'clsx' -import { ClockIcon, DatabaseIcon, PencilIcon } from '@heroicons/react/outline' -import { TrendingUpIcon } from '@heroicons/react/solid' +import { + ClockIcon, + DatabaseIcon, + PencilIcon, + CurrencyDollarIcon, + TrendingUpIcon, +} from '@heroicons/react/outline' import { Row } from '../layout/row' import { formatMoney } from 'common/util/format' import { UserLink } from '../user-page' @@ -18,6 +23,8 @@ import { useState } from 'react' import { ContractInfoDialog } from './contract-info-dialog' import { Bet } from 'common/bet' import NewContractBadge from '../new-contract-badge' +import { CATEGORY_LIST } from 'common/categories' +import { TagsList } from '../tags-list' export function AbbrContractDetails(props: { contract: Contract @@ -25,9 +32,19 @@ export function AbbrContractDetails(props: { showCloseTime?: boolean }) { const { contract, showHotVolume, showCloseTime } = props - const { volume, volume24Hours, creatorName, creatorUsername, closeTime } = - contract + const { + volume, + volume24Hours, + creatorName, + creatorUsername, + closeTime, + tags, + } = contract const { volumeLabel } = contractMetrics(contract) + // Show at most one category that this contract is tagged by + const categories = CATEGORY_LIST.filter((category) => + tags.map((t) => t.toLowerCase()).includes(category) + ).slice(0, 1) return ( @@ -45,21 +62,28 @@ export function AbbrContractDetails(props: { /> - {showHotVolume ? ( - - {formatMoney(volume24Hours)} - - ) : showCloseTime ? ( - - - {(closeTime || 0) < Date.now() ? 'Closed' : 'Closes'}{' '} - {fromNow(closeTime || 0)} - - ) : volume > 0 ? ( - {volumeLabel} - ) : ( - - )} + + {categories.length > 0 && ( + + )} + + {showHotVolume ? ( + + {' '} + {formatMoney(volume24Hours)} + + ) : showCloseTime ? ( + + + {(closeTime || 0) < Date.now() ? 'Closed' : 'Closes'}{' '} + {fromNow(closeTime || 0)} + + ) : volume > 0 ? ( + {volumeLabel} + ) : ( + + )} + ) diff --git a/web/components/outcome-label.tsx b/web/components/outcome-label.tsx index d578247b..5ae08135 100644 --- a/web/components/outcome-label.tsx +++ b/web/components/outcome-label.tsx @@ -83,6 +83,13 @@ export function FreeResponseOutcomeLabel(props: { ) } +export const OUTCOME_TO_COLOR = { + YES: 'primary', + NO: 'red-400', + CANCEL: 'yellow-400', + MKT: 'blue-400', +} + export function YesLabel() { return YES } diff --git a/web/components/tags-list.tsx b/web/components/tags-list.tsx index 65985f12..5eec05ce 100644 --- a/web/components/tags-list.tsx +++ b/web/components/tags-list.tsx @@ -10,13 +10,8 @@ function Hashtag(props: { tag: string; noLink?: boolean }) { const category = CATEGORIES[tag.replace('#', '').toLowerCase()] const body = ( -
- {category ?? tag} +
+ #{category ?? tag}
) @@ -38,7 +33,7 @@ export function TagsList(props: { const { tags, className, noLink, noLabel, label } = props return ( - {!noLabel &&
{label || 'Tags'}
} + {!noLabel &&
{label || 'Tags'}
} {tags.map((tag) => (