2022-02-20 22:25:58 +00:00
|
|
|
import _ from 'lodash'
|
|
|
|
import { useLayoutEffect, useState } from 'react'
|
|
|
|
|
2022-05-09 13:04:36 +00:00
|
|
|
import { DPM, FreeResponse, FullContract } from 'common/contract'
|
2022-02-20 22:25:58 +00:00
|
|
|
import { Col } from '../layout/col'
|
2022-05-09 13:04:36 +00:00
|
|
|
import { useUser } from 'web/hooks/use-user'
|
|
|
|
import { getDpmOutcomeProbability } from 'common/calculate-dpm'
|
|
|
|
import { useAnswers } from 'web/hooks/use-answers'
|
|
|
|
import { tradingAllowed } from 'web/lib/firebase/contracts'
|
2022-02-20 22:25:58 +00:00
|
|
|
import { AnswerItem } from './answer-item'
|
|
|
|
import { CreateAnswerPanel } from './create-answer-panel'
|
|
|
|
import { AnswerResolvePanel } from './answer-resolve-panel'
|
2022-04-18 23:02:40 +00:00
|
|
|
import { Spacer } from '../layout/spacer'
|
2022-04-26 15:53:12 +00:00
|
|
|
import { FeedItems } from '../feed/feed-items'
|
|
|
|
import { ActivityItem } from '../feed/activity-items'
|
2022-05-09 13:04:36 +00:00
|
|
|
import { User } from 'common/user'
|
|
|
|
import { getOutcomeProbability } from 'common/calculate'
|
|
|
|
import { Answer } from 'common/answer'
|
2022-02-20 22:25:58 +00:00
|
|
|
|
2022-03-15 22:27:51 +00:00
|
|
|
export function AnswersPanel(props: {
|
|
|
|
contract: FullContract<DPM, FreeResponse>
|
|
|
|
}) {
|
2022-02-20 22:25:58 +00:00
|
|
|
const { contract } = props
|
2022-02-22 20:12:49 +00:00
|
|
|
const { creatorId, resolution, resolutions, totalBets } = contract
|
2022-02-20 22:25:58 +00:00
|
|
|
|
2022-04-11 21:13:26 +00:00
|
|
|
const answers = useAnswers(contract.id) ?? contract.answers
|
2022-05-04 22:03:06 +00:00
|
|
|
const [winningAnswers, losingAnswers] = _.partition(
|
2022-02-22 20:12:49 +00:00
|
|
|
answers.filter(
|
|
|
|
(answer) => answer.id !== '0' && totalBets[answer.id] > 0.000000001
|
|
|
|
),
|
2022-02-20 22:25:58 +00:00
|
|
|
(answer) =>
|
|
|
|
answer.id === resolution || (resolutions && resolutions[answer.id])
|
|
|
|
)
|
|
|
|
const sortedAnswers = [
|
|
|
|
..._.sortBy(winningAnswers, (answer) =>
|
|
|
|
resolutions ? -1 * resolutions[answer.id] : 0
|
|
|
|
),
|
|
|
|
..._.sortBy(
|
2022-05-04 22:03:06 +00:00
|
|
|
resolution ? [] : losingAnswers,
|
2022-03-15 22:27:51 +00:00
|
|
|
(answer) => -1 * getDpmOutcomeProbability(contract.totalShares, answer.id)
|
2022-02-20 22:25:58 +00:00
|
|
|
),
|
|
|
|
]
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
2022-05-04 22:03:06 +00:00
|
|
|
const answerItems = getAnswerItems(
|
|
|
|
contract,
|
|
|
|
losingAnswers.length > 0 ? losingAnswers : sortedAnswers,
|
|
|
|
user
|
|
|
|
)
|
2022-04-26 15:53:12 +00:00
|
|
|
|
2022-02-20 22:25:58 +00:00
|
|
|
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 (
|
|
|
|
<Col className="gap-3">
|
2022-05-04 22:03:06 +00:00
|
|
|
{(resolveOption || resolution) &&
|
2022-04-18 23:02:40 +00:00
|
|
|
sortedAnswers.map((answer) => (
|
|
|
|
<AnswerItem
|
|
|
|
key={answer.id}
|
|
|
|
answer={answer}
|
|
|
|
contract={contract}
|
|
|
|
showChoice={showChoice}
|
|
|
|
chosenProb={chosenAnswers[answer.id]}
|
|
|
|
totalChosenProb={chosenTotal}
|
|
|
|
onChoose={onChoose}
|
|
|
|
onDeselect={onDeselect}
|
|
|
|
/>
|
|
|
|
))}
|
2022-02-20 22:25:58 +00:00
|
|
|
|
2022-05-04 22:03:06 +00:00
|
|
|
{!resolveOption && (
|
2022-04-26 15:53:12 +00:00
|
|
|
<FeedItems
|
|
|
|
contract={contract}
|
|
|
|
items={answerItems}
|
2022-05-10 20:59:19 +00:00
|
|
|
className={'pr-2 md:pr-0'}
|
2022-04-26 15:53:12 +00:00
|
|
|
betRowClassName={''}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
|
2022-05-04 22:03:06 +00:00
|
|
|
{answers.length <= 1 && (
|
|
|
|
<div className="pb-4 text-gray-500">No answers yet...</div>
|
|
|
|
)}
|
|
|
|
|
2022-04-18 23:02:40 +00:00
|
|
|
{tradingAllowed(contract) &&
|
|
|
|
(!resolveOption || resolveOption === 'CANCEL') && (
|
|
|
|
<CreateAnswerPanel contract={contract} />
|
|
|
|
)}
|
2022-02-20 22:25:58 +00:00
|
|
|
|
|
|
|
{user?.id === creatorId && !resolution && (
|
2022-04-18 23:02:40 +00:00
|
|
|
<>
|
|
|
|
<Spacer h={2} />
|
|
|
|
<AnswerResolvePanel
|
|
|
|
contract={contract}
|
|
|
|
resolveOption={resolveOption}
|
|
|
|
setResolveOption={setResolveOption}
|
|
|
|
chosenAnswers={chosenAnswers}
|
|
|
|
/>
|
|
|
|
</>
|
2022-02-20 22:25:58 +00:00
|
|
|
)}
|
|
|
|
</Col>
|
|
|
|
)
|
|
|
|
}
|
2022-04-26 15:53:12 +00:00
|
|
|
|
2022-05-04 22:03:06 +00:00
|
|
|
function getAnswerItems(
|
2022-04-26 15:53:12 +00:00
|
|
|
contract: FullContract<DPM, FreeResponse>,
|
2022-05-04 22:03:06 +00:00
|
|
|
answers: Answer[],
|
2022-04-26 15:53:12 +00:00
|
|
|
user: User | undefined | null
|
|
|
|
) {
|
|
|
|
let outcomes = _.uniq(
|
|
|
|
answers.map((answer) => answer.number.toString())
|
|
|
|
).filter((outcome) => getOutcomeProbability(contract, outcome) > 0.0001)
|
|
|
|
outcomes = _.sortBy(outcomes, (outcome) =>
|
|
|
|
getOutcomeProbability(contract, outcome)
|
|
|
|
).reverse()
|
|
|
|
|
|
|
|
return outcomes
|
|
|
|
.map((outcome) => {
|
|
|
|
const answer = answers.find((answer) => answer.id === outcome) as Answer
|
|
|
|
//unnecessary
|
|
|
|
return {
|
|
|
|
id: outcome,
|
|
|
|
type: 'answer' as const,
|
|
|
|
contract,
|
|
|
|
answer,
|
|
|
|
items: [] as ActivityItem[],
|
|
|
|
user,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.filter((group) => group.answer)
|
|
|
|
}
|