From 78997c1e45afcbb8b10dc7198306af4eb342d253 Mon Sep 17 00:00:00 2001 From: Boa Date: Fri, 29 Apr 2022 15:11:04 -0600 Subject: [PATCH] Show comments position (#110) * Add betting activity back to feed * Show position in bin. markets, no comments on bets * Degroup bets on Bets tab * Show users position or recent bet with comments * Add tooltip on answer to FR comments * Style improvements * Only use bets by current user for comment input --- web/components/feed/activity-items.ts | 91 ++++--- web/components/feed/feed-items.tsx | 328 +++++++++++++++++------- web/components/outcome-label.tsx | 34 ++- web/pages/[username]/[contractSlug].tsx | 2 +- 4 files changed, 308 insertions(+), 147 deletions(-) diff --git a/web/components/feed/activity-items.ts b/web/components/feed/activity-items.ts index a12c4e0a..7879b637 100644 --- a/web/components/feed/activity-items.ts +++ b/web/components/feed/activity-items.ts @@ -31,6 +31,8 @@ type BaseActivityItem = { export type CommentInputItem = BaseActivityItem & { type: 'commentInput' + betsByCurrentUser: Bet[] + comments: Comment[] } export type DescriptionItem = BaseActivityItem & { @@ -48,12 +50,13 @@ export type BetItem = BaseActivityItem & { bet: Bet hideOutcome: boolean smallAvatar: boolean + hideComment?: boolean } export type CommentItem = BaseActivityItem & { type: 'comment' comment: Comment - bet: Bet | undefined + betsBySameUser: Bet[] hideOutcome: boolean truncate: boolean smallAvatar: boolean @@ -129,7 +132,7 @@ function groupBets( type: 'comment' as const, id: bet.id, comment, - bet, + betsBySameUser: [bet], contract, hideOutcome, truncate: abbreviated, @@ -280,7 +283,7 @@ function groupBetsAndComments( id: comment.id, contract: contract, comment, - bet: undefined, + betsBySameUser: [], truncate: abbreviated, hideOutcome: true, smallAvatar, @@ -308,6 +311,27 @@ function groupBetsAndComments( return abbrItems } +function getCommentsWithPositions( + bets: Bet[], + comments: Comment[], + contract: Contract +) { + const betsByUserId = _.groupBy(bets, (bet) => bet.userId) + + const items = comments.map((comment) => ({ + type: 'comment' as const, + id: comment.id, + contract: contract, + comment, + betsBySameUser: bets.length === 0 ? [] : betsByUserId[comment.userId] ?? [], + truncate: true, + hideOutcome: false, + smallAvatar: false, + })) + + return items +} + export function getAllContractActivityItems( contract: Contract, bets: Bet[], @@ -361,6 +385,8 @@ export function getAllContractActivityItems( type: 'commentInput', id: 'commentInput', contract, + betsByCurrentUser: [], + comments: [], }) } else { items.push( @@ -385,6 +411,8 @@ export function getAllContractActivityItems( type: 'commentInput', id: 'commentInput', contract, + betsByCurrentUser: [], + comments: [], }) } @@ -432,24 +460,13 @@ export function getRecentContractActivityItems( ) ) } else { - const onlyUsersBetsOrBetsWithComments = bets.filter((bet) => - comments.some( - (comment) => comment.betId === bet.id || bet.userId === user?.id - ) - ) items.push( - ...groupBetsAndComments( - onlyUsersBetsOrBetsWithComments, - comments, - contract, - user?.id, - { - hideOutcome: false, - abbreviated: true, - smallAvatar: false, - reversed: true, - } - ) + ...groupBetsAndComments(bets, comments, contract, user?.id, { + hideOutcome: false, + abbreviated: true, + smallAvatar: false, + reversed: true, + }) ) } @@ -471,37 +488,29 @@ export function getSpecificContractActivityItems( switch (mode) { case 'bets': items.push( - ...groupBets(bets, comments, contract, user?.id, { + ...bets.map((bet) => ({ + type: 'bet' as const, + id: bet.id, + bet, + contract, hideOutcome: false, - abbreviated: false, smallAvatar: false, - reversed: false, - }) + hideComment: true, + })) ) break case 'comments': - const onlyBetsWithComments = bets.filter((bet) => - comments.some((comment) => comment.betId === bet.id) - ) - items.push( - ...groupBetsAndComments( - onlyBetsWithComments, - comments, - contract, - user?.id, - { - hideOutcome: false, - abbreviated: false, - smallAvatar: false, - reversed: false, - } - ) - ) + items.push(...getCommentsWithPositions(bets, comments, contract)) + items.push({ type: 'commentInput', id: 'commentInput', contract, + betsByCurrentUser: user + ? bets.filter((bet) => bet.userId === user.id) + : [], + comments: comments, }) break } diff --git a/web/components/feed/feed-items.tsx b/web/components/feed/feed-items.tsx index 7518c998..584907d9 100644 --- a/web/components/feed/feed-items.tsx +++ b/web/components/feed/feed-items.tsx @@ -39,7 +39,13 @@ import BetRow from '../bet-row' import { Avatar } from '../avatar' import { Answer } from '../../../common/answer' import { ActivityItem } from './activity-items' -import { FreeResponse, FullContract } from '../../../common/contract' +import { + Binary, + CPMM, + DPM, + FreeResponse, + FullContract, +} from '../../../common/contract' import { BuyButton } from '../yes-no-selector' import { getDpmOutcomeProbability } from '../../../common/calculate-dpm' import { AnswerBetPanel } from '../answers/answer-bet-panel' @@ -50,6 +56,7 @@ import { trackClick } from '../../lib/firebase/tracking' import { firebaseLogin } from '../../lib/firebase/users' import { DAY_MS } from '../../../common/util/time' import NewContractBadge from '../new-contract-badge' +import { calculateCpmmSale } from '../../../common/calculate-cpmm' export function FeedItems(props: { contract: Contract @@ -123,21 +130,38 @@ function FeedItem(props: { item: ActivityItem }) { export function FeedComment(props: { contract: Contract comment: Comment - bet: Bet | undefined + betsBySameUser: Bet[] hideOutcome: boolean truncate: boolean smallAvatar: boolean }) { - const { contract, comment, bet, hideOutcome, truncate, smallAvatar } = props - let money: string | undefined - let outcome: string | undefined - let bought: string | undefined - if (bet) { - outcome = bet.outcome - bought = bet.amount >= 0 ? 'bought' : 'sold' - money = formatMoney(Math.abs(bet.amount)) - } + const { + contract, + comment, + betsBySameUser, + hideOutcome, + truncate, + smallAvatar, + } = props const { text, userUsername, userName, userAvatarUrl, createdTime } = comment + let outcome: string | undefined, + bought: string | undefined, + money: string | undefined + + const matchedBet = betsBySameUser.find((bet) => bet.id === comment.betId) + if (matchedBet) { + outcome = matchedBet.outcome + bought = matchedBet.amount >= 0 ? 'bought' : 'sold' + money = formatMoney(Math.abs(matchedBet.amount)) + } + + // Only calculated if they don't have a matching bet + const { userPosition, userPositionMoney, yesFloorShares, noFloorShares } = + getBettorsPosition( + contract, + comment.createdTime, + matchedBet ? [] : betsBySameUser + ) return ( <> @@ -155,18 +179,33 @@ export function FeedComment(props: { username={userUsername} name={userName} />{' '} - {bought} {money} - {!hideOutcome && ( + {!matchedBet && userPosition > 0 && ( <> - {' '} - of{' '} - + {'with ' + userPositionMoney + ' '} + <> + {' of '} + noFloorShares ? 'YES' : 'NO'} + contract={contract} + truncate="short" + /> + )} + <> + {bought} {money} + {outcome && !hideOutcome && ( + <> + {' '} + of{' '} + + + )} +

@@ -180,20 +219,12 @@ export function FeedComment(props: { ) } -function RelativeTimestamp(props: { time: number }) { - const { time } = props - return ( - - - {fromNow(time)} - - - ) -} - -export function CommentInput(props: { contract: Contract }) { - // see if we can comment input on any bet: - const { contract } = props +export function CommentInput(props: { + contract: Contract + betsByCurrentUser: Bet[] + comments: Comment[] +}) { + const { contract, betsByCurrentUser, comments } = props const user = useUser() const [comment, setComment] = useState('') @@ -206,14 +237,50 @@ export function CommentInput(props: { contract: Contract }) { setComment('') } + // Should this be oldest bet or most recent bet? + const mostRecentCommentableBet = betsByCurrentUser + .filter( + (bet) => + canCommentOnBet(bet.userId, bet.createdTime, user) && + !comments.some((comment) => comment.betId == bet.id) + ) + .sort((b1, b2) => b1.createdTime - b2.createdTime) + .pop() + + if (mostRecentCommentableBet) { + return ( + + ) + } + const { userPosition, userPositionMoney, yesFloorShares, noFloorShares } = + getBettorsPosition(contract, Date.now(), betsByCurrentUser) + return ( <> - +
+ {user && userPosition > 0 && ( + <> + {'You with ' + userPositionMoney + ' '} + <> + {' of '} + noFloorShares ? 'YES' : 'NO'} + contract={contract} + truncate="short" + /> + + + )}