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 (
+
{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) => (