Separate answers and comments in FR markets
This commit is contained in:
parent
9199b99fd0
commit
20bd97f828
|
@ -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) {
|
|
||||||
const lastComment = _.last(comments)
|
|
||||||
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) =>
|
outcomes = _.sortBy(outcomes, (outcome) =>
|
||||||
getOutcomeProbability(contract, 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(
|
||||||
|
onlyUsersBetsOrBetsWithComments,
|
||||||
|
comments,
|
||||||
|
contract,
|
||||||
|
user?.id,
|
||||||
|
{
|
||||||
hideOutcome: false,
|
hideOutcome: false,
|
||||||
abbreviated,
|
abbreviated,
|
||||||
smallAvatar: false,
|
smallAvatar: false,
|
||||||
reversed,
|
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(
|
||||||
|
|
|
@ -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 }) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user