Separate answers and comments in FR markets

This commit is contained in:
Ian Philips 2022-04-25 15:49:54 -06:00
parent 9199b99fd0
commit 20bd97f828
2 changed files with 38 additions and 154 deletions

View File

@ -23,7 +23,6 @@ export type ActivityItem =
| CloseItem | CloseItem
| ResolveItem | ResolveItem
| CommentInputItem | CommentInputItem
| AnswerItem
type BaseActivityItem = { type BaseActivityItem = {
id: string id: string
@ -69,16 +68,11 @@ export type BetGroupItem = BaseActivityItem & {
} }
export type AnswerGroupItem = BaseActivityItem & { export type AnswerGroupItem = BaseActivityItem & {
type: 'answergroup' type: 'answergroup' | 'answer'
answer: Answer answer: Answer
items: ActivityItem[] items: ActivityItem[]
} }
export type AnswerItem = BaseActivityItem & {
type: 'answer'
answer: Answer
}
export type CloseItem = BaseActivityItem & { export type CloseItem = BaseActivityItem & {
type: 'close' type: 'close'
} }
@ -239,14 +233,13 @@ function getAnswerGroups(
(answer) => answer.id === outcome (answer) => answer.id === outcome
) as Answer ) as Answer
// let items = groupBets(answerBets, answerComments, contract, user?.id, { let items = groupBets(answerBets, answerComments, contract, user?.id, {
// hideOutcome: true, hideOutcome: true,
// abbreviated, abbreviated,
// smallAvatar: true, smallAvatar: true,
// reversed, reversed,
// }) })
//
let items: ActivityItem[] = []
if (abbreviated) items = items.slice(-2) if (abbreviated) items = items.slice(-2)
return { return {
@ -262,75 +255,33 @@ function getAnswerGroups(
return answerGroups return answerGroups
} }
function getAnswers( function getAnswers(
contract: FullContract<DPM, FreeResponse>, contract: FullContract<DPM, FreeResponse>,
bets: Bet[], bets: Bet[],
comments: Comment[], user: User | undefined | null
user: User | undefined | null,
options: {
sortByProb: boolean
abbreviated: boolean
reversed: boolean
}
) { ) {
const { sortByProb, abbreviated, reversed } = options
let outcomes = _.uniq(bets.map((bet) => bet.outcome)).filter( let outcomes = _.uniq(bets.map((bet) => bet.outcome)).filter(
(outcome) => getOutcomeProbability(contract, outcome) > 0.0001 (outcome) => getOutcomeProbability(contract, outcome) > 0.0001
) )
if (abbreviated) { outcomes = _.sortBy(outcomes, (outcome) =>
const lastComment = _.last(comments) getOutcomeProbability(contract, outcome)
const lastCommentOutcome = bets.find( )
(bet) => bet.id === lastComment?.betId
)?.outcome
const lastBetOutcome = _.last(bets)?.outcome
if (lastCommentOutcome && lastBetOutcome) {
outcomes = _.uniq([
...outcomes.filter(
(outcome) =>
outcome !== lastCommentOutcome && outcome !== lastBetOutcome
),
lastCommentOutcome,
lastBetOutcome,
])
}
outcomes = outcomes.slice(-2)
}
if (sortByProb) {
outcomes = _.sortBy(outcomes, (outcome) =>
getOutcomeProbability(contract, outcome)
)
} else {
// Sort by recent bet.
outcomes = _.sortBy(outcomes, (outcome) =>
_.findLastIndex(bets, (bet) => bet.outcome === outcome)
)
}
const answerGroups = outcomes const answerGroups = outcomes
.map((outcome) => { .map((outcome) => {
const answerBets = bets.filter((bet) => bet.outcome === outcome)
const answerComments = comments.filter((comment) =>
answerBets.some((bet) => bet.id === comment.betId)
)
const answer = contract.answers?.find( const answer = contract.answers?.find(
(answer) => answer.id === outcome (answer) => answer.id === outcome
) as Answer ) as Answer
// let items = groupBets(answerBets, answerComments, contract, user?.id, {
// hideOutcome: true,
// abbreviated,
// smallAvatar: true,
// reversed,
// })
//
return { return {
id: outcome, id: outcome,
type: 'answer' as const, type: 'answer' as const,
contract, contract,
answer, answer,
items: [] as ActivityItem[],
user, user,
className: 'border-base-200 flex-1 bg-base-200 p-3 rounded-md',
} }
}) })
.filter((group) => group.answer) .filter((group) => group.answer)
@ -410,13 +361,24 @@ export function getAllContractActivityItems(
: [{ type: 'description', id: '0', contract }] : [{ type: 'description', id: '0', contract }]
if (outcomeType === 'FREE_RESPONSE') { if (outcomeType === 'FREE_RESPONSE') {
const onlyUsersBetsOrBetsWithComments = bets.filter((bet) =>
comments.some(
(comment) => comment.betId === bet.id || bet.userId === user?.id
)
)
items.push( items.push(
...groupBetsAndComments(bets, comments, contract, user?.id, { ...groupBetsAndComments(
hideOutcome: false, onlyUsersBetsOrBetsWithComments,
abbreviated, comments,
smallAvatar: false, contract,
reversed, user?.id,
}) {
hideOutcome: false,
abbreviated,
smallAvatar: false,
reversed,
}
)
) )
const commentsByBetId = mapCommentsByBetId(comments) const commentsByBetId = mapCommentsByBetId(comments)
items.push({ items.push({
@ -428,17 +390,7 @@ export function getAllContractActivityItems(
}) })
items.push( items.push(
...getAnswers( ...getAnswers(contract as FullContract<DPM, FreeResponse>, bets, user)
contract as FullContract<DPM, FreeResponse>,
bets,
comments,
user,
{
sortByProb: true,
abbreviated,
reversed,
}
)
) )
} else { } else {
items.push( items.push(

View File

@ -1,5 +1,5 @@
// From https://tailwindui.com/components/application-ui/lists/feeds // From https://tailwindui.com/components/application-ui/lists/feeds
import { Fragment, useRef, useState } from 'react' import React, { Fragment, useRef, useState } from 'react'
import * as _ from 'lodash' import * as _ from 'lodash'
import { import {
BanIcon, BanIcon,
@ -110,7 +110,7 @@ function FeedItem(props: { item: ActivityItem }) {
case 'answergroup': case 'answergroup':
return <FeedAnswerGroup {...item} /> return <FeedAnswerGroup {...item} />
case 'answer': case 'answer':
return <FeedAnswer {...item} /> return <FeedAnswerGroup {...item} />
case 'close': case 'close':
return <FeedClose {...item} /> return <FeedClose {...item} />
case 'resolve': case 'resolve':
@ -202,10 +202,6 @@ export function CommentInput(props: {
const user = useUser() const user = useUser()
const [comment, setComment] = useState('') const [comment, setComment] = useState('')
// if (outcomeType === 'FREE_RESPONSE') {
// return <div />
// }
let canCommentOnABet = false let canCommentOnABet = false
bets.some((bet) => { bets.some((bet) => {
// make sure there is not already a comment with a matching bet id: // make sure there is not already a comment with a matching bet id:
@ -653,8 +649,9 @@ function FeedAnswerGroup(props: {
contract: FullContract<any, FreeResponse> contract: FullContract<any, FreeResponse>
answer: Answer answer: Answer
items: ActivityItem[] items: ActivityItem[]
className?: string
}) { }) {
const { answer, items, contract } = props const { answer, items, contract, className } = props
const { username, avatarUrl, name, text } = answer const { username, avatarUrl, name, text } = answer
const prob = getDpmOutcomeProbability(contract.totalShares, answer.id) const prob = getDpmOutcomeProbability(contract.totalShares, answer.id)
@ -662,7 +659,7 @@ function FeedAnswerGroup(props: {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
return ( return (
<Col className="flex-1 gap-2"> <Col className={className ? className : 'flex-1 gap-2'}>
<Modal open={open} setOpen={setOpen}> <Modal open={open} setOpen={setOpen}>
<AnswerBetPanel <AnswerBetPanel
answer={answer} answer={answer}
@ -732,71 +729,6 @@ function FeedAnswerGroup(props: {
</Col> </Col>
) )
} }
function FeedAnswer(props: {
contract: FullContract<any, FreeResponse>
answer: Answer
}) {
const { answer, contract } = props
const { username, avatarUrl, name, text } = answer
const prob = getDpmOutcomeProbability(contract.totalShares, answer.id)
const probPercent = formatPercent(prob)
const [open, setOpen] = useState(false)
return (
<Col
className="border-base-300 flex-1 bg-white p-3"
style={{ borderWidth: 2, borderRadius: 6 }}
>
<Modal open={open} setOpen={setOpen}>
<AnswerBetPanel
answer={answer}
contract={contract}
closePanel={() => setOpen(false)}
className="sm:max-w-84 !rounded-md bg-white !px-8 !py-6"
isModal={true}
/>
</Modal>
<Row className="my-4 gap-3">
<div className="px-1">
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-gray-200">
<Avatar username={username} avatarUrl={avatarUrl} />
</div>
</div>
<Col className="min-w-0 flex-1 gap-2">
<div className="text-sm text-gray-500">
<UserLink username={username} name={name} /> answered
</div>
<Col className="align-items justify-between gap-4 sm:flex-row">
<span className="whitespace-pre-line text-lg">
<Linkify text={text} />
</span>
<Row className="align-items justify-end gap-4">
<span
className={clsx(
'text-2xl',
tradingAllowed(contract) ? 'text-green-500' : 'text-gray-500'
)}
>
{probPercent}
</span>
<BuyButton
className={clsx(
'btn-sm flex-initial !px-6 sm:flex',
tradingAllowed(contract) ? '' : '!hidden'
)}
onClick={() => setOpen(true)}
/>
</Row>
</Col>
</Col>
</Row>
</Col>
)
}
// TODO: Should highlight the entire Feed segment // TODO: Should highlight the entire Feed segment
function FeedExpand(props: { setExpanded: (expanded: boolean) => void }) { function FeedExpand(props: { setExpanded: (expanded: boolean) => void }) {