import clsx from 'clsx' import Link from 'next/link' import { Row } from '../layout/row' import { formatLargeNumber, formatPercent } from 'common/util/format' import { contractPath, getBinaryProbPercent } from 'web/lib/firebase/contracts' import { Col } from '../layout/col' import { BinaryContract, Contract, CPMMBinaryContract, FreeResponseContract, MultipleChoiceContract, NumericContract, PseudoNumericContract, } from 'common/contract' import { AnswerLabel, BinaryContractOutcomeLabel, CancelLabel, FreeResponseOutcomeLabel, } from '../outcome-label' import { getOutcomeProbability, getProbability, getTopAnswer, } from 'common/calculate' import { AvatarDetails, MiscDetails, ShowTime } from './contract-details' import { getExpectedValue, getValueFromBucket } from 'common/calculate-dpm' import { getColor, ProbBar, QuickBet } from './quick-bet' import { useContractWithPreload } from 'web/hooks/use-contract' import { useUser } from 'web/hooks/use-user' import { track } from '@amplitude/analytics-browser' import { trackCallback } from 'web/lib/service/analytics' import { getMappedValue } from 'common/pseudo-numeric' import { Tooltip } from '../tooltip' import { SiteLink } from '../site-link' import { ProbChange } from './prob-change-table' export function ContractCard(props: { contract: Contract showTime?: ShowTime className?: string questionClass?: string onClick?: () => void hideQuickBet?: boolean hideGroupLink?: boolean trackingPostfix?: string noLinkAvatar?: boolean newTab?: boolean }) { const { showTime, className, questionClass, onClick, hideQuickBet, hideGroupLink, trackingPostfix, noLinkAvatar, newTab, } = props const contract = useContractWithPreload(props.contract) ?? props.contract const { question, outcomeType } = contract const { resolution } = contract const user = useUser() const marketClosed = (contract.closeTime || Infinity) < Date.now() || !!resolution const showQuickBet = user && !marketClosed && (outcomeType === 'BINARY' || outcomeType === 'PSEUDO_NUMERIC') && !hideQuickBet return (

{question}

{(outcomeType === 'FREE_RESPONSE' || outcomeType === 'MULTIPLE_CHOICE') && (resolution ? ( ) : ( ))} {showQuickBet ? ( ) : ( <> {outcomeType === 'BINARY' && ( )} {outcomeType === 'PSEUDO_NUMERIC' && ( )} {outcomeType === 'NUMERIC' && ( )} {(outcomeType === 'FREE_RESPONSE' || outcomeType === 'MULTIPLE_CHOICE') && ( )} )} {/* Add click layer */} {onClick ? ( { // Let the browser handle the link click (opens in new tab). if (e.ctrlKey || e.metaKey) return e.preventDefault() track('click market card' + (trackingPostfix ?? ''), { slug: contract.slug, contractId: contract.id, }) onClick() }} /> ) : ( )}
) } export function BinaryResolutionOrChance(props: { contract: BinaryContract large?: boolean className?: string probAfter?: number // 0 to 1 }) { const { contract, large, className, probAfter } = props const { resolution } = contract const textColor = `text-${getColor(contract)}` const before = getBinaryProbPercent(contract) const after = probAfter && formatPercent(probAfter) const probChanged = before !== after return ( {resolution ? (
Resolved
) : ( <> {probAfter && probChanged ? (
{before} {after}
) : (
{before}
)}
chance
)} ) } function FreeResponseTopAnswer(props: { contract: FreeResponseContract | MultipleChoiceContract className?: string }) { const { contract } = props const topAnswer = getTopAnswer(contract) return topAnswer ? ( ) : null } export function FreeResponseResolutionOrChance(props: { contract: FreeResponseContract | MultipleChoiceContract truncate: 'short' | 'long' | 'none' className?: string }) { const { contract, truncate, className } = props const { resolution } = contract const topAnswer = getTopAnswer(contract) const textColor = `text-${getColor(contract)}` return ( {resolution ? ( <>
Resolved
{(resolution === 'CANCEL' || resolution === 'MKT') && ( )} ) : ( topAnswer && (
{formatPercent(getOutcomeProbability(contract, topAnswer.id))}
chance
) )} ) } export function NumericResolutionOrExpectation(props: { contract: NumericContract className?: string }) { const { contract, className } = props const { resolution } = contract const textColor = `text-${getColor(contract)}` const resolutionValue = contract.resolutionValue ?? getValueFromBucket(resolution ?? '', contract) return ( {resolution ? ( <>
Resolved
{resolution === 'CANCEL' ? ( ) : (
{formatLargeNumber(resolutionValue)}
)} ) : ( <>
{formatLargeNumber(getExpectedValue(contract))}
expected
)} ) } export function PseudoNumericResolutionOrExpectation(props: { contract: PseudoNumericContract className?: string }) { const { contract, className } = props const { resolution, resolutionValue, resolutionProbability } = contract const textColor = `text-blue-400` const value = resolution ? resolutionValue ? resolutionValue : getMappedValue(contract)(resolutionProbability ?? 0) : getMappedValue(contract)(getProbability(contract)) return ( {resolution ? ( <>
Resolved
{resolution === 'CANCEL' ? ( ) : ( {formatLargeNumber(value)} )} ) : ( <> {formatLargeNumber(value)}
expected
)} ) } export function ContractCardProbChange(props: { contract: CPMMBinaryContract noLinkAvatar?: boolean className?: string }) { const { noLinkAvatar, className } = props const contract = useContractWithPreload(props.contract) as CPMMBinaryContract return ( {contract.question} ) }