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

View File

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

View File

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