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 { 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<Contract[] | undefined>()
const [sort, setSort] = useState<BetSort>('newest')
const [filter, setFilter] = useState<BetFilter>('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 <LoadingIndicator />
}
if (bets.length === 0) return <NoBets user={user} />
// 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]

View File

@ -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<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 (
<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 className={'mb-2 text-sm text-indigo-700'}>
<SiteLink href={contractPath(contract)}>

View File

@ -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<Comment[]>([] as Comment[])
const [usersComments, setUsersComments] = useState<Comment[] | undefined>()
const [usersContracts, setUsersContracts] = useState<Contract[] | 'loading'>(
'loading'
)
@ -85,9 +86,9 @@ export function UserPage(props: {
const [portfolioHistory, setUsersPortfolioHistory] = useState<
PortfolioMetrics[]
>([])
const [commentsByContract, setCommentsByContract] = useState<
Map<Contract, Comment[]> | 'loading'
>('loading')
const [contractsById, setContractsById] = useState<
Dictionary<Contract> | 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<Contract, Comment[]>()
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: {
<Spacer h={10} />
{usersContracts !== 'loading' && commentsByContract != 'loading' ? (
{usersContracts !== 'loading' && contractsById && usersComments ? (
<Tabs
currentPageForAnalytics={'profile'}
labelClassName={'pb-2 pt-1 '}
@ -296,7 +293,8 @@ export function UserPage(props: {
content: (
<UserCommentsList
user={user}
commentsByUniqueContracts={commentsByContract}
contractsById={contractsById}
comments={usersComments}
/>
),
tabIcon: (
@ -314,6 +312,7 @@ export function UserPage(props: {
user={user}
bets={userBets}
hideBetsBefore={isCurrentUser ? 0 : JUNE_1_2022}
contractsById={contractsById}
/>
</div>
),