From 5e1ed17cdfaf8397183621468b32922fe5287f3a Mon Sep 17 00:00:00 2001 From: James Grugett Date: Sun, 10 Jul 2022 19:19:35 -0500 Subject: [PATCH] Load contracts at UserPage top level instead of in BetsList --- web/components/bets-list.tsx | 39 ++++++++------------------ web/components/comments-list.tsx | 15 ++++++++-- web/components/user-page.tsx | 47 ++++++++++++++++---------------- 3 files changed, 47 insertions(+), 54 deletions(-) diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx index 6d19c1e4..17ba9fa3 100644 --- a/web/components/bets-list.tsx +++ b/web/components/bets-list.tsx @@ -1,5 +1,5 @@ import Link from 'next/link' -import { uniq, groupBy, mapValues, sortBy, partition, sumBy } from 'lodash' +import { groupBy, mapValues, sortBy, partition, sumBy } from 'lodash' import dayjs from 'dayjs' import { useEffect, useMemo, useState } from 'react' import clsx from 'clsx' @@ -16,7 +16,6 @@ import { Col } from './layout/col' import { Spacer } from './layout/spacer' import { Contract, - getContractFromId, contractPath, getBinaryProbPercent, } from 'web/lib/firebase/contracts' @@ -25,7 +24,6 @@ import { UserLink } from './user-page' import { sellBet } from 'web/lib/firebase/api' import { ConfirmationButton } from './confirmation-button' import { OutcomeLabel, YesLabel, NoLabel } from './outcome-label' -import { filterDefined } from 'common/util/array' import { LoadingIndicator } from './loading-indicator' import { SiteLink } from './site-link' import { @@ -56,9 +54,10 @@ const CONTRACTS_PER_PAGE = 20 export function BetsList(props: { user: User bets: Bet[] | undefined + contractsById: { [id: string]: Contract } | undefined hideBetsBefore?: number }) { - const { user, bets: allBets, hideBetsBefore } = props + const { user, bets: allBets, contractsById, hideBetsBefore } = props const signedInUser = useUser() const isYourBets = user.id === signedInUser?.id @@ -69,7 +68,6 @@ export function BetsList(props: { () => allBets?.filter((bet) => bet.createdTime >= (hideBetsBefore ?? 0)), [allBets, hideBetsBefore] ) - const [contracts, setContracts] = useState() const [sort, setSort] = useState('newest') const [filter, setFilter] = useState('open') @@ -77,39 +75,26 @@ export function BetsList(props: { const start = page * CONTRACTS_PER_PAGE const end = start + CONTRACTS_PER_PAGE - useEffect(() => { - if (bets) { - const contractIds = uniq(bets.map((bet) => bet.contractId)) - - let disposed = false - Promise.all(contractIds.map((id) => getContractFromId(id))).then( - (contracts) => { - if (!disposed) setContracts(filterDefined(contracts)) - } - ) - - return () => { - disposed = true - } - } - }, [bets]) - const getTime = useTimeSinceFirstRender() useEffect(() => { - if (bets && contracts) { + if (bets && contractsById) { trackLatency('portfolio', getTime()) } - }, [bets, contracts, getTime]) + }, [bets, contractsById, getTime]) - if (!bets || !contracts) { + if (!bets || !contractsById) { return } - if (bets.length === 0) return + // Decending creation time. bets.sort((bet1, bet2) => bet2.createdTime - bet1.createdTime) const contractBets = groupBy(bets, 'contractId') - const contractsById = Object.fromEntries(contracts.map((c) => [c.id, c])) + + // Keep only contracts that have bets. + const contracts = Object.values(contractsById).filter( + (c) => contractBets[c.id] + ) const contractsMetrics = mapValues(contractBets, (bets, contractId) => { const contract = contractsById[contractId] diff --git a/web/components/comments-list.tsx b/web/components/comments-list.tsx index bceb2d59..ab9ed523 100644 --- a/web/components/comments-list.tsx +++ b/web/components/comments-list.tsx @@ -9,16 +9,25 @@ import { UserLink } from './user-page' import { User } from 'common/user' import { Col } from './layout/col' import { Linkify } from './linkify' +import { groupBy } from 'lodash' export function UserCommentsList(props: { user: User - commentsByUniqueContracts: Map + comments: Comment[] + contractsById: { [id: string]: Contract } }) { - const { commentsByUniqueContracts } = props + const { comments, contractsById } = props + const commentsByContract = groupBy(comments, 'contractId') + + const contractCommentPairs = Object.entries(commentsByContract) + .map( + ([contractId, comments]) => [contractsById[contractId], comments] as const + ) + .filter(([contract]) => contract) return ( - {Array.from(commentsByUniqueContracts).map(([contract, comments]) => ( + {contractCommentPairs.map(([contract, comments]) => (
diff --git a/web/components/user-page.tsx b/web/components/user-page.tsx index 64eab05c..3e455b03 100644 --- a/web/components/user-page.tsx +++ b/web/components/user-page.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx' -import { uniq } from 'lodash' +import { Dictionary, keyBy, uniq } from 'lodash' import { useEffect, useState } from 'react' import { useRouter } from 'next/router' import { LinkIcon } from '@heroicons/react/solid' @@ -39,6 +39,7 @@ import { PortfolioMetrics } from 'common/user' import { ReferralsButton } from 'web/components/referrals-button' import { GroupsButton } from 'web/components/groups/groups-button' import { PortfolioValueSection } from './portfolio/portfolio-value-section' +import { filterDefined } from 'common/util/array' export function UserLink(props: { name: string @@ -72,7 +73,7 @@ export function UserPage(props: { const router = useRouter() const isCurrentUser = user.id === currentUser?.id const bannerUrl = user.bannerUrl ?? defaultBannerUrl(user.id) - const [usersComments, setUsersComments] = useState([] as Comment[]) + const [usersComments, setUsersComments] = useState() const [usersContracts, setUsersContracts] = useState( 'loading' ) @@ -85,9 +86,9 @@ export function UserPage(props: { const [portfolioHistory, setUsersPortfolioHistory] = useState< PortfolioMetrics[] >([]) - const [commentsByContract, setCommentsByContract] = useState< - Map | 'loading' - >('loading') + const [contractsById, setContractsById] = useState< + Dictionary | undefined + >() const [showConfetti, setShowConfetti] = useState(false) const { width, height } = useWindowSize() @@ -106,25 +107,21 @@ export function UserPage(props: { // TODO: display comments on groups useEffect(() => { - const uniqueContractIds = uniq( - usersComments.map((comment) => comment.contractId) - ) - Promise.all( - uniqueContractIds.map( - (contractId) => contractId && getContractFromId(contractId) - ) - ).then((contracts) => { - const commentsByContract = new Map() - contracts.forEach((contract) => { - if (!contract) return - commentsByContract.set( - contract, - usersComments.filter((comment) => comment.contractId === contract.id) + if (usersComments && userBets) { + const uniqueContractIds = uniq([ + ...usersComments.map((comment) => comment.contractId), + ...(userBets?.map((bet) => bet.contractId) ?? []), + ]) + Promise.all( + uniqueContractIds.map((contractId) => + contractId ? getContractFromId(contractId) : undefined ) + ).then((contracts) => { + const contractsById = keyBy(filterDefined(contracts), 'id') + setContractsById(contractsById) }) - setCommentsByContract(commentsByContract) - }) - }, [usersComments]) + } + }, [userBets, usersComments]) const yourFollows = useFollows(currentUser?.id) const isFollowing = yourFollows?.includes(user.id) @@ -265,7 +262,7 @@ export function UserPage(props: { - {usersContracts !== 'loading' && commentsByContract != 'loading' ? ( + {usersContracts !== 'loading' && contractsById && usersComments ? ( ), tabIcon: ( @@ -314,6 +312,7 @@ export function UserPage(props: { user={user} bets={userBets} hideBetsBefore={isCurrentUser ? 0 : JUNE_1_2022} + contractsById={contractsById} />
),