import clsx from 'clsx'
import Link from 'next/link'
import { Row } from '../layout/row'
import {
formatLargeNumber,
formatMoney,
formatPercent,
} from 'common/util/format'
import {
Contract,
contractPath,
getBinaryProbPercent,
getBinaryProb,
} from 'web/lib/firebase/contracts'
import { Col } from '../layout/col'
import {
Binary,
CPMM,
DPM,
FreeResponse,
FreeResponseContract,
FullContract,
NumericContract,
} from 'common/contract'
import {
AnswerLabel,
BinaryContractOutcomeLabel,
FreeResponseOutcomeLabel,
OUTCOME_TO_COLOR,
} from '../outcome-label'
import { getOutcomeProbability, getTopAnswer } from 'common/calculate'
import { AvatarDetails, MiscDetails } from './contract-details'
import { getExpectedValue, getValueFromBucket } from 'common/calculate-dpm'
import TriangleFillIcon from 'web/lib/icons/triangle-fill-icon'
import TriangleDownFillIcon from 'web/lib/icons/triangle-down-fill-icon'
import toast from 'react-hot-toast'
import { CheckIcon, XIcon } from '@heroicons/react/solid'
import { useEffect, useState } from 'react'
import { APIError, placeBet } from 'web/lib/firebase/api-call'
// 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 || '')
: outcomeType === 'NUMERIC'
? getNumericScale(contract as NumericContract)
: 1 // Should not happen
}
function getNumericScale(contract: NumericContract) {
const { min, max } = contract
const ev = getExpectedValue(contract)
return (ev - min) / (max - min)
}
function getColor(contract: Contract) {
// TODO: Not sure why eg green-400 doesn't work here; try upgrading Tailwind
// TODO: Try injecting a gradient here
// return 'primary'
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'
)
}
if (contract.outcomeType === 'NUMERIC') {
return 'blue-400'
}
const marketClosed = (contract.closeTime || Infinity) < Date.now()
return marketClosed
? 'gray-400'
: getProb(contract) >= 0.5
? 'primary'
: 'red-400'
}
export function ContractCard(props: {
contract: Contract
showHotVolume?: boolean
showCloseTime?: boolean
className?: string
}) {
const { contract, showHotVolume, showCloseTime, className } = props
const { question, outcomeType } = contract
const prob = getProb(contract)
const color = getColor(contract)
const marketClosed = (contract.closeTime || Infinity) < Date.now()
// TODO: switch to useContract after you place a bet on it
function betToast(outcome: string) {
let canceled = false
const toastId = toast.custom(
{question}
{outcomeType === 'FREE_RESPONSE' && (Betting M$10 on {outcome} in {secondsLeft}s