Convert to typed ActivityItems
This commit is contained in:
parent
44a093aff4
commit
29e33bc0ac
|
@ -10,7 +10,7 @@ export type Comment = {
|
||||||
createdTime: number
|
createdTime: number
|
||||||
|
|
||||||
// Denormalized, for rendering comments
|
// Denormalized, for rendering comments
|
||||||
userName?: string
|
userName: string
|
||||||
userUsername?: string
|
userUsername: string
|
||||||
userAvatarUrl?: string
|
userAvatarUrl?: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,29 +9,72 @@ import { filterDefined } from '../../../common/util/array'
|
||||||
import { canAddComment, mapCommentsByBetId } from '../../lib/firebase/comments'
|
import { canAddComment, mapCommentsByBetId } from '../../lib/firebase/comments'
|
||||||
import { fromNow } from '../../lib/util/time'
|
import { fromNow } from '../../lib/util/time'
|
||||||
|
|
||||||
export type ActivityItem = {
|
export type ActivityItem =
|
||||||
|
| DescriptionItem
|
||||||
|
| QuestionItem
|
||||||
|
| BetItem
|
||||||
|
| CommentItem
|
||||||
|
| CreateAnswerItem
|
||||||
|
| BetGroupItem
|
||||||
|
| AnswerGroupItem
|
||||||
|
| CloseItem
|
||||||
|
| ResolveItem
|
||||||
|
|
||||||
|
type BaseActivityItem = {
|
||||||
id: string
|
id: string
|
||||||
type:
|
contract: Contract
|
||||||
| 'bet'
|
|
||||||
| 'comment'
|
|
||||||
| 'start'
|
|
||||||
| 'betgroup'
|
|
||||||
| 'answergroup'
|
|
||||||
| 'close'
|
|
||||||
| 'resolve'
|
|
||||||
| 'expand'
|
|
||||||
| undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FeedAnswerGroupItem = ActivityItem & {
|
export type DescriptionItem = BaseActivityItem & {
|
||||||
|
type: 'description'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type QuestionItem = BaseActivityItem & {
|
||||||
|
type: 'question'
|
||||||
|
showDescription: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BetItem = BaseActivityItem & {
|
||||||
|
type: 'bet'
|
||||||
|
bet: Bet
|
||||||
|
hideOutcome: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CommentItem = BaseActivityItem & {
|
||||||
|
type: 'comment'
|
||||||
|
comment: Comment
|
||||||
|
bet: Bet
|
||||||
|
showOutcomeLabel: boolean
|
||||||
|
truncate: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateAnswerItem = BaseActivityItem & {
|
||||||
|
type: 'createanswer'
|
||||||
|
answer: Answer
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BetGroupItem = BaseActivityItem & {
|
||||||
|
type: 'betgroup'
|
||||||
|
bets: Bet[]
|
||||||
|
hideOutcome: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AnswerGroupItem = BaseActivityItem & {
|
||||||
type: 'answergroup'
|
type: 'answergroup'
|
||||||
contract: Contract
|
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
comments: Comment[]
|
comments: Comment[]
|
||||||
answer: Answer
|
answer: Answer
|
||||||
user: User | null | undefined
|
user: User | null | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CloseItem = BaseActivityItem & {
|
||||||
|
type: 'close'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ResolveItem = BaseActivityItem & {
|
||||||
|
type: 'resolve'
|
||||||
|
}
|
||||||
|
|
||||||
const DAY_IN_MS = 24 * 60 * 60 * 1000
|
const DAY_IN_MS = 24 * 60 * 60 * 1000
|
||||||
|
|
||||||
// Group together bets that are:
|
// Group together bets that are:
|
||||||
|
@ -47,22 +90,38 @@ function groupBets(
|
||||||
userId?: string
|
userId?: string
|
||||||
) {
|
) {
|
||||||
const commentsMap = mapCommentsByBetId(comments)
|
const commentsMap = mapCommentsByBetId(comments)
|
||||||
const items: any[] = []
|
const items: ActivityItem[] = []
|
||||||
let group: Bet[] = []
|
let group: Bet[] = []
|
||||||
|
|
||||||
// Turn the current group into an ActivityItem
|
// Turn the current group into an ActivityItem
|
||||||
function pushGroup() {
|
function pushGroup() {
|
||||||
if (group.length == 1) {
|
if (group.length == 1) {
|
||||||
items.push(toActivityItem(group[0], false))
|
items.push(toActivityItem(group[0]))
|
||||||
} else if (group.length > 1) {
|
} else if (group.length > 1) {
|
||||||
items.push({ type: 'betgroup', bets: [...group], id: group[0].id })
|
items.push({
|
||||||
|
type: 'betgroup',
|
||||||
|
bets: [...group],
|
||||||
|
id: group[0].id,
|
||||||
|
contract,
|
||||||
|
hideOutcome: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
group = []
|
group = []
|
||||||
}
|
}
|
||||||
|
|
||||||
function toActivityItem(bet: Bet, isPublic: boolean) {
|
function toActivityItem(bet: Bet) {
|
||||||
const comment = commentsMap[bet.id]
|
const comment = commentsMap[bet.id]
|
||||||
return comment ? toFeedComment(bet, comment) : toFeedBet(bet, contract)
|
return comment
|
||||||
|
? {
|
||||||
|
type: 'comment' as const,
|
||||||
|
id: bet.id,
|
||||||
|
comment,
|
||||||
|
bet,
|
||||||
|
contract,
|
||||||
|
showOutcomeLabel: true,
|
||||||
|
truncate: true,
|
||||||
|
}
|
||||||
|
: { type: 'bet' as const, id: bet.id, bet, contract, hideOutcome: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const bet of bets) {
|
for (const bet of bets) {
|
||||||
|
@ -71,7 +130,7 @@ function groupBets(
|
||||||
if (commentsMap[bet.id] || isCreator) {
|
if (commentsMap[bet.id] || isCreator) {
|
||||||
pushGroup()
|
pushGroup()
|
||||||
// Create a single item for this
|
// Create a single item for this
|
||||||
items.push(toActivityItem(bet, true))
|
items.push(toActivityItem(bet))
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
group.length > 0 &&
|
group.length > 0 &&
|
||||||
|
@ -86,7 +145,7 @@ function groupBets(
|
||||||
if (group.length > 0) {
|
if (group.length > 0) {
|
||||||
pushGroup()
|
pushGroup()
|
||||||
}
|
}
|
||||||
return items as ActivityItem[]
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAnswerGroups(
|
function getAnswerGroups(
|
||||||
|
@ -135,41 +194,6 @@ function getAnswerGroups(
|
||||||
return answerGroups
|
return answerGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
function toFeedBet(bet: Bet, contract: Contract) {
|
|
||||||
return {
|
|
||||||
id: bet.id,
|
|
||||||
contractId: bet.contractId,
|
|
||||||
userId: bet.userId,
|
|
||||||
type: 'bet',
|
|
||||||
amount: bet.sale ? -bet.sale.amount : bet.amount,
|
|
||||||
outcome: bet.outcome,
|
|
||||||
createdTime: bet.createdTime,
|
|
||||||
date: fromNow(bet.createdTime),
|
|
||||||
contract,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toFeedComment(bet: Bet, comment: Comment) {
|
|
||||||
return {
|
|
||||||
id: bet.id,
|
|
||||||
contractId: bet.contractId,
|
|
||||||
userId: bet.userId,
|
|
||||||
type: 'comment',
|
|
||||||
amount: bet.sale ? -bet.sale.amount : bet.amount,
|
|
||||||
outcome: bet.outcome,
|
|
||||||
createdTime: bet.createdTime,
|
|
||||||
date: fromNow(bet.createdTime),
|
|
||||||
|
|
||||||
// Invariant: bet.comment exists
|
|
||||||
text: comment.text,
|
|
||||||
person: {
|
|
||||||
username: comment.userUsername,
|
|
||||||
name: comment.userName,
|
|
||||||
avatarUrl: comment.userAvatarUrl,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAllContractActivityItems(
|
export function getAllContractActivityItems(
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
bets: Bet[],
|
bets: Bet[],
|
||||||
|
@ -184,8 +208,10 @@ export function getAllContractActivityItems(
|
||||||
? bets.filter((bet) => !bet.isAnte)
|
? bets.filter((bet) => !bet.isAnte)
|
||||||
: bets.filter((bet) => !(bet.isAnte && (bet.outcome as string) === '0'))
|
: bets.filter((bet) => !(bet.isAnte && (bet.outcome as string) === '0'))
|
||||||
|
|
||||||
|
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)
|
||||||
} else if (outcomeType === 'FREE_RESPONSE') {
|
} else if (outcomeType === 'FREE_RESPONSE') {
|
||||||
// Keep bets on comments or your bets where you can comment.
|
// Keep bets on comments or your bets where you can comment.
|
||||||
const commentBetIds = new Set(comments.map((comment) => comment.betId))
|
const commentBetIds = new Set(comments.map((comment) => comment.betId))
|
||||||
|
@ -196,19 +222,18 @@ export function getAllContractActivityItems(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const items: ActivityItem[] = outcome ? [] : [{ type: 'start', id: '0' }]
|
const items: ActivityItem[] =
|
||||||
|
outcome && answer
|
||||||
|
? [{ type: 'createanswer', id: answer.id, contract, answer }]
|
||||||
|
: [{ type: 'description', id: '0', contract }]
|
||||||
|
|
||||||
items.push(...groupBets(bets, comments, DAY_IN_MS, contract, user?.id))
|
items.push(...groupBets(bets, comments, DAY_IN_MS, contract, user?.id))
|
||||||
|
|
||||||
if (contract.closeTime && contract.closeTime <= Date.now()) {
|
if (contract.closeTime && contract.closeTime <= Date.now()) {
|
||||||
items.push({ type: 'close', id: `${contract.closeTime}` })
|
items.push({ type: 'close', id: `${contract.closeTime}`, contract })
|
||||||
}
|
}
|
||||||
if (contract.resolution) {
|
if (contract.resolution) {
|
||||||
items.push({ type: 'resolve', id: `${contract.resolutionTime}` })
|
items.push({ type: 'resolve', id: `${contract.resolutionTime}`, contract })
|
||||||
}
|
|
||||||
if (outcome) {
|
|
||||||
// Hack to add some more padding above the 'multi' feedType, by adding a null item.
|
|
||||||
items.unshift({ type: undefined, id: '-1' })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
@ -223,20 +248,13 @@ 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[] = [{ type: 'start', id: '0' }]
|
const items: ActivityItem[] = []
|
||||||
items.push(
|
items.push(
|
||||||
...(contract.outcomeType === 'FREE_RESPONSE'
|
...(contract.outcomeType === 'FREE_RESPONSE'
|
||||||
? getAnswerGroups(contract, bets, comments, user)
|
? getAnswerGroups(contract, bets, comments, user)
|
||||||
: groupBets(bets, comments, DAY_IN_MS, contract, user?.id))
|
: groupBets(bets, comments, DAY_IN_MS, contract, user?.id))
|
||||||
)
|
)
|
||||||
|
|
||||||
if (contract.closeTime && contract.closeTime <= Date.now()) {
|
|
||||||
items.push({ type: 'close', id: `${contract.closeTime}` })
|
|
||||||
}
|
|
||||||
if (contract.resolution) {
|
|
||||||
items.push({ type: 'resolve', id: `${contract.resolutionTime}` })
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove all but last bet group.
|
// Remove all but last bet group.
|
||||||
const betGroups = items.filter((item) => item.type === 'betgroup')
|
const betGroups = items.filter((item) => item.type === 'betgroup')
|
||||||
const lastBetGroup = betGroups[betGroups.length - 1]
|
const lastBetGroup = betGroups[betGroups.length - 1]
|
||||||
|
@ -244,6 +262,16 @@ export function getRecentContractActivityItems(
|
||||||
(item) => item.type !== 'betgroup' || item.id === lastBetGroup?.id
|
(item) => item.type !== 'betgroup' || item.id === lastBetGroup?.id
|
||||||
)
|
)
|
||||||
|
|
||||||
// Only show the first item plus the last three items.
|
const questionItem: QuestionItem = {
|
||||||
return filtered.length > 3 ? [filtered[0], ...filtered.slice(-3)] : filtered
|
type: 'question',
|
||||||
|
id: '0',
|
||||||
|
contract,
|
||||||
|
showDescription: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
questionItem,
|
||||||
|
// Only take the last three items.
|
||||||
|
...filtered.slice(-3),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {
|
||||||
MAX_COMMENT_LENGTH,
|
MAX_COMMENT_LENGTH,
|
||||||
} from '../../lib/firebase/comments'
|
} from '../../lib/firebase/comments'
|
||||||
import { formatMoney } from '../../../common/util/format'
|
import { formatMoney } from '../../../common/util/format'
|
||||||
|
import { Comment } from '../../../common/comment'
|
||||||
import { ResolutionOrChance } from '../contract-card'
|
import { ResolutionOrChance } from '../contract-card'
|
||||||
import { SiteLink } from '../site-link'
|
import { SiteLink } from '../site-link'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
|
@ -44,7 +45,8 @@ import { parseTags } from '../../../common/util/parse'
|
||||||
import { Avatar } from '../avatar'
|
import { Avatar } from '../avatar'
|
||||||
import { useAdmin } from '../../hooks/use-admin'
|
import { useAdmin } from '../../hooks/use-admin'
|
||||||
import { Answer } from '../../../common/answer'
|
import { Answer } from '../../../common/answer'
|
||||||
import { ActivityItem, FeedAnswerGroupItem } from './activity-items'
|
import { ActivityItem } from './activity-items'
|
||||||
|
import { User } from '../../../common/user'
|
||||||
|
|
||||||
export type FeedType =
|
export type FeedType =
|
||||||
// Main homepage/fold feed,
|
// Main homepage/fold feed,
|
||||||
|
@ -68,8 +70,8 @@ export function FeedItems(props: {
|
||||||
return (
|
return (
|
||||||
<div className="flow-root pr-2 md:pr-0">
|
<div className="flow-root pr-2 md:pr-0">
|
||||||
<div className={clsx(tradingAllowed(contract) ? '' : '-mb-6')}>
|
<div className={clsx(tradingAllowed(contract) ? '' : '-mb-6')}>
|
||||||
{items.map((activityItem, activityItemIdx) => (
|
{items.map((item, activityItemIdx) => (
|
||||||
<div key={activityItem.id} className="relative pb-6">
|
<div key={item.id} className="relative pb-6">
|
||||||
{activityItemIdx !== items.length - 1 ? (
|
{activityItemIdx !== items.length - 1 ? (
|
||||||
<span
|
<span
|
||||||
className="absolute top-5 left-5 -ml-px h-[calc(100%-2rem)] w-0.5 bg-gray-200"
|
className="absolute top-5 left-5 -ml-px h-[calc(100%-2rem)] w-0.5 bg-gray-200"
|
||||||
|
@ -77,32 +79,24 @@ export function FeedItems(props: {
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="relative flex items-start space-x-3">
|
<div className="relative flex items-start space-x-3">
|
||||||
{activityItem.type === 'start' ? (
|
{item.type === 'question' ? (
|
||||||
feedType === 'activity' ? (
|
<FeedQuestion {...item} />
|
||||||
<FeedQuestion contract={contract} />
|
) : item.type === 'description' ? (
|
||||||
) : feedType === 'market' ? (
|
<FeedDescription {...item} />
|
||||||
<FeedDescription contract={contract} />
|
) : item.type === 'createanswer' ? (
|
||||||
) : feedType === 'multi' ? (
|
<FeedCreateAnswer {...item} />
|
||||||
<FeedAnswer contract={contract} outcome={outcome || '0'} />
|
) : item.type === 'comment' ? (
|
||||||
) : null
|
<FeedComment {...item} />
|
||||||
) : activityItem.type === 'comment' ? (
|
) : item.type === 'bet' ? (
|
||||||
<FeedComment
|
<FeedBet {...item} />
|
||||||
activityItem={activityItem}
|
) : item.type === 'betgroup' ? (
|
||||||
moreHref={contractPath(contract)}
|
<FeedBetGroup {...item} />
|
||||||
feedType={feedType}
|
) : item.type === 'answergroup' ? (
|
||||||
/>
|
<FeedAnswerGroup {...item} />
|
||||||
) : activityItem.type === 'bet' ? (
|
) : item.type === 'close' ? (
|
||||||
<FeedBet activityItem={activityItem} feedType={feedType} />
|
<FeedClose {...item} />
|
||||||
) : activityItem.type === 'betgroup' ? (
|
) : item.type === 'resolve' ? (
|
||||||
<FeedBetGroup activityItem={activityItem} feedType={feedType} />
|
<FeedResolve {...item} />
|
||||||
) : activityItem.type === 'answergroup' ? (
|
|
||||||
<FeedAnswerGroup
|
|
||||||
activityItem={activityItem as FeedAnswerGroupItem}
|
|
||||||
/>
|
|
||||||
) : activityItem.type === 'close' ? (
|
|
||||||
<FeedClose contract={contract} />
|
|
||||||
) : activityItem.type === 'resolve' ? (
|
|
||||||
<FeedResolve contract={contract} />
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -116,12 +110,16 @@ export function FeedItems(props: {
|
||||||
}
|
}
|
||||||
|
|
||||||
function FeedComment(props: {
|
function FeedComment(props: {
|
||||||
activityItem: any
|
contract: Contract
|
||||||
moreHref: string
|
comment: Comment
|
||||||
feedType: FeedType
|
bet: Bet
|
||||||
|
showOutcomeLabel: boolean
|
||||||
|
truncate: boolean
|
||||||
}) {
|
}) {
|
||||||
const { activityItem, moreHref, feedType } = props
|
const { contract, comment, bet, showOutcomeLabel, truncate } = props
|
||||||
const { person, text, amount, outcome, createdTime, contract } = activityItem
|
const { createdTime } = contract
|
||||||
|
const { amount, outcome } = bet
|
||||||
|
const { text, userUsername, userName, userAvatarUrl } = comment
|
||||||
|
|
||||||
const bought = amount >= 0 ? 'bought' : 'sold'
|
const bought = amount >= 0 ? 'bought' : 'sold'
|
||||||
const money = formatMoney(Math.abs(amount))
|
const money = formatMoney(Math.abs(amount))
|
||||||
|
@ -134,7 +132,7 @@ function FeedComment(props: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Avatar username={person.username} avatarUrl={person.avatarUrl} />
|
<Avatar username={userUsername} avatarUrl={userAvatarUrl} />
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
{/* {answer && (
|
{/* {answer && (
|
||||||
<div className="text-neutral mb-2" style={{ fontSize: 15 }}>
|
<div className="text-neutral mb-2" style={{ fontSize: 15 }}>
|
||||||
|
@ -145,18 +143,23 @@ function FeedComment(props: {
|
||||||
<p className="mt-0.5 text-sm text-gray-500">
|
<p className="mt-0.5 text-sm text-gray-500">
|
||||||
<UserLink
|
<UserLink
|
||||||
className="text-gray-500"
|
className="text-gray-500"
|
||||||
username={person.username}
|
username={userUsername}
|
||||||
name={person.name}
|
name={userName}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
{bought} {money}
|
{bought} {money}
|
||||||
<MaybeOutcomeLabel outcome={outcome} feedType={feedType} />
|
{showOutcomeLabel && (
|
||||||
|
<>
|
||||||
|
{' '}
|
||||||
|
of <OutcomeLabel outcome={outcome} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Timestamp time={createdTime} />
|
<Timestamp time={createdTime} />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<TruncatedComment
|
<TruncatedComment
|
||||||
comment={text}
|
comment={text}
|
||||||
moreHref={moreHref}
|
moreHref={contractPath(contract)}
|
||||||
shouldTruncate={feedType == 'activity'}
|
shouldTruncate={truncate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -174,27 +177,31 @@ function Timestamp(props: { time: number }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function FeedBet(props: { activityItem: any; feedType: FeedType }) {
|
function FeedBet(props: {
|
||||||
const { activityItem, feedType } = props
|
contract: Contract
|
||||||
const { id, contractId, amount, outcome, createdTime, contract } =
|
bet: Bet
|
||||||
activityItem
|
hideOutcome: boolean
|
||||||
|
}) {
|
||||||
|
const { contract, bet, hideOutcome } = props
|
||||||
|
const { id, amount, outcome, createdTime, userId } = bet
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const isSelf = user?.id == activityItem.userId
|
const isSelf = user?.id === userId
|
||||||
const isCreator = contract.creatorId == activityItem.userId
|
const isCreator = contract.creatorId === userId
|
||||||
|
|
||||||
// You can comment if your bet was posted in the last hour
|
// You can comment if your bet was posted in the last hour
|
||||||
const canComment = canAddComment(createdTime, isSelf)
|
const canComment = canAddComment(createdTime, isSelf)
|
||||||
|
|
||||||
const [comment, setComment] = useState('')
|
const [comment, setComment] = useState('')
|
||||||
async function submitComment() {
|
async function submitComment() {
|
||||||
if (!user || !comment) return
|
if (!user || !comment) return
|
||||||
await createComment(contractId, id, comment, user)
|
await createComment(contract.id, id, comment, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
const bought = amount >= 0 ? 'bought' : 'sold'
|
const bought = amount >= 0 ? 'bought' : 'sold'
|
||||||
const money = formatMoney(Math.abs(amount))
|
const money = formatMoney(Math.abs(amount))
|
||||||
|
|
||||||
const answer =
|
const answer =
|
||||||
feedType !== 'multi' &&
|
!hideOutcome &&
|
||||||
(contract.answers?.find((answer: Answer) => answer?.id === outcome) as
|
(contract.answers?.find((answer: Answer) => answer?.id === outcome) as
|
||||||
| Answer
|
| Answer
|
||||||
| undefined)
|
| undefined)
|
||||||
|
@ -225,8 +232,11 @@ function FeedBet(props: { activityItem: any; feedType: FeedType }) {
|
||||||
{isSelf ? 'You' : isCreator ? contract.creatorName : 'A trader'}
|
{isSelf ? 'You' : isCreator ? contract.creatorName : 'A trader'}
|
||||||
</span>{' '}
|
</span>{' '}
|
||||||
{bought} {money}
|
{bought} {money}
|
||||||
{!answer && (
|
{!answer && !hideOutcome && (
|
||||||
<MaybeOutcomeLabel outcome={outcome} feedType={feedType} />
|
<>
|
||||||
|
{' '}
|
||||||
|
of <OutcomeLabel outcome={outcome} />
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Timestamp time={createdTime} />
|
<Timestamp time={createdTime} />
|
||||||
{canComment && (
|
{canComment && (
|
||||||
|
@ -506,10 +516,8 @@ function FeedDescription(props: { contract: Contract }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function FeedAnswer(props: { contract: Contract; outcome: string }) {
|
function FeedCreateAnswer(props: { contract: Contract; answer: Answer }) {
|
||||||
const { contract, outcome } = props
|
const { contract, answer } = props
|
||||||
const answer = contract?.answers?.[Number(outcome) - 1]
|
|
||||||
if (!answer) return null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -521,7 +529,7 @@ function FeedAnswer(props: { contract: Contract; outcome: string }) {
|
||||||
name={answer.name}
|
name={answer.name}
|
||||||
username={answer.username}
|
username={answer.username}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
submitted answer <OutcomeLabel outcome={outcome} />{' '}
|
submitted answer <OutcomeLabel outcome={answer.id} />{' '}
|
||||||
<Timestamp time={contract.createdTime} />
|
<Timestamp time={contract.createdTime} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -597,12 +605,8 @@ function FeedClose(props: { contract: Contract }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function BetGroupSpan(props: {
|
function BetGroupSpan(props: { bets: Bet[]; outcome?: string }) {
|
||||||
bets: Bet[]
|
const { bets, outcome } = props
|
||||||
outcome: string
|
|
||||||
feedType: FeedType
|
|
||||||
}) {
|
|
||||||
const { bets, outcome, feedType } = props
|
|
||||||
|
|
||||||
const numberTraders = _.uniqBy(bets, (b) => b.userId).length
|
const numberTraders = _.uniqBy(bets, (b) => b.userId).length
|
||||||
|
|
||||||
|
@ -617,15 +621,23 @@ function BetGroupSpan(props: {
|
||||||
{buyTotal > 0 && <>bought {formatMoney(buyTotal)} </>}
|
{buyTotal > 0 && <>bought {formatMoney(buyTotal)} </>}
|
||||||
{sellTotal > 0 && <>sold {formatMoney(sellTotal)} </>}
|
{sellTotal > 0 && <>sold {formatMoney(sellTotal)} </>}
|
||||||
</JoinSpans>
|
</JoinSpans>
|
||||||
<MaybeOutcomeLabel outcome={outcome} feedType={feedType} />{' '}
|
{outcome && (
|
||||||
|
<>
|
||||||
|
{' '}
|
||||||
|
of <OutcomeLabel outcome={outcome} />
|
||||||
|
</>
|
||||||
|
)}{' '}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this expandable to show all grouped bets?
|
// TODO: Make this expandable to show all grouped bets?
|
||||||
function FeedBetGroup(props: { activityItem: any; feedType: FeedType }) {
|
function FeedBetGroup(props: {
|
||||||
const { activityItem, feedType } = props
|
contract: Contract
|
||||||
const bets: Bet[] = activityItem.bets
|
bets: Bet[]
|
||||||
|
hideOutcome: boolean
|
||||||
|
}) {
|
||||||
|
const { bets, hideOutcome } = props
|
||||||
|
|
||||||
const betGroups = _.groupBy(bets, (bet) => bet.outcome)
|
const betGroups = _.groupBy(bets, (bet) => bet.outcome)
|
||||||
const outcomes = Object.keys(betGroups)
|
const outcomes = Object.keys(betGroups)
|
||||||
|
@ -647,9 +659,8 @@ function FeedBetGroup(props: { activityItem: any; feedType: FeedType }) {
|
||||||
{outcomes.map((outcome, index) => (
|
{outcomes.map((outcome, index) => (
|
||||||
<Fragment key={outcome}>
|
<Fragment key={outcome}>
|
||||||
<BetGroupSpan
|
<BetGroupSpan
|
||||||
outcome={outcome}
|
outcome={hideOutcome ? undefined : outcome}
|
||||||
bets={betGroups[outcome]}
|
bets={betGroups[outcome]}
|
||||||
feedType={feedType}
|
|
||||||
/>
|
/>
|
||||||
{index !== outcomes.length - 1 && <br />}
|
{index !== outcomes.length - 1 && <br />}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
@ -661,9 +672,14 @@ function FeedBetGroup(props: { activityItem: any; feedType: FeedType }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function FeedAnswerGroup(props: { activityItem: FeedAnswerGroupItem }) {
|
function FeedAnswerGroup(props: {
|
||||||
const { activityItem } = props
|
contract: Contract
|
||||||
const { contract, answer, bets, comments, user } = activityItem
|
answer: Answer
|
||||||
|
bets: Bet[]
|
||||||
|
comments: Comment[]
|
||||||
|
user: User | null | undefined
|
||||||
|
}) {
|
||||||
|
const { contract, answer, bets, comments, user } = props
|
||||||
|
|
||||||
const betGroups = _.groupBy(bets, (bet) => bet.outcome)
|
const betGroups = _.groupBy(bets, (bet) => bet.outcome)
|
||||||
const outcomes = Object.keys(betGroups)
|
const outcomes = Object.keys(betGroups)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user