Preview the quick bet result on hover (#319)
* Switch from triangle to a circle arrow
WIP
* Revert "Switch from triangle to a circle arrow"
This reverts commit 370f8eefe4.
* Show amount moved in probability
* Animate the prob bar change too
* Pull out quick bet display component
* Minor cleanups
* Clean up comments
* Close empty divs
* Feedback from Ian
* Pull out constant
* Get rid of quick bet separators
* Fix typescript change
* Invert colors so gray indicates placed bets
* Update comment on useSaveShares re: Ian's comments
			
			
This commit is contained in:
		
							parent
							
								
									2d8ad40e70
								
							
						
					
					
						commit
						f9336c00be
					
				|  | @ -6,7 +6,6 @@ import { | ||||||
|   Contract, |   Contract, | ||||||
|   contractPath, |   contractPath, | ||||||
|   getBinaryProbPercent, |   getBinaryProbPercent, | ||||||
|   listenForContract, |  | ||||||
| } from 'web/lib/firebase/contracts' | } from 'web/lib/firebase/contracts' | ||||||
| import { Col } from '../layout/col' | import { Col } from '../layout/col' | ||||||
| import { | import { | ||||||
|  | @ -26,8 +25,7 @@ import { | ||||||
| import { getOutcomeProbability, getTopAnswer } from 'common/calculate' | import { getOutcomeProbability, getTopAnswer } from 'common/calculate' | ||||||
| import { AvatarDetails, MiscDetails } from './contract-details' | import { AvatarDetails, MiscDetails } from './contract-details' | ||||||
| import { getExpectedValue, getValueFromBucket } from 'common/calculate-dpm' | import { getExpectedValue, getValueFromBucket } from 'common/calculate-dpm' | ||||||
| import { useEffect, useState } from 'react' | import { QuickBet, ProbBar, getColor } from './quick-bet' | ||||||
| import { QuickBet, QuickOutcomeView, ProbBar, getColor } from './quick-bet' |  | ||||||
| import { useContractWithPreload } from 'web/hooks/use-contract' | import { useContractWithPreload } from 'web/hooks/use-contract' | ||||||
| 
 | 
 | ||||||
| export function ContractCard(props: { | export function ContractCard(props: { | ||||||
|  | @ -54,7 +52,7 @@ export function ContractCard(props: { | ||||||
|           className |           className | ||||||
|         )} |         )} | ||||||
|       > |       > | ||||||
|         <Row className={clsx(showQuickBet ? 'divide-x' : '')}> |         <Row> | ||||||
|           <Col className="relative flex-1 gap-3 pr-1"> |           <Col className="relative flex-1 gap-3 pr-1"> | ||||||
|             <div |             <div | ||||||
|               className={clsx( |               className={clsx( | ||||||
|  | @ -92,11 +90,31 @@ export function ContractCard(props: { | ||||||
|             <QuickBet contract={contract} /> |             <QuickBet contract={contract} /> | ||||||
|           ) : ( |           ) : ( | ||||||
|             <Col className="m-auto pl-2"> |             <Col className="m-auto pl-2"> | ||||||
|               <QuickOutcomeView contract={contract} /> |               {outcomeType === 'BINARY' && ( | ||||||
|  |                 <BinaryResolutionOrChance | ||||||
|  |                   className="items-center" | ||||||
|  |                   contract={contract} | ||||||
|  |                 /> | ||||||
|  |               )} | ||||||
|  | 
 | ||||||
|  |               {outcomeType === 'NUMERIC' && ( | ||||||
|  |                 <NumericResolutionOrExpectation | ||||||
|  |                   className="items-center" | ||||||
|  |                   contract={contract as NumericContract} | ||||||
|  |                 /> | ||||||
|  |               )} | ||||||
|  | 
 | ||||||
|  |               {outcomeType === 'FREE_RESPONSE' && ( | ||||||
|  |                 <FreeResponseResolutionOrChance | ||||||
|  |                   className="self-end text-gray-600" | ||||||
|  |                   contract={contract as FullContract<DPM, FreeResponse>} | ||||||
|  |                   truncate="long" | ||||||
|  |                 /> | ||||||
|  |               )} | ||||||
|  |               <ProbBar contract={contract} /> | ||||||
|             </Col> |             </Col> | ||||||
|           )} |           )} | ||||||
|         </Row> |         </Row> | ||||||
|         <ProbBar contract={contract} /> |  | ||||||
|       </Col> |       </Col> | ||||||
|     </div> |     </div> | ||||||
|   ) |   ) | ||||||
|  | @ -106,9 +124,8 @@ export function BinaryResolutionOrChance(props: { | ||||||
|   contract: FullContract<DPM | CPMM, Binary> |   contract: FullContract<DPM | CPMM, Binary> | ||||||
|   large?: boolean |   large?: boolean | ||||||
|   className?: string |   className?: string | ||||||
|   hideText?: boolean |  | ||||||
| }) { | }) { | ||||||
|   const { contract, large, className, hideText } = props |   const { contract, large, className } = props | ||||||
|   const { resolution } = contract |   const { resolution } = contract | ||||||
|   const textColor = `text-${getColor(contract)}` |   const textColor = `text-${getColor(contract)}` | ||||||
| 
 | 
 | ||||||
|  | @ -129,11 +146,9 @@ export function BinaryResolutionOrChance(props: { | ||||||
|       ) : ( |       ) : ( | ||||||
|         <> |         <> | ||||||
|           <div className={textColor}>{getBinaryProbPercent(contract)}</div> |           <div className={textColor}>{getBinaryProbPercent(contract)}</div> | ||||||
|           {!hideText && ( |  | ||||||
|           <div className={clsx(textColor, large ? 'text-xl' : 'text-base')}> |           <div className={clsx(textColor, large ? 'text-xl' : 'text-base')}> | ||||||
|             chance |             chance | ||||||
|           </div> |           </div> | ||||||
|           )} |  | ||||||
|         </> |         </> | ||||||
|       )} |       )} | ||||||
|     </Col> |     </Col> | ||||||
|  | @ -162,9 +177,8 @@ export function FreeResponseResolutionOrChance(props: { | ||||||
|   contract: FreeResponseContract |   contract: FreeResponseContract | ||||||
|   truncate: 'short' | 'long' | 'none' |   truncate: 'short' | 'long' | 'none' | ||||||
|   className?: string |   className?: string | ||||||
|   hideText?: boolean |  | ||||||
| }) { | }) { | ||||||
|   const { contract, truncate, className, hideText } = props |   const { contract, truncate, className } = props | ||||||
|   const { resolution } = contract |   const { resolution } = contract | ||||||
| 
 | 
 | ||||||
|   const topAnswer = getTopAnswer(contract) |   const topAnswer = getTopAnswer(contract) | ||||||
|  | @ -189,7 +203,7 @@ export function FreeResponseResolutionOrChance(props: { | ||||||
|               <div> |               <div> | ||||||
|                 {formatPercent(getOutcomeProbability(contract, topAnswer.id))} |                 {formatPercent(getOutcomeProbability(contract, topAnswer.id))} | ||||||
|               </div> |               </div> | ||||||
|               {!hideText && <div className="text-base">chance</div>} |               <div className="text-base">chance</div> | ||||||
|             </Col> |             </Col> | ||||||
|           </Row> |           </Row> | ||||||
|         ) |         ) | ||||||
|  | @ -201,9 +215,8 @@ export function FreeResponseResolutionOrChance(props: { | ||||||
| export function NumericResolutionOrExpectation(props: { | export function NumericResolutionOrExpectation(props: { | ||||||
|   contract: NumericContract |   contract: NumericContract | ||||||
|   className?: string |   className?: string | ||||||
|   hideText?: boolean |  | ||||||
| }) { | }) { | ||||||
|   const { contract, className, hideText } = props |   const { contract, className } = props | ||||||
|   const { resolution } = contract |   const { resolution } = contract | ||||||
|   const textColor = `text-${getColor(contract)}` |   const textColor = `text-${getColor(contract)}` | ||||||
| 
 | 
 | ||||||
|  | @ -222,9 +235,7 @@ export function NumericResolutionOrExpectation(props: { | ||||||
|           <div className={clsx('text-3xl', textColor)}> |           <div className={clsx('text-3xl', textColor)}> | ||||||
|             {formatLargeNumber(getExpectedValue(contract))} |             {formatLargeNumber(getExpectedValue(contract))} | ||||||
|           </div> |           </div> | ||||||
|           {!hideText && ( |  | ||||||
|           <div className={clsx('text-base', textColor)}>expected</div> |           <div className={clsx('text-base', textColor)}>expected</div> | ||||||
|           )} |  | ||||||
|         </> |         </> | ||||||
|       )} |       )} | ||||||
|     </Col> |     </Col> | ||||||
|  |  | ||||||
|  | @ -1,5 +1,9 @@ | ||||||
| import clsx from 'clsx' | import clsx from 'clsx' | ||||||
| import { getOutcomeProbability, getTopAnswer } from 'common/calculate' | import { | ||||||
|  |   getOutcomeProbability, | ||||||
|  |   getOutcomeProbabilityAfterBet, | ||||||
|  |   getTopAnswer, | ||||||
|  | } from 'common/calculate' | ||||||
| import { getExpectedValue } from 'common/calculate-dpm' | import { getExpectedValue } from 'common/calculate-dpm' | ||||||
| import { | import { | ||||||
|   Contract, |   Contract, | ||||||
|  | @ -8,55 +12,81 @@ import { | ||||||
|   DPM, |   DPM, | ||||||
|   Binary, |   Binary, | ||||||
|   NumericContract, |   NumericContract, | ||||||
|   FreeResponse, |   FreeResponseContract, | ||||||
| } from 'common/contract' | } from 'common/contract' | ||||||
| import { formatMoney } from 'common/util/format' | import { | ||||||
|  |   formatLargeNumber, | ||||||
|  |   formatMoney, | ||||||
|  |   formatPercent, | ||||||
|  | } from 'common/util/format' | ||||||
|  | import { useState } from 'react' | ||||||
| import toast from 'react-hot-toast' | import toast from 'react-hot-toast' | ||||||
| import { useUser } from 'web/hooks/use-user' | import { useUser } from 'web/hooks/use-user' | ||||||
| import { useUserContractBets } from 'web/hooks/use-user-bets' | import { useUserContractBets } from 'web/hooks/use-user-bets' | ||||||
| import { placeBet } from 'web/lib/firebase/api-call' | import { placeBet } from 'web/lib/firebase/api-call' | ||||||
| import { getBinaryProb } from 'web/lib/firebase/contracts' | import { getBinaryProb, getBinaryProbPercent } from 'web/lib/firebase/contracts' | ||||||
| import TriangleDownFillIcon from 'web/lib/icons/triangle-down-fill-icon' | import TriangleDownFillIcon from 'web/lib/icons/triangle-down-fill-icon' | ||||||
| import TriangleFillIcon from 'web/lib/icons/triangle-fill-icon' | import TriangleFillIcon from 'web/lib/icons/triangle-fill-icon' | ||||||
| import { Col } from '../layout/col' | import { Col } from '../layout/col' | ||||||
| import { OUTCOME_TO_COLOR } from '../outcome-label' | import { OUTCOME_TO_COLOR } from '../outcome-label' | ||||||
| import { useSaveShares } from '../use-save-shares' | import { useSaveShares } from '../use-save-shares' | ||||||
| import { | 
 | ||||||
|   BinaryResolutionOrChance, | const BET_SIZE = 10 | ||||||
|   NumericResolutionOrExpectation, |  | ||||||
|   FreeResponseResolutionOrChance, |  | ||||||
| } from './contract-card' |  | ||||||
| 
 | 
 | ||||||
| export function QuickBet(props: { contract: Contract }) { | export function QuickBet(props: { contract: Contract }) { | ||||||
|   const { contract } = props |   const { contract } = props | ||||||
| 
 | 
 | ||||||
|   const user = useUser() |   const user = useUser() | ||||||
|   const userBets = useUserContractBets(user?.id, contract.id) |   const userBets = useUserContractBets(user?.id, contract.id) | ||||||
|   const { yesFloorShares, noFloorShares, yesShares, noShares } = useSaveShares( |   const { yesFloorShares, noFloorShares } = useSaveShares( | ||||||
|     contract as FullContract<CPMM | DPM, Binary>, |     contract as FullContract<CPMM | DPM, Binary>, | ||||||
|     userBets |     userBets | ||||||
|   ) |   ) | ||||||
|   // TODO: For some reason, Floor Shares are inverted for non-BINARY markets
 |   // TODO: This relies on a hack in useSaveShares, where noFloorShares includes
 | ||||||
|  |   // all non-YES shares. Ideally, useSaveShares should group by all outcomes
 | ||||||
|   const hasUpShares = |   const hasUpShares = | ||||||
|     contract.outcomeType === 'BINARY' ? yesFloorShares : noFloorShares |     contract.outcomeType === 'BINARY' ? yesFloorShares : noFloorShares | ||||||
|   const hasDownShares = |   const hasDownShares = | ||||||
|     contract.outcomeType === 'BINARY' ? noFloorShares : yesFloorShares |     contract.outcomeType === 'BINARY' ? noFloorShares : yesFloorShares | ||||||
| 
 | 
 | ||||||
|   const color = getColor(contract) |   const [upHover, setUpHover] = useState(false) | ||||||
|  |   const [downHover, setDownHover] = useState(false) | ||||||
|  | 
 | ||||||
|  |   let previewProb = undefined | ||||||
|  |   try { | ||||||
|  |     previewProb = upHover | ||||||
|  |       ? getOutcomeProbabilityAfterBet( | ||||||
|  |           contract, | ||||||
|  |           quickOutcome(contract, 'UP') || '', | ||||||
|  |           BET_SIZE | ||||||
|  |         ) | ||||||
|  |       : downHover | ||||||
|  |       ? 1 - | ||||||
|  |         getOutcomeProbabilityAfterBet( | ||||||
|  |           contract, | ||||||
|  |           quickOutcome(contract, 'DOWN') || '', | ||||||
|  |           BET_SIZE | ||||||
|  |         ) | ||||||
|  |       : undefined | ||||||
|  |   } catch (e) { | ||||||
|  |     // Catch any errors from hovering on an invalid option
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const color = getColor(contract, previewProb) | ||||||
| 
 | 
 | ||||||
|   async function placeQuickBet(direction: 'UP' | 'DOWN') { |   async function placeQuickBet(direction: 'UP' | 'DOWN') { | ||||||
|     const betPromise = async () => { |     const betPromise = async () => { | ||||||
|       const outcome = quickOutcome(contract, direction) |       const outcome = quickOutcome(contract, direction) | ||||||
|       return await placeBet({ |       return await placeBet({ | ||||||
|         amount: 10, |         amount: BET_SIZE, | ||||||
|         outcome, |         outcome, | ||||||
|         contractId: contract.id, |         contractId: contract.id, | ||||||
|       }) |       }) | ||||||
|     } |     } | ||||||
|     const shortQ = contract.question.slice(0, 20) |     const shortQ = contract.question.slice(0, 20) | ||||||
|     toast.promise(betPromise(), { |     toast.promise(betPromise(), { | ||||||
|       loading: `${formatMoney(10)} on "${shortQ}"...`, |       loading: `${formatMoney(BET_SIZE)} on "${shortQ}"...`, | ||||||
|       success: `${formatMoney(10)} on "${shortQ}"...`, |       success: `${formatMoney(BET_SIZE)} on "${shortQ}"...`, | ||||||
|       error: (err) => `${err.message}`, |       error: (err) => `${err.message}`, | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  | @ -68,7 +98,7 @@ export function QuickBet(props: { contract: Contract }) { | ||||||
|     if (contract.outcomeType === 'FREE_RESPONSE') { |     if (contract.outcomeType === 'FREE_RESPONSE') { | ||||||
|       // TODO: Implement shorting of free response answers
 |       // TODO: Implement shorting of free response answers
 | ||||||
|       if (direction === 'DOWN') { |       if (direction === 'DOWN') { | ||||||
|         throw new Error("Can't short free response answers") |         throw new Error("Can't bet against free response answers") | ||||||
|       } |       } | ||||||
|       return getTopAnswer(contract)?.id |       return getTopAnswer(contract)?.id | ||||||
|     } |     } | ||||||
|  | @ -81,18 +111,19 @@ export function QuickBet(props: { contract: Contract }) { | ||||||
|   return ( |   return ( | ||||||
|     <Col |     <Col | ||||||
|       className={clsx( |       className={clsx( | ||||||
|         'relative -my-4 -mr-5 min-w-[6rem] justify-center gap-2 pr-5 pl-3 align-middle', |         'relative -my-4 -mr-5 min-w-[6rem] justify-center gap-2 pr-5 pl-3 align-middle' | ||||||
|         // Use this for colored QuickBet panes
 |         // Use this for colored QuickBet panes
 | ||||||
|         // `bg-opacity-10 bg-${color}`
 |         // `bg-opacity-10 bg-${color}`
 | ||||||
|         'bg-gray-50' |  | ||||||
|       )} |       )} | ||||||
|     > |     > | ||||||
|       {/* Up bet triangle */} |       {/* Up bet triangle */} | ||||||
|       <div> |       <div> | ||||||
|         <div |         <div | ||||||
|           className="peer absolute top-0 left-0 right-0 h-[50%]" |           className="peer absolute top-0 left-0 right-0 h-[50%]" | ||||||
|  |           onMouseEnter={() => setUpHover(true)} | ||||||
|  |           onMouseLeave={() => setUpHover(false)} | ||||||
|           onClick={() => placeQuickBet('UP')} |           onClick={() => placeQuickBet('UP')} | ||||||
|         ></div> |         /> | ||||||
|         <div className="mt-2 text-center text-xs text-transparent peer-hover:text-gray-400"> |         <div className="mt-2 text-center text-xs text-transparent peer-hover:text-gray-400"> | ||||||
|           {formatMoney(10)} |           {formatMoney(10)} | ||||||
|         </div> |         </div> | ||||||
|  | @ -101,31 +132,43 @@ export function QuickBet(props: { contract: Contract }) { | ||||||
|           <TriangleFillIcon |           <TriangleFillIcon | ||||||
|             className={clsx( |             className={clsx( | ||||||
|               'mx-auto h-5 w-5', |               'mx-auto h-5 w-5', | ||||||
|               `text-${color} text-opacity-70 peer-hover:text-gray-400` |               upHover ? `text-${color}` : 'text-gray-400' | ||||||
|             )} |             )} | ||||||
|           /> |           /> | ||||||
|         ) : ( |         ) : ( | ||||||
|           <TriangleFillIcon className="mx-auto h-5 w-5 text-gray-200 peer-hover:text-gray-400" /> |           <TriangleFillIcon | ||||||
|  |             className={clsx( | ||||||
|  |               'mx-auto h-5 w-5', | ||||||
|  |               upHover ? `text-${color}` : 'text-gray-200' | ||||||
|  |             )} | ||||||
|  |           /> | ||||||
|         )} |         )} | ||||||
|       </div> |       </div> | ||||||
| 
 | 
 | ||||||
|       <QuickOutcomeView contract={contract} /> |       <QuickOutcomeView contract={contract} previewProb={previewProb} /> | ||||||
| 
 | 
 | ||||||
|       {/* Down bet triangle */} |       {/* Down bet triangle */} | ||||||
|       <div> |       <div> | ||||||
|         <div |         <div | ||||||
|           className="peer absolute bottom-0 left-0 right-0 h-[50%]" |           className="peer absolute bottom-0 left-0 right-0 h-[50%]" | ||||||
|  |           onMouseEnter={() => setDownHover(true)} | ||||||
|  |           onMouseLeave={() => setDownHover(false)} | ||||||
|           onClick={() => placeQuickBet('DOWN')} |           onClick={() => placeQuickBet('DOWN')} | ||||||
|         ></div> |         ></div> | ||||||
|         {hasDownShares > 0 ? ( |         {hasDownShares > 0 ? ( | ||||||
|           <TriangleDownFillIcon |           <TriangleDownFillIcon | ||||||
|             className={clsx( |             className={clsx( | ||||||
|               'mx-auto h-5 w-5', |               'mx-auto h-5 w-5', | ||||||
|               `text-${color} text-opacity-70 peer-hover:text-gray-400` |               downHover ? `text-${color}` : 'text-gray-400' | ||||||
|             )} |             )} | ||||||
|           /> |           /> | ||||||
|         ) : ( |         ) : ( | ||||||
|           <TriangleDownFillIcon className="mx-auto h-5 w-5 text-gray-200 peer-hover:text-gray-400" /> |           <TriangleDownFillIcon | ||||||
|  |             className={clsx( | ||||||
|  |               'mx-auto h-5 w-5', | ||||||
|  |               downHover ? `text-${color}` : 'text-gray-200' | ||||||
|  |             )} | ||||||
|  |           /> | ||||||
|         )} |         )} | ||||||
|         <div className="mb-2 text-center text-xs text-transparent peer-hover:text-gray-400"> |         <div className="mb-2 text-center text-xs text-transparent peer-hover:text-gray-400"> | ||||||
|           {formatMoney(10)} |           {formatMoney(10)} | ||||||
|  | @ -135,10 +178,10 @@ export function QuickBet(props: { contract: Contract }) { | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function ProbBar(props: { contract: Contract }) { | export function ProbBar(props: { contract: Contract; previewProb?: number }) { | ||||||
|   const { contract } = props |   const { contract, previewProb } = props | ||||||
|   const color = getColor(contract) |   const color = getColor(contract, previewProb) | ||||||
|   const prob = getProb(contract) |   const prob = previewProb ?? getProb(contract) | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <div |       <div | ||||||
|  | @ -147,7 +190,7 @@ export function ProbBar(props: { contract: Contract }) { | ||||||
|           'bg-gray-200' |           'bg-gray-200' | ||||||
|         )} |         )} | ||||||
|         style={{ height: `${100 * (1 - prob)}%` }} |         style={{ height: `${100 * (1 - prob)}%` }} | ||||||
|       ></div> |       /> | ||||||
|       <div |       <div | ||||||
|         className={clsx( |         className={clsx( | ||||||
|           'absolute right-0 bottom-0 w-2 rounded-br-md transition-all', |           'absolute right-0 bottom-0 w-2 rounded-br-md transition-all', | ||||||
|  | @ -156,41 +199,45 @@ export function ProbBar(props: { contract: Contract }) { | ||||||
|           prob === 1 ? 'rounded-tr-md' : '' |           prob === 1 ? 'rounded-tr-md' : '' | ||||||
|         )} |         )} | ||||||
|         style={{ height: `${100 * prob}%` }} |         style={{ height: `${100 * prob}%` }} | ||||||
|       ></div> |       /> | ||||||
|     </> |     </> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function QuickOutcomeView(props: { contract: Contract }) { | function QuickOutcomeView(props: { | ||||||
|   const { contract } = props |   contract: Contract | ||||||
|  |   previewProb?: number | ||||||
|  |   caption?: 'chance' | 'expected' | ||||||
|  | }) { | ||||||
|  |   const { contract, previewProb, caption } = props | ||||||
|   const { outcomeType } = contract |   const { outcomeType } = contract | ||||||
|  |   // If there's a preview prob, display that instead of the current prob
 | ||||||
|  |   const override = | ||||||
|  |     previewProb === undefined ? undefined : formatPercent(previewProb) | ||||||
|  |   const textColor = `text-${getColor(contract, previewProb)}` | ||||||
|  | 
 | ||||||
|  |   let display: string | undefined | ||||||
|  |   switch (outcomeType) { | ||||||
|  |     case 'BINARY': | ||||||
|  |       display = getBinaryProbPercent(contract) | ||||||
|  |       break | ||||||
|  |     case 'NUMERIC': | ||||||
|  |       display = formatLargeNumber(getExpectedValue(contract as NumericContract)) | ||||||
|  |       break | ||||||
|  |     case 'FREE_RESPONSE': | ||||||
|  |       const topAnswer = getTopAnswer(contract as FreeResponseContract) | ||||||
|  |       display = | ||||||
|  |         topAnswer && | ||||||
|  |         formatPercent(getOutcomeProbability(contract, topAnswer.id)) | ||||||
|  |       break | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <> |     <Col className={clsx('items-center text-3xl', textColor)}> | ||||||
|       {outcomeType === 'BINARY' && ( |       {override ?? display} | ||||||
|         <BinaryResolutionOrChance |       {caption && <div className="text-base">{caption}</div>} | ||||||
|           className="items-center" |       <ProbBar contract={contract} previewProb={previewProb} /> | ||||||
|           contract={contract} |     </Col> | ||||||
|           hideText |  | ||||||
|         /> |  | ||||||
|       )} |  | ||||||
| 
 |  | ||||||
|       {outcomeType === 'NUMERIC' && ( |  | ||||||
|         <NumericResolutionOrExpectation |  | ||||||
|           className="items-center" |  | ||||||
|           contract={contract as NumericContract} |  | ||||||
|           hideText |  | ||||||
|         /> |  | ||||||
|       )} |  | ||||||
| 
 |  | ||||||
|       {outcomeType === 'FREE_RESPONSE' && ( |  | ||||||
|         <FreeResponseResolutionOrChance |  | ||||||
|           className="self-end text-gray-600" |  | ||||||
|           contract={contract as FullContract<DPM, FreeResponse>} |  | ||||||
|           truncate="long" |  | ||||||
|           hideText |  | ||||||
|         /> |  | ||||||
|       )} |  | ||||||
|     </> |  | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -215,15 +262,14 @@ function getNumericScale(contract: NumericContract) { | ||||||
|   return (ev - min) / (max - min) |   return (ev - min) / (max - min) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function getColor(contract: Contract) { | export function getColor(contract: Contract, previewProb?: number) { | ||||||
|   // TODO: Not sure why eg green-400 doesn't work here; try upgrading Tailwind
 |   // TODO: Not sure why eg green-400 doesn't work here; try upgrading Tailwind
 | ||||||
|   // TODO: Try injecting a gradient here
 |   // TODO: Try injecting a gradient here
 | ||||||
|   // return 'primary'
 |   // return 'primary'
 | ||||||
|   const { resolution } = contract |   const { resolution } = contract | ||||||
|   if (resolution) { |   if (resolution) { | ||||||
|     return ( |     return ( | ||||||
|       // @ts-ignore; TODO: Have better typing for contract.resolution?
 |       OUTCOME_TO_COLOR[resolution as 'YES' | 'NO' | 'CANCEL' | 'MKT'] ?? | ||||||
|       OUTCOME_TO_COLOR[resolution] || |  | ||||||
|       // If resolved to a FR answer, use 'primary'
 |       // If resolved to a FR answer, use 'primary'
 | ||||||
|       'primary' |       'primary' | ||||||
|     ) |     ) | ||||||
|  | @ -233,9 +279,6 @@ export function getColor(contract: Contract) { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const marketClosed = (contract.closeTime || Infinity) < Date.now() |   const marketClosed = (contract.closeTime || Infinity) < Date.now() | ||||||
|   return marketClosed |   const prob = previewProb ?? getProb(contract) | ||||||
|     ? 'gray-400' |   return marketClosed ? 'gray-400' : prob >= 0.5 ? 'primary' : 'red-400' | ||||||
|     : getProb(contract) >= 0.5 |  | ||||||
|     ? 'primary' |  | ||||||
|     : 'red-400' |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user