FR: Use nested comments/bets under answers for contract page. filter more items out of FR feed.
This commit is contained in:
parent
328593ecb0
commit
f8c4bfe5de
|
@ -2,11 +2,12 @@ import _ from 'lodash'
|
||||||
|
|
||||||
import { Answer } from '../../../common/answer'
|
import { Answer } from '../../../common/answer'
|
||||||
import { Bet } from '../../../common/bet'
|
import { Bet } from '../../../common/bet'
|
||||||
|
import { getOutcomeProbability } from '../../../common/calculate'
|
||||||
import { Comment } from '../../../common/comment'
|
import { Comment } from '../../../common/comment'
|
||||||
import { Contract } from '../../../common/contract'
|
import { Contract } from '../../../common/contract'
|
||||||
import { User } from '../../../common/user'
|
import { User } from '../../../common/user'
|
||||||
import { filterDefined } from '../../../common/util/array'
|
import { filterDefined } from '../../../common/util/array'
|
||||||
import { canAddComment, mapCommentsByBetId } from '../../lib/firebase/comments'
|
import { mapCommentsByBetId } from '../../lib/firebase/comments'
|
||||||
|
|
||||||
export type ActivityItem =
|
export type ActivityItem =
|
||||||
| DescriptionItem
|
| DescriptionItem
|
||||||
|
@ -43,7 +44,7 @@ export type CommentItem = BaseActivityItem & {
|
||||||
type: 'comment'
|
type: 'comment'
|
||||||
comment: Comment
|
comment: Comment
|
||||||
bet: Bet
|
bet: Bet
|
||||||
showOutcomeLabel: boolean
|
hideOutcome: boolean
|
||||||
truncate: boolean
|
truncate: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +86,13 @@ function groupBets(
|
||||||
windowMs: number,
|
windowMs: number,
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
userId: string | undefined,
|
userId: string | undefined,
|
||||||
hideOutcome: boolean
|
options: {
|
||||||
|
hideOutcome: boolean
|
||||||
|
truncateComments: boolean
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
|
const { hideOutcome, truncateComments } = options
|
||||||
|
|
||||||
const commentsMap = mapCommentsByBetId(comments)
|
const commentsMap = mapCommentsByBetId(comments)
|
||||||
const items: ActivityItem[] = []
|
const items: ActivityItem[] = []
|
||||||
let group: Bet[] = []
|
let group: Bet[] = []
|
||||||
|
@ -107,7 +113,7 @@ function groupBets(
|
||||||
group = []
|
group = []
|
||||||
}
|
}
|
||||||
|
|
||||||
function toActivityItem(bet: Bet) {
|
function toActivityItem(bet: Bet): ActivityItem {
|
||||||
const comment = commentsMap[bet.id]
|
const comment = commentsMap[bet.id]
|
||||||
return comment
|
return comment
|
||||||
? {
|
? {
|
||||||
|
@ -116,10 +122,16 @@ function groupBets(
|
||||||
comment,
|
comment,
|
||||||
bet,
|
bet,
|
||||||
contract,
|
contract,
|
||||||
showOutcomeLabel: !hideOutcome,
|
hideOutcome,
|
||||||
truncate: true,
|
truncate: truncateComments,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: 'bet' as const,
|
||||||
|
id: bet.id,
|
||||||
|
bet,
|
||||||
|
contract,
|
||||||
|
hideOutcome,
|
||||||
}
|
}
|
||||||
: { type: 'bet' as const, id: bet.id, bet, contract, hideOutcome }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const bet of bets) {
|
for (const bet of bets) {
|
||||||
|
@ -150,24 +162,23 @@ function getAnswerGroups(
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
bets: Bet[],
|
bets: Bet[],
|
||||||
comments: Comment[],
|
comments: Comment[],
|
||||||
user: User | undefined | null
|
user: User | undefined | null,
|
||||||
|
options: {
|
||||||
|
truncateComments: boolean
|
||||||
|
sortByProb: boolean
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
// Keep last two comments.
|
const { truncateComments, sortByProb } = options
|
||||||
comments = comments.slice(-2)
|
|
||||||
const lastBet = bets[bets.length - 1]
|
|
||||||
|
|
||||||
// Include up to 2 outcomes from comments and last bet.
|
let outcomes = _.uniq(bets.map((bet) => bet.outcome)).filter(
|
||||||
const outcomes = filterDefined(
|
(outcome) => getOutcomeProbability(contract.totalShares, outcome) > 0.01
|
||||||
_.uniq([
|
)
|
||||||
...comments.map(
|
if (sortByProb) {
|
||||||
(comment) => bets.find((bet) => bet.id === comment.betId)?.outcome
|
outcomes = _.sortBy(
|
||||||
),
|
outcomes,
|
||||||
lastBet?.outcome,
|
(outcome) => -1 * getOutcomeProbability(contract.totalShares, outcome)
|
||||||
])
|
)
|
||||||
).slice(0, 2)
|
}
|
||||||
|
|
||||||
// Keep bets on selected outcomes.
|
|
||||||
bets = bets.filter((bet) => outcomes.includes(bet.outcome))
|
|
||||||
|
|
||||||
const answerGroups = outcomes.map((outcome) => {
|
const answerGroups = outcomes.map((outcome) => {
|
||||||
const answerBets = bets.filter((bet) => bet.outcome === outcome)
|
const answerBets = bets.filter((bet) => bet.outcome === outcome)
|
||||||
|
@ -178,13 +189,13 @@ function getAnswerGroups(
|
||||||
(answer) => answer.id === outcome
|
(answer) => answer.id === outcome
|
||||||
) as Answer
|
) as Answer
|
||||||
|
|
||||||
const answerItems = groupBets(
|
const items = groupBets(
|
||||||
answerBets,
|
answerBets,
|
||||||
answerComments,
|
answerComments,
|
||||||
DAY_IN_MS,
|
DAY_IN_MS,
|
||||||
contract,
|
contract,
|
||||||
user?.id,
|
user?.id,
|
||||||
true
|
{ hideOutcome: true, truncateComments }
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -192,7 +203,7 @@ function getAnswerGroups(
|
||||||
type: 'answergroup' as const,
|
type: 'answergroup' as const,
|
||||||
contract,
|
contract,
|
||||||
answer,
|
answer,
|
||||||
items: answerItems,
|
items,
|
||||||
user,
|
user,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -208,24 +219,16 @@ export function getAllContractActivityItems(
|
||||||
outcome?: string
|
outcome?: string
|
||||||
) {
|
) {
|
||||||
const { outcomeType } = contract
|
const { outcomeType } = contract
|
||||||
const isBinary = outcomeType === 'BINARY'
|
|
||||||
|
|
||||||
bets = isBinary
|
bets =
|
||||||
? bets.filter((bet) => !bet.isAnte)
|
outcomeType === 'BINARY'
|
||||||
: bets.filter((bet) => !(bet.isAnte && (bet.outcome as string) === '0'))
|
? bets.filter((bet) => !bet.isAnte)
|
||||||
|
: bets.filter((bet) => !(bet.isAnte && (bet.outcome as string) === '0'))
|
||||||
|
|
||||||
let answer: Answer | undefined
|
let answer: Answer | undefined
|
||||||
if (outcome) {
|
if (outcome) {
|
||||||
bets = bets.filter((bet) => bet.outcome === outcome)
|
bets = bets.filter((bet) => bet.outcome === outcome)
|
||||||
answer = contract.answers?.find((answer) => answer.id === outcome)
|
answer = contract.answers?.find((answer) => answer.id === outcome)
|
||||||
} else if (outcomeType === 'FREE_RESPONSE') {
|
|
||||||
// Keep bets on comments or your bets where you can comment.
|
|
||||||
const commentBetIds = new Set(comments.map((comment) => comment.betId))
|
|
||||||
bets = bets.filter(
|
|
||||||
(bet) =>
|
|
||||||
commentBetIds.has(bet.id) ||
|
|
||||||
canAddComment(bet.createdTime, user?.id === bet.userId)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const items: ActivityItem[] =
|
const items: ActivityItem[] =
|
||||||
|
@ -234,7 +237,15 @@ export function getAllContractActivityItems(
|
||||||
: [{ type: 'description', id: '0', contract }]
|
: [{ type: 'description', id: '0', contract }]
|
||||||
|
|
||||||
items.push(
|
items.push(
|
||||||
...groupBets(bets, comments, DAY_IN_MS, contract, user?.id, !!outcome)
|
...(outcomeType === 'FREE_RESPONSE' && !outcome
|
||||||
|
? getAnswerGroups(contract, bets, comments, user, {
|
||||||
|
truncateComments: false,
|
||||||
|
sortByProb: true,
|
||||||
|
})
|
||||||
|
: groupBets(bets, comments, DAY_IN_MS, contract, user?.id, {
|
||||||
|
hideOutcome: !!outcome,
|
||||||
|
truncateComments: false,
|
||||||
|
}))
|
||||||
)
|
)
|
||||||
|
|
||||||
if (contract.closeTime && contract.closeTime <= Date.now()) {
|
if (contract.closeTime && contract.closeTime <= Date.now()) {
|
||||||
|
@ -256,18 +267,6 @@ export function getRecentContractActivityItems(
|
||||||
bets = bets.sort((b1, b2) => b1.createdTime - b2.createdTime)
|
bets = bets.sort((b1, b2) => b1.createdTime - b2.createdTime)
|
||||||
comments = comments.sort((c1, c2) => c1.createdTime - c2.createdTime)
|
comments = comments.sort((c1, c2) => c1.createdTime - c2.createdTime)
|
||||||
|
|
||||||
const items: ActivityItem[] =
|
|
||||||
contract.outcomeType === 'FREE_RESPONSE'
|
|
||||||
? getAnswerGroups(contract, bets, comments, user)
|
|
||||||
: groupBets(bets, comments, DAY_IN_MS, contract, user?.id, false)
|
|
||||||
|
|
||||||
// Remove all but last bet group.
|
|
||||||
const betGroups = items.filter((item) => item.type === 'betgroup')
|
|
||||||
const lastBetGroup = betGroups[betGroups.length - 1]
|
|
||||||
const filtered = items.filter(
|
|
||||||
(item) => item.type !== 'betgroup' || item.id === lastBetGroup?.id
|
|
||||||
)
|
|
||||||
|
|
||||||
const questionItem: QuestionItem = {
|
const questionItem: QuestionItem = {
|
||||||
type: 'question',
|
type: 'question',
|
||||||
id: '0',
|
id: '0',
|
||||||
|
@ -275,9 +274,52 @@ export function getRecentContractActivityItems(
|
||||||
showDescription: false,
|
showDescription: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
let items: ActivityItem[] = []
|
||||||
questionItem,
|
|
||||||
// Only take the last three items.
|
if (contract.outcomeType === 'FREE_RESPONSE') {
|
||||||
...filtered.slice(-3),
|
// Keep last two comments.
|
||||||
]
|
comments = comments.slice(-2)
|
||||||
|
const lastBet = bets[bets.length - 1]
|
||||||
|
|
||||||
|
const outcomeToComments = _.groupBy(comments, (c) => {
|
||||||
|
const bet = bets.find((bet) => bet.id === c.betId)
|
||||||
|
return bet?.outcome
|
||||||
|
})
|
||||||
|
delete outcomeToComments['undefined']
|
||||||
|
|
||||||
|
// Include up to 2 outcomes from comments and last bet.
|
||||||
|
const outcomes = filterDefined(
|
||||||
|
_.uniq([...Object.keys(outcomeToComments), lastBet?.outcome])
|
||||||
|
).slice(-2)
|
||||||
|
|
||||||
|
// Keep bets on selected outcomes.
|
||||||
|
bets = bets.filter((bet) => outcomes.includes(bet.outcome))
|
||||||
|
// Filter out bets before comments.
|
||||||
|
bets = bets.filter((bet) => {
|
||||||
|
const comments = outcomeToComments[bet.outcome]
|
||||||
|
if (
|
||||||
|
!comments ||
|
||||||
|
comments.length === 0 ||
|
||||||
|
comments.some((c) => c.betId === bet.id)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
return comments.every((c) => c.createdTime <= bet.createdTime)
|
||||||
|
})
|
||||||
|
|
||||||
|
items.push(
|
||||||
|
...getAnswerGroups(contract, bets, comments, user, {
|
||||||
|
truncateComments: true,
|
||||||
|
sortByProb: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
items.push(
|
||||||
|
...groupBets(bets, comments, DAY_IN_MS, contract, user?.id, {
|
||||||
|
hideOutcome: false,
|
||||||
|
truncateComments: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [questionItem, ...items.slice(-3)]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import _, { update } from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
import { Contract } from '../../lib/firebase/contracts'
|
import { Contract } from '../../lib/firebase/contracts'
|
||||||
import { Comment } from '../../lib/firebase/comments'
|
import { Comment } from '../../lib/firebase/comments'
|
||||||
|
|
|
@ -110,10 +110,10 @@ function FeedComment(props: {
|
||||||
contract: Contract
|
contract: Contract
|
||||||
comment: Comment
|
comment: Comment
|
||||||
bet: Bet
|
bet: Bet
|
||||||
showOutcomeLabel: boolean
|
hideOutcome: boolean
|
||||||
truncate: boolean
|
truncate: boolean
|
||||||
}) {
|
}) {
|
||||||
const { contract, comment, bet, showOutcomeLabel, truncate } = props
|
const { contract, comment, bet, hideOutcome, truncate } = props
|
||||||
const { amount, outcome } = bet
|
const { amount, outcome } = bet
|
||||||
const { text, userUsername, userName, userAvatarUrl, createdTime } = comment
|
const { text, userUsername, userName, userAvatarUrl, createdTime } = comment
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ function FeedComment(props: {
|
||||||
name={userName}
|
name={userName}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
{bought} {money}
|
{bought} {money}
|
||||||
{showOutcomeLabel && (
|
{!hideOutcome && (
|
||||||
<>
|
<>
|
||||||
{' '}
|
{' '}
|
||||||
of <OutcomeLabel outcome={outcome} />
|
of <OutcomeLabel outcome={outcome} />
|
||||||
|
@ -615,7 +615,6 @@ function BetGroupSpan(props: { bets: Bet[]; outcome?: string }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this expandable to show all grouped bets?
|
|
||||||
function FeedBetGroup(props: {
|
function FeedBetGroup(props: {
|
||||||
contract: Contract
|
contract: Contract
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user