Cleaner home page loading!

This commit is contained in:
James Grugett 2022-09-30 20:07:49 -05:00
parent dc0b6dc6a6
commit b0b1d72ba6
3 changed files with 112 additions and 58 deletions

View File

@ -8,12 +8,14 @@ import {
getUserBetContracts,
getUserBetContractsQuery,
listAllContracts,
trendingContractsQuery,
} from 'web/lib/firebase/contracts'
import { QueryClient, useQuery, useQueryClient } from 'react-query'
import { MINUTE_MS, sleep } from 'common/util/time'
import { query, limit } from 'firebase/firestore'
import { dailyScoreIndex } from 'web/lib/service/algolia'
import {
dailyScoreIndex,
newIndex,
trendingIndex,
} from 'web/lib/service/algolia'
import { CPMMBinaryContract } from 'common/contract'
import { zipObject } from 'lodash'
@ -27,16 +29,50 @@ export const useContracts = () => {
return contracts
}
export const useTrendingContracts = (maxContracts: number) => {
const { data } = useQuery(['trending-contracts', maxContracts], () =>
trendingIndex.search<CPMMBinaryContract>('', {
facetFilters: ['isResolved:false'],
hitsPerPage: maxContracts,
})
)
if (!data) return undefined
return data.hits
}
export const useNewContracts = (maxContracts: number) => {
const { data } = useQuery(['newest-contracts', maxContracts], () =>
newIndex.search<CPMMBinaryContract>('', {
facetFilters: ['isResolved:false'],
hitsPerPage: maxContracts,
})
)
if (!data) return undefined
return data.hits
}
export const useContractsByDailyScoreNotBetOn = (
userId: string | null | undefined,
maxContracts: number
) => {
const { data } = useQuery(['daily-score', userId, maxContracts], () =>
dailyScoreIndex.search<CPMMBinaryContract>('', {
facetFilters: ['isResolved:false', `uniqueBettors:-${userId}`],
hitsPerPage: maxContracts,
})
)
if (!userId || !data) return undefined
return data.hits.filter((c) => c.dailyScore)
}
export const useContractsByDailyScoreGroups = (
groupSlugs: string[] | undefined
) => {
const facetFilters = ['isResolved:false']
const { data } = useQuery(['daily-score', groupSlugs], () =>
Promise.all(
(groupSlugs ?? []).map((slug) =>
dailyScoreIndex.search<CPMMBinaryContract>('', {
facetFilters: [...facetFilters, `groupLinks.slug:${slug}`],
facetFilters: ['isResolved:false', `groupLinks.slug:${slug}`],
})
)
)
@ -56,14 +92,6 @@ export const getCachedContracts = async () =>
staleTime: Infinity,
})
export const useTrendingContracts = (maxContracts: number) => {
const result = useFirestoreQueryData(
['trending-contracts', maxContracts],
query(trendingContractsQuery, limit(maxContracts))
)
return result.data
}
export const useInactiveContracts = () => {
const [contracts, setContracts] = useState<Contract[] | undefined>()

View File

@ -14,6 +14,8 @@ export const getIndexName = (sort: string) => {
return `${indexPrefix}contracts-${sort}`
}
export const trendingIndex = searchClient.initIndex(getIndexName('score'))
export const newIndex = searchClient.initIndex(getIndexName('newest'))
export const probChangeDescendingIndex = searchClient.initIndex(
getIndexName('prob-change-day')
)

View File

@ -12,7 +12,6 @@ import { Dictionary, sortBy, sum } from 'lodash'
import { Page } from 'web/components/page'
import { Col } from 'web/components/layout/col'
import { ContractSearch, SORTS } from 'web/components/contract-search'
import { User } from 'common/user'
import { useTracking } from 'web/hooks/use-tracking'
import { track } from 'web/lib/service/analytics'
@ -43,7 +42,12 @@ import { isArray, keyBy } from 'lodash'
import { usePrefetch } from 'web/hooks/use-prefetch'
import { Title } from 'web/components/title'
import { CPMMBinaryContract } from 'common/contract'
import { useContractsByDailyScoreGroups } from 'web/hooks/use-contracts'
import {
useContractsByDailyScoreNotBetOn,
useContractsByDailyScoreGroups,
useTrendingContracts,
useNewContracts,
} from 'web/hooks/use-contracts'
import { ProfitBadge } from 'web/components/profit-badge'
import { LoadingIndicator } from 'web/components/loading-indicator'
@ -71,12 +75,18 @@ export default function Home() {
}
}, [user, sections])
const groups = useMemberGroupsSubscription(user)
const trendingContracts = useTrendingContracts(6)
const newContracts = useNewContracts(6)
const dailyTrendingContracts = useContractsByDailyScoreNotBetOn(user?.id, 6)
const groups = useMemberGroupsSubscription(user)
const groupContracts = useContractsByDailyScoreGroups(
groups?.map((g) => g.slug)
)
const isLoading =
!user || !trendingContracts || !newContracts || !dailyTrendingContracts
return (
<Page>
<Toaster />
@ -90,11 +100,15 @@ export default function Home() {
<DailyStats user={user} />
</Row>
{!user ? (
{isLoading ? (
<LoadingIndicator />
) : (
<>
{sections.map((section) => renderSection(section, user))}
{renderSections(user, sections, {
score: trendingContracts,
newest: newContracts,
'daily-trending': dailyTrendingContracts,
})}
<TrendingGroupsSection user={user} />
@ -118,8 +132,8 @@ export default function Home() {
}
const HOME_SECTIONS = [
{ label: 'Daily movers', id: 'daily-movers' },
{ label: 'Daily trending', id: 'daily-trending' },
{ label: 'Daily movers', id: 'daily-movers' },
{ label: 'Trending', id: 'score' },
{ label: 'New', id: 'newest' },
]
@ -128,11 +142,7 @@ export const getHomeItems = (sections: string[]) => {
// Accommodate old home sections.
if (!isArray(sections)) sections = []
const items: { id: string; label: string; group?: Group }[] = [
...HOME_SECTIONS,
]
const itemsById = keyBy(items, 'id')
const itemsById = keyBy(HOME_SECTIONS, 'id')
const sectionItems = filterDefined(sections.map((id) => itemsById[id]))
// Add new home section items to the top.
@ -140,7 +150,9 @@ export const getHomeItems = (sections: string[]) => {
...HOME_SECTIONS.filter((item) => !sectionItems.includes(item))
)
// Add unmentioned items to the end.
sectionItems.push(...items.filter((item) => !sectionItems.includes(item)))
sectionItems.push(
...HOME_SECTIONS.filter((item) => !sectionItems.includes(item))
)
return {
sections: sectionItems,
@ -148,28 +160,46 @@ export const getHomeItems = (sections: string[]) => {
}
}
function renderSection(section: { id: string; label: string }, user: User) {
const { id, label } = section
function renderSections(
user: User,
sections: { id: string; label: string }[],
sectionContracts: {
'daily-trending': CPMMBinaryContract[]
newest: CPMMBinaryContract[]
score: CPMMBinaryContract[]
}
) {
return (
<>
{sections.map((s) => {
const { id, label } = s
if (id === 'daily-movers') {
return <DailyMoversSection key={id} userId={user.id} />
}
if (id === 'daily-trending')
if (id === 'daily-trending') {
return (
<SearchSection
<ContractsSection
key={id}
label={label}
sort={'daily-score'}
pill="personal"
user={user}
contracts={sectionContracts[id]}
sort="daily-score"
showProbChange
/>
)
const sort = SORTS.find((sort) => sort.value === id)
if (sort)
}
const contracts =
sectionContracts[s.id as keyof typeof sectionContracts]
return (
<SearchSection key={id} label={label} sort={sort.value} user={user} />
<ContractsSection
key={id}
label={label}
contracts={contracts}
sort={id === 'daily-trending' ? 'daily-score' : (id as Sort)}
/>
)
})}
</>
)
return null
}
function renderGroupSections(
@ -237,13 +267,14 @@ function SectionHeader(props: {
)
}
function SearchSection(props: {
function ContractsSection(props: {
label: string
user: User
contracts: CPMMBinaryContract[]
sort: Sort
pill?: string
showProbChange?: boolean
}) {
const { label, user, sort, pill } = props
const { label, contracts, sort, pill, showProbChange } = props
return (
<Col>
@ -251,14 +282,7 @@ function SearchSection(props: {
label={label}
href={`/search?s=${sort}${pill ? `&p=${pill}` : ''}`}
/>
<ContractSearch
user={user}
defaultSort={sort}
defaultPill={pill}
noControls
maxResults={6}
persistPrefix={`home-${sort}`}
/>
<ContractsGrid contracts={contracts} cardUIOptions={{ showProbChange }} />
</Col>
)
}