diff --git a/web/components/feed/activity-feed.tsx b/web/components/feed/activity-feed.tsx deleted file mode 100644 index 3b53ee73..00000000 --- a/web/components/feed/activity-feed.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Contract } from 'web/lib/firebase/contracts' -import { Comment } from 'web/lib/firebase/comments' -import { Col } from '../layout/col' -import { Bet } from 'common/bet' -import { useUser } from 'web/hooks/use-user' -import { ContractActivity } from './contract-activity' - -export function ActivityFeed(props: { - feed: { - contract: Contract - recentBets: Bet[] - recentComments: Comment[] - }[] - mode: 'only-recent' | 'abbreviated' | 'all' - getContractPath?: (contract: Contract) => string -}) { - const { feed, mode, getContractPath } = props - const user = useUser() - - return ( - - {feed.map((item) => ( - - ))} - - ) -} diff --git a/web/components/feed/activity-items.ts b/web/components/feed/activity-items.ts index 4af7d385..ee7239e3 100644 --- a/web/components/feed/activity-items.ts +++ b/web/components/feed/activity-items.ts @@ -1,4 +1,4 @@ -import { last, findLastIndex, uniq, sortBy } from 'lodash' +import { uniq, sortBy } from 'lodash' import { Answer } from 'common/answer' import { Bet } from 'common/bet' @@ -6,14 +6,11 @@ import { getOutcomeProbability } from 'common/calculate' import { Comment } from 'common/comment' import { Contract, FreeResponseContract } from 'common/contract' import { User } from 'common/user' -import { mapCommentsByBetId } from 'web/lib/firebase/comments' export type ActivityItem = | DescriptionItem | QuestionItem | BetItem - | CommentItem - | BetGroupItem | AnswerGroupItem | CloseItem | ResolveItem @@ -49,15 +46,6 @@ export type BetItem = BaseActivityItem & { hideComment?: boolean } -export type CommentItem = BaseActivityItem & { - type: 'comment' - comment: Comment - betsBySameUser: Bet[] - probAtCreatedTime?: number - truncate?: boolean - smallAvatar?: boolean -} - export type CommentThreadItem = BaseActivityItem & { type: 'commentThread' parentComment: Comment @@ -65,12 +53,6 @@ export type CommentThreadItem = BaseActivityItem & { bets: Bet[] } -export type BetGroupItem = BaseActivityItem & { - type: 'betgroup' - bets: Bet[] - hideOutcome: boolean -} - export type AnswerGroupItem = BaseActivityItem & { type: 'answergroup' user: User | undefined | null @@ -87,172 +69,6 @@ export type ResolveItem = BaseActivityItem & { type: 'resolve' } -const DAY_IN_MS = 24 * 60 * 60 * 1000 -const ABBREVIATED_NUM_COMMENTS_OR_BETS_TO_SHOW = 3 - -// Group together bets that are: -// - Within a day of the first in the group -// (Unless the bets are older: then are grouped by 7-days.) -// - Do not have a comment -// - Were not created by this user -// Return a list of ActivityItems -function groupBets( - bets: Bet[], - comments: Comment[], - contract: Contract, - userId: string | undefined, - options: { - hideOutcome: boolean - abbreviated: boolean - smallAvatar: boolean - reversed: boolean - } -) { - const { hideOutcome, abbreviated, smallAvatar, reversed } = options - - const commentsMap = mapCommentsByBetId(comments) - const items: ActivityItem[] = [] - let group: Bet[] = [] - - // Turn the current group into an ActivityItem - function pushGroup() { - if (group.length == 1) { - items.push(toActivityItem(group[0])) - } else if (group.length > 1) { - items.push({ - type: 'betgroup', - bets: [...group], - id: group[0].id, - contract, - hideOutcome, - }) - } - group = [] - } - - function toActivityItem(bet: Bet): ActivityItem { - const comment = commentsMap[bet.id] - return comment - ? { - type: 'comment' as const, - id: bet.id, - comment, - betsBySameUser: [bet], - contract, - truncate: abbreviated, - smallAvatar, - } - : { - type: 'bet' as const, - id: bet.id, - bet, - contract, - hideOutcome, - smallAvatar, - } - } - - for (const bet of bets) { - const isCreator = userId === bet.userId - - // If first bet in group is older than 3 days, group by 7 days. Otherwise, group by 1 day. - const windowMs = - Date.now() - (group[0]?.createdTime ?? bet.createdTime) > DAY_IN_MS * 3 - ? DAY_IN_MS * 7 - : DAY_IN_MS - - if (commentsMap[bet.id] || isCreator) { - pushGroup() - // Create a single item for this - items.push(toActivityItem(bet)) - } else { - if ( - group.length > 0 && - bet.createdTime - group[0].createdTime > windowMs - ) { - // More than `windowMs` has passed; start a new group - pushGroup() - } - group.push(bet) - } - } - if (group.length > 0) { - pushGroup() - } - const abbrItems = abbreviated - ? items.slice(-ABBREVIATED_NUM_COMMENTS_OR_BETS_TO_SHOW) - : items - if (reversed) abbrItems.reverse() - return abbrItems -} - -function getAnswerGroups( - contract: FreeResponseContract, - bets: Bet[], - comments: Comment[], - user: User | undefined | null, - options: { - sortByProb: boolean - abbreviated: boolean - reversed: boolean - } -) { - const { sortByProb, abbreviated, reversed } = options - - let outcomes = uniq(bets.map((bet) => bet.outcome)) - 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) => - getOutcomeProbability(contract, outcome) - ) - } else { - // Sort by recent bet. - outcomes = sortBy(outcomes, (outcome) => - findLastIndex(bets, (bet) => bet.outcome === outcome) - ) - } - - const answerGroups = outcomes - .map((outcome) => { - const answer = contract.answers?.find( - (answer) => answer.id === outcome - ) as Answer - - // TODO: this doesn't abbreviate these groups for activity feed anymore - return { - id: outcome, - type: 'answergroup' as const, - contract, - user, - answer, - comments, - bets, - } - }) - .filter((group) => group.answer) - - if (reversed) answerGroups.reverse() - - return answerGroups -} - function getAnswerAndCommentInputGroups( contract: FreeResponseContract, bets: Bet[], @@ -284,54 +100,6 @@ function getAnswerAndCommentInputGroups( return answerGroups } -function groupBetsAndComments( - bets: Bet[], - comments: Comment[], - contract: Contract, - userId: string | undefined, - options: { - hideOutcome: boolean - abbreviated: boolean - smallAvatar: boolean - reversed: boolean - } -) { - const { smallAvatar, abbreviated, reversed } = options - // Comments in feed don't show user's position? - const commentsWithoutBets = comments - .filter((comment) => !comment.betId) - .map((comment) => ({ - type: 'comment' as const, - id: comment.id, - contract: contract, - comment, - betsBySameUser: [], - truncate: abbreviated, - smallAvatar, - })) - - const groupedBets = groupBets(bets, comments, contract, userId, options) - - // iterate through the bets and comment activity items and add them to the items in order of comment creation time: - const unorderedBetsAndComments = [...commentsWithoutBets, ...groupedBets] - const sortedBetsAndComments = sortBy(unorderedBetsAndComments, (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 - } - }) - - const abbrItems = abbreviated - ? sortedBetsAndComments.slice(-ABBREVIATED_NUM_COMMENTS_OR_BETS_TO_SHOW) - : sortedBetsAndComments - - if (reversed) abbrItems.reverse() - return abbrItems -} - function getCommentThreads( bets: Bet[], comments: Comment[], @@ -351,122 +119,6 @@ function getCommentThreads( return items } -export function getAllContractActivityItems( - contract: Contract, - bets: Bet[], - comments: Comment[], - user: User | null | undefined, - options: { - abbreviated: boolean - } -) { - const { abbreviated } = options - const { outcomeType } = contract - const reversed = true - - bets = - outcomeType === 'BINARY' - ? bets.filter((bet) => !bet.isAnte && !bet.isRedemption) - : bets.filter((bet) => !(bet.isAnte && (bet.outcome as string) === '0')) - - const items: ActivityItem[] = abbreviated - ? [ - { - type: 'question', - id: '0', - contract, - showDescription: false, - }, - ] - : [{ type: 'description', id: '0', contract }] - - if (outcomeType === 'FREE_RESPONSE') { - 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, - smallAvatar: false, - reversed, - } - ) - ) - } else { - items.push( - ...groupBetsAndComments(bets, comments, contract, user?.id, { - hideOutcome: false, - abbreviated, - smallAvatar: false, - reversed, - }) - ) - } - - if (contract.closeTime && contract.closeTime <= Date.now()) { - items.push({ type: 'close', id: `${contract.closeTime}`, contract }) - } - if (contract.resolution) { - items.push({ type: 'resolve', id: `${contract.resolutionTime}`, contract }) - } - - if (reversed) items.reverse() - - return items -} - -export function getRecentContractActivityItems( - contract: Contract, - bets: Bet[], - comments: Comment[], - user: User | null | undefined, - options: { - contractPath?: string - } -) { - const { contractPath } = options - bets = bets.sort((b1, b2) => b1.createdTime - b2.createdTime) - comments = comments.sort((c1, c2) => c1.createdTime - c2.createdTime) - - const questionItem: QuestionItem = { - type: 'question', - id: '0', - contract, - showDescription: false, - contractPath, - } - - const items = [] - if (contract.outcomeType === 'FREE_RESPONSE') { - items.push( - ...getAnswerGroups(contract, bets, comments, user, { - sortByProb: false, - abbreviated: true, - reversed: true, - }) - ) - } else { - items.push( - ...groupBetsAndComments(bets, comments, contract, user?.id, { - hideOutcome: false, - abbreviated: true, - smallAvatar: false, - reversed: true, - }) - ) - } - - return [questionItem, ...items] -} - function commentIsGeneralComment(comment: Comment, contract: Contract) { return ( comment.answerOutcome === undefined && diff --git a/web/components/feed/contract-activity.tsx b/web/components/feed/contract-activity.tsx index 95bc4bfe..8c436333 100644 --- a/web/components/feed/contract-activity.tsx +++ b/web/components/feed/contract-activity.tsx @@ -3,11 +3,7 @@ import { Comment } from 'web/lib/firebase/comments' import { Bet } from 'common/bet' import { useBets } from 'web/hooks/use-bets' import { useComments } from 'web/hooks/use-comments' -import { - getAllContractActivityItems, - getRecentContractActivityItems, - getSpecificContractActivityItems, -} from './activity-items' +import { getSpecificContractActivityItems } from './activity-items' import { FeedItems } from './feed-items' import { User } from 'common/user' import { useContractWithPreload } from 'web/hooks/use-contract' @@ -17,45 +13,27 @@ export function ContractActivity(props: { bets: Bet[] comments: Comment[] user: User | null | undefined - mode: - | 'only-recent' - | 'abbreviated' - | 'all' - | 'comments' - | 'bets' - | 'free-response-comment-answer-groups' + mode: 'comments' | 'bets' | 'free-response-comment-answer-groups' contractPath?: string className?: string betRowClassName?: string }) { - const { user, mode, contractPath, className, betRowClassName } = props + const { user, mode, className, betRowClassName } = props const contract = useContractWithPreload(props.contract) ?? props.contract - const updatedComments = - // eslint-disable-next-line react-hooks/rules-of-hooks - mode === 'only-recent' ? undefined : useComments(contract.id) + const updatedComments = useComments(contract.id) const comments = updatedComments ?? props.comments - const updatedBets = - // eslint-disable-next-line react-hooks/rules-of-hooks - mode === 'only-recent' ? undefined : useBets(contract.id) + const updatedBets = useBets(contract.id) const bets = (updatedBets ?? props.bets).filter((bet) => !bet.isRedemption) - const items = - mode === 'only-recent' - ? getRecentContractActivityItems(contract, bets, comments, user, { - contractPath, - }) - : mode === 'comments' || - mode === 'bets' || - mode === 'free-response-comment-answer-groups' - ? getSpecificContractActivityItems(contract, bets, comments, user, { - mode, - }) - : // only used in abbreviated mode with folds/communities, all mode isn't used - getAllContractActivityItems(contract, bets, comments, user, { - abbreviated: mode === 'abbreviated', - }) + const items = getSpecificContractActivityItems( + contract, + bets, + comments, + user, + { mode } + ) return ( case 'description': return - case 'comment': - return case 'bet': return - case 'betgroup': - return case 'answergroup': return case 'close': diff --git a/web/pages/activity.tsx b/web/pages/activity.tsx deleted file mode 100644 index 5d1a0a18..00000000 --- a/web/pages/activity.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useEffect, useState } from 'react' -import Router, { useRouter } from 'next/router' -import { Page } from 'web/components/page' -import { ActivityFeed } from 'web/components/feed/activity-feed' -import { Spacer } from 'web/components/layout/spacer' -import { Col } from 'web/components/layout/col' -import { useUser } from 'web/hooks/use-user' -import { LoadingIndicator } from 'web/components/loading-indicator' -import { useAlgoFeed } from 'web/hooks/use-algo-feed' -import { ContractPageContent } from './[username]/[contractSlug]' -import { CategorySelector } from '../components/feed/category-selector' - -export default function Activity() { - const user = useUser() - const [category, setCategory] = useState('all') - - const feed = useAlgoFeed(user, category) - - const router = useRouter() - const { u: username, s: slug } = router.query - const contract = feed?.find( - ({ contract }) => contract.slug === slug - )?.contract - - useEffect(() => { - // If the page initially loads with query params, redirect to the contract page. - if (router.isReady && slug && username) { - Router.replace(`/${username}/${slug}`) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [router.isReady]) - - if (user === null) { - Router.replace('/') - return <> - } - - return ( - <> - - - - - {feed ? ( - - `activity?u=${c.creatorUsername}&s=${c.slug}` - } - /> - ) : ( - - )} - - - - {contract && ( - - )} - - ) -}