From 8291a05f32c2bdc3f34aa370d65bc6abfca99f61 Mon Sep 17 00:00:00 2001 From: Ian Philips Date: Thu, 21 Apr 2022 08:20:58 -0600 Subject: [PATCH] Allow free comments with optional bets --- common/comment.ts | 2 +- functions/.gitignore | 3 +- web/components/feed/activity-items.ts | 82 ++++++++++++++++------ web/components/feed/feed-items.tsx | 91 +++++++++++++++++++++++-- web/lib/firebase/comments.ts | 49 ++++++++----- web/pages/[username]/[contractSlug].tsx | 5 +- 6 files changed, 185 insertions(+), 47 deletions(-) diff --git a/common/comment.ts b/common/comment.ts index cf78da4b..5daeb37e 100644 --- a/common/comment.ts +++ b/common/comment.ts @@ -3,7 +3,7 @@ export type Comment = { id: string contractId: string - betId: string + betId?: string userId: string text: string diff --git a/functions/.gitignore b/functions/.gitignore index 8b54e3dc..f6db6f5f 100644 --- a/functions/.gitignore +++ b/functions/.gitignore @@ -1,5 +1,6 @@ # Secrets .env* +.runtimeconfig.json # Compiled JavaScript files lib/**/*.js @@ -13,4 +14,4 @@ node_modules/ package-lock.json ui-debug.log -firebase-debug.log \ No newline at end of file +firebase-debug.log diff --git a/web/components/feed/activity-items.ts b/web/components/feed/activity-items.ts index fb5effd6..9d2f50d3 100644 --- a/web/components/feed/activity-items.ts +++ b/web/components/feed/activity-items.ts @@ -12,6 +12,7 @@ import { } from '../../../common/contract' import { User } from '../../../common/user' import { mapCommentsByBetId } from '../../lib/firebase/comments' +import { useUser } from '../../hooks/use-user' export type ActivityItem = | DescriptionItem @@ -22,12 +23,19 @@ export type ActivityItem = | AnswerGroupItem | CloseItem | ResolveItem + | CommentInputItem type BaseActivityItem = { id: string contract: Contract } +export type CommentInputItem = BaseActivityItem & { + type: 'commentInput' + bets: Bet[] + comments: Comment[] +} + export type DescriptionItem = BaseActivityItem & { type: 'description' } @@ -48,7 +56,7 @@ export type BetItem = BaseActivityItem & { export type CommentItem = BaseActivityItem & { type: 'comment' comment: Comment - bet: Bet + bet: Bet | undefined hideOutcome: boolean truncate: boolean smallAvatar: boolean @@ -279,26 +287,53 @@ export function getAllContractActivityItems( ] : [{ type: 'description', id: '0', contract }] - items.push( - ...(outcomeType === 'FREE_RESPONSE' - ? getAnswerGroups( - contract as FullContract, - bets, - comments, - user, - { - sortByProb: true, - abbreviated, - reversed, - } - ) - : groupBets(bets, comments, contract, user?.id, { - hideOutcome: false, + // for each comment. turn it into an activity item and add it to the items: + const commentWithoutBetActivityItems = comments + .filter((comment) => !comment.betId) + .map((comment) => ({ + type: 'comment' as const, + id: comment.id, + contract: contract, + comment, + bet: undefined, + truncate: false, + hideOutcome: true, + smallAvatar: false, + })) + const groupedBets = groupBets(bets, comments, contract, user?.id, { + hideOutcome: false, + abbreviated, + smallAvatar: false, + reversed: false, + }) + // iterate through the bets and comment acitivity items and add them to the items in order of comment creation time: + const allActivityItems = [...commentWithoutBetActivityItems, ...groupedBets] + const sortedActivityItems = _.sortBy(allActivityItems, (item) => { + if (item.type === 'comment') { + return item.comment.createdTime + } else if (item.type === 'bet') { + return item.bet.createdTime + } else if (item.type === 'betgroup') { + return item.bets[0].createdTime + } + }) + items.push(...sortedActivityItems) + + if (outcomeType === 'FREE_RESPONSE') { + items.push( + ...getAnswerGroups( + contract as FullContract, + bets, + comments, + user, + { + sortByProb: true, abbreviated, - smallAvatar: false, - reversed: false, - })) - ) + reversed, + } + ) + ) + } if (contract.closeTime && contract.closeTime <= Date.now()) { items.push({ type: 'close', id: `${contract.closeTime}`, contract }) @@ -306,6 +341,13 @@ export function getAllContractActivityItems( if (contract.resolution) { items.push({ type: 'resolve', id: `${contract.resolutionTime}`, contract }) } + items.push({ + type: 'commentInput', + id: 'commentInput', + bets, + comments, + contract, + }) if (reversed) items.reverse() diff --git a/web/components/feed/feed-items.tsx b/web/components/feed/feed-items.tsx index e2def4d4..5d858021 100644 --- a/web/components/feed/feed-items.tsx +++ b/web/components/feed/feed-items.tsx @@ -104,24 +104,30 @@ function FeedItem(props: { item: ActivityItem }) { return case 'resolve': return + case 'commentInput': + return } } export function FeedComment(props: { contract: Contract comment: Comment - bet: Bet + bet: Bet | undefined hideOutcome: boolean truncate: boolean smallAvatar: boolean }) { const { contract, comment, bet, hideOutcome, truncate, smallAvatar } = props - const { amount, outcome } = bet + 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 { text, userUsername, userName, userAvatarUrl, createdTime } = comment - const bought = amount >= 0 ? 'bought' : 'sold' - const money = formatMoney(Math.abs(amount)) - return ( <> @@ -174,6 +180,77 @@ function RelativeTimestamp(props: { time: number }) { ) } +export function CommentInput(props: { + contract: Contract + comments: Comment[] + bets: Bet[] +}) { + // see if we can comment input on any bet: + const { contract, bets, comments } = props + const user = useUser() + let canCommentOnBet = false + bets.forEach((bet) => { + // make sure there is not already a comment with a mathcing bet id: + const matchingComment = comments.find((comment) => comment.betId === bet.id) + if (matchingComment) { + return + } + const { createdTime, userId } = bet + const isSelf = user?.id === userId + // You can comment if your bet was posted in the last hour + const canComment = isSelf && Date.now() - createdTime < 60 * 60 * 1000 + if (canComment) { + // if you can comment on this bet, then you can comment on the contract + canCommentOnBet = true + } + }) + + const [comment, setComment] = useState('') + + async function submitComment() { + if (!user || !comment) return + await createComment(contract.id, comment, user) + setComment('') + } + + if (canCommentOnBet) return
+ + return ( + <> +
+ +
+
+
+ {/*{isSelf ? 'You' : bettor ? bettor.name : 'A trader'}{' '}*/} + +
+