Load contracts at UserPage top level instead of in BetsList

This commit is contained in:
James Grugett 2022-07-10 19:19:35 -05:00
parent f294189e20
commit 5e1ed17cdf
3 changed files with 47 additions and 54 deletions

View File

@ -1,5 +1,5 @@
import Link from 'next/link' 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 dayjs from 'dayjs'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import clsx from 'clsx' import clsx from 'clsx'
@ -16,7 +16,6 @@ import { Col } from './layout/col'
import { Spacer } from './layout/spacer' import { Spacer } from './layout/spacer'
import { import {
Contract, Contract,
getContractFromId,
contractPath, contractPath,
getBinaryProbPercent, getBinaryProbPercent,
} from 'web/lib/firebase/contracts' } from 'web/lib/firebase/contracts'
@ -25,7 +24,6 @@ import { UserLink } from './user-page'
import { sellBet } from 'web/lib/firebase/api' import { sellBet } from 'web/lib/firebase/api'
import { ConfirmationButton } from './confirmation-button' import { ConfirmationButton } from './confirmation-button'
import { OutcomeLabel, YesLabel, NoLabel } from './outcome-label' import { OutcomeLabel, YesLabel, NoLabel } from './outcome-label'
import { filterDefined } from 'common/util/array'
import { LoadingIndicator } from './loading-indicator' import { LoadingIndicator } from './loading-indicator'
import { SiteLink } from './site-link' import { SiteLink } from './site-link'
import { import {
@ -56,9 +54,10 @@ const CONTRACTS_PER_PAGE = 20
export function BetsList(props: { export function BetsList(props: {
user: User user: User
bets: Bet[] | undefined bets: Bet[] | undefined
contractsById: { [id: string]: Contract } | undefined
hideBetsBefore?: number hideBetsBefore?: number
}) { }) {
const { user, bets: allBets, hideBetsBefore } = props const { user, bets: allBets, contractsById, hideBetsBefore } = props
const signedInUser = useUser() const signedInUser = useUser()
const isYourBets = user.id === signedInUser?.id const isYourBets = user.id === signedInUser?.id
@ -69,7 +68,6 @@ export function BetsList(props: {
() => allBets?.filter((bet) => bet.createdTime >= (hideBetsBefore ?? 0)), () => allBets?.filter((bet) => bet.createdTime >= (hideBetsBefore ?? 0)),
[allBets, hideBetsBefore] [allBets, hideBetsBefore]
) )
const [contracts, setContracts] = useState<Contract[] | undefined>()
const [sort, setSort] = useState<BetSort>('newest') const [sort, setSort] = useState<BetSort>('newest')
const [filter, setFilter] = useState<BetFilter>('open') const [filter, setFilter] = useState<BetFilter>('open')
@ -77,39 +75,26 @@ export function BetsList(props: {
const start = page * CONTRACTS_PER_PAGE const start = page * CONTRACTS_PER_PAGE
const end = start + 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() const getTime = useTimeSinceFirstRender()
useEffect(() => { useEffect(() => {
if (bets && contracts) { if (bets && contractsById) {
trackLatency('portfolio', getTime()) trackLatency('portfolio', getTime())
} }
}, [bets, contracts, getTime]) }, [bets, contractsById, getTime])
if (!bets || !contracts) { if (!bets || !contractsById) {
return <LoadingIndicator /> return <LoadingIndicator />
} }
if (bets.length === 0) return <NoBets user={user} /> if (bets.length === 0) return <NoBets user={user} />
// Decending creation time. // Decending creation time.
bets.sort((bet1, bet2) => bet2.createdTime - bet1.createdTime) bets.sort((bet1, bet2) => bet2.createdTime - bet1.createdTime)
const contractBets = groupBy(bets, 'contractId') 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 contractsMetrics = mapValues(contractBets, (bets, contractId) => {
const contract = contractsById[contractId] const contract = contractsById[contractId]

View File

@ -9,16 +9,25 @@ import { UserLink } from './user-page'
import { User } from 'common/user' import { User } from 'common/user'
import { Col } from './layout/col' import { Col } from './layout/col'
import { Linkify } from './linkify' import { Linkify } from './linkify'
import { groupBy } from 'lodash'
export function UserCommentsList(props: { export function UserCommentsList(props: {
user: User user: User
commentsByUniqueContracts: Map<Contract, Comment[]> 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 ( return (
<Col className={'bg-white'}> <Col className={'bg-white'}>
{Array.from(commentsByUniqueContracts).map(([contract, comments]) => ( {contractCommentPairs.map(([contract, comments]) => (
<div key={contract.id} className={'border-width-1 border-b p-5'}> <div key={contract.id} className={'border-width-1 border-b p-5'}>
<div className={'mb-2 text-sm text-indigo-700'}> <div className={'mb-2 text-sm text-indigo-700'}>
<SiteLink href={contractPath(contract)}> <SiteLink href={contractPath(contract)}>

View File

@ -1,5 +1,5 @@
import clsx from 'clsx' import clsx from 'clsx'
import { uniq } from 'lodash' import { Dictionary, keyBy, uniq } from 'lodash'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { LinkIcon } from '@heroicons/react/solid' import { LinkIcon } from '@heroicons/react/solid'
@ -39,6 +39,7 @@ import { PortfolioMetrics } from 'common/user'
import { ReferralsButton } from 'web/components/referrals-button' import { ReferralsButton } from 'web/components/referrals-button'
import { GroupsButton } from 'web/components/groups/groups-button' import { GroupsButton } from 'web/components/groups/groups-button'
import { PortfolioValueSection } from './portfolio/portfolio-value-section' import { PortfolioValueSection } from './portfolio/portfolio-value-section'
import { filterDefined } from 'common/util/array'
export function UserLink(props: { export function UserLink(props: {
name: string name: string
@ -72,7 +73,7 @@ export function UserPage(props: {
const router = useRouter() const router = useRouter()
const isCurrentUser = user.id === currentUser?.id const isCurrentUser = user.id === currentUser?.id
const bannerUrl = user.bannerUrl ?? defaultBannerUrl(user.id) const bannerUrl = user.bannerUrl ?? defaultBannerUrl(user.id)
const [usersComments, setUsersComments] = useState<Comment[]>([] as Comment[]) const [usersComments, setUsersComments] = useState<Comment[] | undefined>()
const [usersContracts, setUsersContracts] = useState<Contract[] | 'loading'>( const [usersContracts, setUsersContracts] = useState<Contract[] | 'loading'>(
'loading' 'loading'
) )
@ -85,9 +86,9 @@ export function UserPage(props: {
const [portfolioHistory, setUsersPortfolioHistory] = useState< const [portfolioHistory, setUsersPortfolioHistory] = useState<
PortfolioMetrics[] PortfolioMetrics[]
>([]) >([])
const [commentsByContract, setCommentsByContract] = useState< const [contractsById, setContractsById] = useState<
Map<Contract, Comment[]> | 'loading' Dictionary<Contract> | undefined
>('loading') >()
const [showConfetti, setShowConfetti] = useState(false) const [showConfetti, setShowConfetti] = useState(false)
const { width, height } = useWindowSize() const { width, height } = useWindowSize()
@ -106,25 +107,21 @@ export function UserPage(props: {
// TODO: display comments on groups // TODO: display comments on groups
useEffect(() => { useEffect(() => {
const uniqueContractIds = uniq( if (usersComments && userBets) {
usersComments.map((comment) => comment.contractId) const uniqueContractIds = uniq([
) ...usersComments.map((comment) => comment.contractId),
...(userBets?.map((bet) => bet.contractId) ?? []),
])
Promise.all( Promise.all(
uniqueContractIds.map( uniqueContractIds.map((contractId) =>
(contractId) => contractId && getContractFromId(contractId) contractId ? getContractFromId(contractId) : undefined
) )
).then((contracts) => { ).then((contracts) => {
const commentsByContract = new Map<Contract, Comment[]>() const contractsById = keyBy(filterDefined(contracts), 'id')
contracts.forEach((contract) => { setContractsById(contractsById)
if (!contract) return
commentsByContract.set(
contract,
usersComments.filter((comment) => comment.contractId === contract.id)
)
}) })
setCommentsByContract(commentsByContract) }
}) }, [userBets, usersComments])
}, [usersComments])
const yourFollows = useFollows(currentUser?.id) const yourFollows = useFollows(currentUser?.id)
const isFollowing = yourFollows?.includes(user.id) const isFollowing = yourFollows?.includes(user.id)
@ -265,7 +262,7 @@ export function UserPage(props: {
<Spacer h={10} /> <Spacer h={10} />
{usersContracts !== 'loading' && commentsByContract != 'loading' ? ( {usersContracts !== 'loading' && contractsById && usersComments ? (
<Tabs <Tabs
currentPageForAnalytics={'profile'} currentPageForAnalytics={'profile'}
labelClassName={'pb-2 pt-1 '} labelClassName={'pb-2 pt-1 '}
@ -296,7 +293,8 @@ export function UserPage(props: {
content: ( content: (
<UserCommentsList <UserCommentsList
user={user} user={user}
commentsByUniqueContracts={commentsByContract} contractsById={contractsById}
comments={usersComments}
/> />
), ),
tabIcon: ( tabIcon: (
@ -314,6 +312,7 @@ export function UserPage(props: {
user={user} user={user}
bets={userBets} bets={userBets}
hideBetsBefore={isCurrentUser ? 0 : JUNE_1_2022} hideBetsBefore={isCurrentUser ? 0 : JUNE_1_2022}
contractsById={contractsById}
/> />
</div> </div>
), ),