diff --git a/web/components/answers-panel.tsx b/web/components/answers-panel.tsx deleted file mode 100644 index 58a3f15c..00000000 --- a/web/components/answers-panel.tsx +++ /dev/null @@ -1,690 +0,0 @@ -import clsx from 'clsx' -import _ from 'lodash' -import { useEffect, useLayoutEffect, useRef, useState } from 'react' -import Textarea from 'react-expanding-textarea' -import { XIcon } from '@heroicons/react/solid' - -import { Answer } from '../../common/answer' -import { Contract } from '../../common/contract' -import { AmountInput } from './amount-input' -import { Col } from './layout/col' -import { createAnswer, placeBet, resolveMarket } from '../lib/firebase/api-call' -import { Row } from './layout/row' -import { Avatar } from './avatar' -import { SiteLink } from './site-link' -import { DateTimeTooltip } from './datetime-tooltip' -import dayjs from 'dayjs' -import { BuyButton, ChooseCancelSelector } from './yes-no-selector' -import { Spacer } from './layout/spacer' -import { - formatMoney, - formatPercent, - formatWithCommas, -} from '../../common/util/format' -import { InfoTooltip } from './info-tooltip' -import { useUser } from '../hooks/use-user' -import { - getProbabilityAfterBet, - getOutcomeProbability, - calculateShares, - calculatePayoutAfterCorrectBet, -} from '../../common/calculate' -import { firebaseLogin } from '../lib/firebase/users' -import { Bet } from '../../common/bet' -import { useAnswers } from '../hooks/use-answers' -import { ResolveConfirmationButton } from './confirmation-button' -import { tradingAllowed } from '../lib/firebase/contracts' -import { removeUndefinedProps } from '../../common/util/object' - -export function AnswersPanel(props: { contract: Contract; answers: Answer[] }) { - const { contract } = props - const { creatorId, resolution, resolutions } = contract - - const answers = useAnswers(contract.id) ?? props.answers - const [winningAnswers, otherAnswers] = _.partition( - answers.filter((answer) => answer.id !== '0'), - (answer) => - answer.id === resolution || (resolutions && resolutions[answer.id]) - ) - const sortedAnswers = [ - ..._.sortBy(winningAnswers, (answer) => - resolutions ? -1 * resolutions[answer.id] : 0 - ), - ..._.sortBy( - otherAnswers, - (answer) => -1 * getOutcomeProbability(contract.totalShares, answer.id) - ), - ] - - const user = useUser() - - const [resolveOption, setResolveOption] = useState< - 'CHOOSE' | 'CHOOSE_MULTIPLE' | 'CANCEL' | undefined - >() - const [chosenAnswers, setChosenAnswers] = useState<{ - [answerId: string]: number - }>({}) - - const chosenTotal = _.sum(Object.values(chosenAnswers)) - - const onChoose = (answerId: string, prob: number) => { - if (resolveOption === 'CHOOSE') { - setChosenAnswers({ [answerId]: prob }) - } else { - setChosenAnswers((chosenAnswers) => { - return { - ...chosenAnswers, - [answerId]: prob, - } - }) - } - } - - const onDeselect = (answerId: string) => { - setChosenAnswers((chosenAnswers) => { - const newChosenAnswers = { ...chosenAnswers } - delete newChosenAnswers[answerId] - return newChosenAnswers - }) - } - - useLayoutEffect(() => { - setChosenAnswers({}) - }, [resolveOption]) - - const showChoice = resolution - ? undefined - : resolveOption === 'CHOOSE' - ? 'radio' - : resolveOption === 'CHOOSE_MULTIPLE' - ? 'checkbox' - : undefined - - return ( - - {sortedAnswers.map((answer) => ( - - ))} - - {sortedAnswers.length === 0 ? ( -
No answers yet...
- ) : ( -
- None of the above:{' '} - {formatPercent(getOutcomeProbability(contract.totalShares, '0'))} -
- )} - - {tradingAllowed(contract) && !resolveOption && ( - - )} - - {user?.id === creatorId && !resolution && ( - - )} - - ) -} - -function AnswerItem(props: { - answer: Answer - contract: Contract - showChoice: 'radio' | 'checkbox' | undefined - chosenProb: number | undefined - totalChosenProb?: number - onChoose: (answerId: string, prob: number) => void - onDeselect: (answerId: string) => void -}) { - const { - answer, - contract, - showChoice, - chosenProb, - totalChosenProb, - onChoose, - onDeselect, - } = props - const { resolution, resolutions, totalShares } = contract - const { username, avatarUrl, name, createdTime, number, text } = answer - const isChosen = chosenProb !== undefined - - const createdDate = dayjs(createdTime).format('MMM D') - const prob = getOutcomeProbability(totalShares, answer.id) - const roundedProb = Math.round(prob * 100) - const probPercent = formatPercent(prob) - const wasResolvedTo = - resolution === answer.id || (resolutions && resolutions[answer.id]) - - const [isBetting, setIsBetting] = useState(false) - - return ( - - -
{text}
- - - - - -
{name}
-
-
- -
- -
- - {createdDate} - -
-
-
#{number}
-
- - - {isBetting ? ( - setIsBetting(false)} - /> - ) : ( - - {!wasResolvedTo && - (showChoice === 'checkbox' ? ( - { - const { value } = e.target - const numberValue = value - ? parseInt(value.replace(/[^\d]/, '')) - : 0 - if (!isNaN(numberValue)) onChoose(answer.id, numberValue) - }} - /> - ) : ( -
- {probPercent} -
- ))} - {showChoice ? ( -
- - {showChoice === 'checkbox' && ( -
- {chosenProb && totalChosenProb - ? Math.round((100 * chosenProb) / totalChosenProb) - : 0} - % share -
- )} -
- ) : ( - <> - {tradingAllowed(contract) && ( - { - setIsBetting(true) - }} - /> - )} - {wasResolvedTo && ( - -
- Chosen{' '} - {resolutions - ? `${Math.round(resolutions[answer.id])}%` - : ''} -
-
{probPercent}
- - )} - - )} -
- )} - - ) -} - -function AnswerBetPanel(props: { - answer: Answer - contract: Contract - closePanel: () => void -}) { - const { answer, contract, closePanel } = props - const { id: answerId } = answer - - const user = useUser() - const [betAmount, setBetAmount] = useState(undefined) - - const [error, setError] = useState() - const [isSubmitting, setIsSubmitting] = useState(false) - - const inputRef = useRef(null) - useEffect(() => { - inputRef.current && inputRef.current.focus() - }, []) - - async function submitBet() { - if (!user || !betAmount) return - - if (user.balance < betAmount) { - setError('Insufficient balance') - return - } - - setError(undefined) - setIsSubmitting(true) - - const result = await placeBet({ - amount: betAmount, - outcome: answerId, - contractId: contract.id, - }).then((r) => r.data as any) - - console.log('placed bet. Result:', result) - - if (result?.status === 'success') { - setIsSubmitting(false) - closePanel() - } else { - setError(result?.error || 'Error placing bet') - setIsSubmitting(false) - } - } - - const betDisabled = isSubmitting || !betAmount || error - - const initialProb = getOutcomeProbability(contract.totalShares, answer.id) - - const resultProb = getProbabilityAfterBet( - contract.totalShares, - answerId, - betAmount ?? 0 - ) - - const shares = calculateShares(contract.totalShares, betAmount ?? 0, answerId) - - const currentPayout = betAmount - ? calculatePayoutAfterCorrectBet(contract, { - outcome: answerId, - amount: betAmount, - shares, - } as Bet) - : 0 - - const currentReturn = betAmount ? (currentPayout - betAmount) / betAmount : 0 - const currentReturnPercent = (currentReturn * 100).toFixed() + '%' - - return ( - - -
Buy this answer
- - -
-
Amount
- - - - -
Implied probability
- -
{formatPercent(initialProb)}
-
-
{formatPercent(resultProb)}
-
- - - - - Payout if chosen - - -
- {formatMoney(currentPayout)} -   (+{currentReturnPercent}) -
- - - - {user ? ( - - ) : ( - - )} - - ) -} - -function CreateAnswerInput(props: { contract: Contract }) { - const { contract } = props - const user = useUser() - const [text, setText] = useState('') - const [betAmount, setBetAmount] = useState(10) - const [amountError, setAmountError] = useState() - const [isSubmitting, setIsSubmitting] = useState(false) - - const canSubmit = text && betAmount && !amountError && !isSubmitting - - const submitAnswer = async () => { - if (canSubmit) { - setIsSubmitting(true) - const result = await createAnswer({ - contractId: contract.id, - text, - amount: betAmount, - }).then((r) => r.data) - - setIsSubmitting(false) - - if (result.status === 'success') { - setText('') - setBetAmount(10) - setAmountError(undefined) - } - } - } - - const resultProb = getProbabilityAfterBet( - contract.totalShares, - 'new', - betAmount ?? 0 - ) - - const shares = calculateShares(contract.totalShares, betAmount ?? 0, 'new') - - const currentPayout = betAmount - ? calculatePayoutAfterCorrectBet(contract, { - outcome: 'new', - amount: betAmount, - shares, - } as Bet) - : 0 - - const currentReturn = betAmount ? (currentPayout - betAmount) / betAmount : 0 - const currentReturnPercent = (currentReturn * 100).toFixed() + '%' - - return ( - - -
Add your answer
-