From b0b1d72ba61382c2035c8867e735816b0bfaf2f8 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Fri, 30 Sep 2022 20:07:49 -0500 Subject: [PATCH] Cleaner home page loading! --- web/hooks/use-contracts.ts | 56 ++++++++++++++----- web/lib/service/algolia.ts | 2 + web/pages/home/index.tsx | 112 ++++++++++++++++++++++--------------- 3 files changed, 112 insertions(+), 58 deletions(-) diff --git a/web/hooks/use-contracts.ts b/web/hooks/use-contracts.ts index 11aae65c..7952deba 100644 --- a/web/hooks/use-contracts.ts +++ b/web/hooks/use-contracts.ts @@ -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('', { + 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('', { + 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('', { + 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('', { - 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() diff --git a/web/lib/service/algolia.ts b/web/lib/service/algolia.ts index 29cbd6bf..bdace399 100644 --- a/web/lib/service/algolia.ts +++ b/web/lib/service/algolia.ts @@ -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') ) diff --git a/web/pages/home/index.tsx b/web/pages/home/index.tsx index 2ddc3026..4ad7f97b 100644 --- a/web/pages/home/index.tsx +++ b/web/pages/home/index.tsx @@ -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 ( @@ -90,11 +100,15 @@ export default function Home() { - {!user ? ( + {isLoading ? ( ) : ( <> - {sections.map((section) => renderSection(section, user))} + {renderSections(user, sections, { + score: trendingContracts, + newest: newContracts, + 'daily-trending': dailyTrendingContracts, + })} @@ -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 - if (id === 'daily-movers') { - return +function renderSections( + user: User, + sections: { id: string; label: string }[], + sectionContracts: { + 'daily-trending': CPMMBinaryContract[] + newest: CPMMBinaryContract[] + score: CPMMBinaryContract[] } - if (id === 'daily-trending') - return ( - - ) - const sort = SORTS.find((sort) => sort.value === id) - if (sort) - return ( - - ) - - return null +) { + return ( + <> + {sections.map((s) => { + const { id, label } = s + if (id === 'daily-movers') { + return + } + if (id === 'daily-trending') { + return ( + + ) + } + const contracts = + sectionContracts[s.id as keyof typeof sectionContracts] + return ( + + ) + })} + + ) } 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 ( @@ -251,14 +282,7 @@ function SearchSection(props: { label={label} href={`/search?s=${sort}${pill ? `&p=${pill}` : ''}`} /> - + ) }