Hot markets! 🔥
This commit is contained in:
parent
4386422f02
commit
1bc323d575
|
@ -120,7 +120,7 @@ export function ContractDetails(props: {
|
|||
|
||||
<Row className="gap-2 flex-wrap">
|
||||
{tags.map((tag) => (
|
||||
<div className="bg-gray-100 px-1">
|
||||
<div key={tag} className="bg-gray-100 px-1">
|
||||
<Linkify text={tag} gray />
|
||||
</div>
|
||||
))}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { parseTags } from '../lib/util/parse'
|
|||
import { ContractCard } from './contract-card'
|
||||
import { Sort, useQueryAndSortParams } from '../hooks/use-sort-and-query-params'
|
||||
|
||||
function ContractsGrid(props: { contracts: Contract[] }) {
|
||||
export function ContractsGrid(props: { contracts: Contract[] }) {
|
||||
const [resolvedContracts, activeContracts] = _.partition(
|
||||
props.contracts,
|
||||
(c) => c.isResolved
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import _ from 'lodash'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Contract, listenForContracts } from '../lib/firebase/contracts'
|
||||
import { Bet, listenForRecentBets } from '../lib/firebase/bets'
|
||||
import {
|
||||
computeHotContracts,
|
||||
Contract,
|
||||
listenForContracts,
|
||||
} from '../lib/firebase/contracts'
|
||||
|
||||
export const useContracts = () => {
|
||||
const [contracts, setContracts] = useState<Contract[] | 'loading'>('loading')
|
||||
|
@ -10,3 +16,16 @@ export const useContracts = () => {
|
|||
|
||||
return contracts
|
||||
}
|
||||
|
||||
export const useHotContracts = () => {
|
||||
const [recentBets, setRecentBets] = useState<Bet[] | 'loading'>('loading')
|
||||
|
||||
useEffect(() => {
|
||||
const oneDay = 1000 * 60 * 60 * 24
|
||||
return listenForRecentBets(oneDay, setRecentBets)
|
||||
}, [])
|
||||
|
||||
if (recentBets === 'loading') return 'loading'
|
||||
|
||||
return computeHotContracts(recentBets)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ import {
|
|||
query,
|
||||
onSnapshot,
|
||||
where,
|
||||
getDocs,
|
||||
} from 'firebase/firestore'
|
||||
import _ from 'lodash'
|
||||
import { db } from './init'
|
||||
|
||||
export type Bet = {
|
||||
|
@ -62,3 +64,34 @@ export function listenForUserBets(
|
|||
setBets(bets)
|
||||
})
|
||||
}
|
||||
|
||||
export function listenForRecentBets(
|
||||
timePeriodMs: number,
|
||||
setBets: (bets: Bet[]) => void
|
||||
) {
|
||||
const recentQuery = query(
|
||||
collectionGroup(db, 'bets'),
|
||||
where('createdTime', '>', Date.now() - timePeriodMs)
|
||||
)
|
||||
return onSnapshot(recentQuery, (snap) => {
|
||||
const bets = snap.docs.map((doc) => doc.data() as Bet)
|
||||
|
||||
bets.sort((bet1, bet2) => bet1.createdTime - bet2.createdTime)
|
||||
|
||||
setBets(bets)
|
||||
})
|
||||
}
|
||||
|
||||
export async function getRecentBets(timePeriodMs: number) {
|
||||
const recentQuery = query(
|
||||
collectionGroup(db, 'bets'),
|
||||
where('createdTime', '>', Date.now() - timePeriodMs)
|
||||
)
|
||||
|
||||
const snapshot = await getDocs(recentQuery)
|
||||
const bets = snapshot.docs.map((doc) => doc.data() as Bet)
|
||||
|
||||
bets.sort((bet1, bet2) => bet1.createdTime - bet2.createdTime)
|
||||
|
||||
return bets
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@ import {
|
|||
onSnapshot,
|
||||
orderBy,
|
||||
getDoc,
|
||||
limit,
|
||||
} from 'firebase/firestore'
|
||||
import dayjs from 'dayjs'
|
||||
import { Bet, getRecentBets } from './bets'
|
||||
import _ from 'lodash'
|
||||
|
||||
export type Contract = {
|
||||
id: string
|
||||
|
@ -131,3 +132,17 @@ export function listenForContract(
|
|||
setContract((contractSnap.data() ?? null) as Contract | null)
|
||||
})
|
||||
}
|
||||
|
||||
export function computeHotContracts(recentBets: Bet[]) {
|
||||
const contractBets = _.groupBy(recentBets, (bet) => bet.contractId)
|
||||
const hotContractIds = _.sortBy(Object.keys(contractBets), (contractId) =>
|
||||
_.sumBy(contractBets[contractId], (bet) => -1 * bet.amount)
|
||||
).slice(0, 4)
|
||||
return hotContractIds
|
||||
}
|
||||
|
||||
export async function getHotContracts() {
|
||||
const oneDay = 1000 * 60 * 60 * 24
|
||||
const recentBets = await getRecentBets(oneDay)
|
||||
return computeHotContracts(recentBets)
|
||||
}
|
||||
|
|
|
@ -3,26 +3,42 @@ import React from 'react'
|
|||
import { useUser } from '../hooks/use-user'
|
||||
import Markets from './markets'
|
||||
import LandingPage from './landing-page'
|
||||
import { Contract, listAllContracts } from '../lib/firebase/contracts'
|
||||
import {
|
||||
Contract,
|
||||
getHotContracts,
|
||||
listAllContracts,
|
||||
} from '../lib/firebase/contracts'
|
||||
import _ from 'lodash'
|
||||
|
||||
export async function getStaticProps() {
|
||||
const contracts = await listAllContracts().catch((_) => [])
|
||||
const [contracts, hotContractIds] = await Promise.all([
|
||||
listAllContracts().catch((_) => []),
|
||||
getHotContracts().catch(() => []),
|
||||
])
|
||||
|
||||
return {
|
||||
props: {
|
||||
contracts,
|
||||
hotContractIds,
|
||||
},
|
||||
|
||||
revalidate: 60, // regenerate after a minute
|
||||
}
|
||||
}
|
||||
|
||||
const Home = (props: { contracts: Contract[] }) => {
|
||||
const Home = (props: { contracts: Contract[]; hotContractIds: string[] }) => {
|
||||
const user = useUser()
|
||||
|
||||
if (user === undefined) return <></>
|
||||
|
||||
return user ? <Markets contracts={props.contracts} /> : <LandingPage />
|
||||
return user ? (
|
||||
<Markets
|
||||
contracts={props.contracts}
|
||||
hotContractIds={props.hotContractIds}
|
||||
/>
|
||||
) : (
|
||||
<LandingPage />
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
|
|
|
@ -1,30 +1,61 @@
|
|||
import { SearchableGrid } from '../components/contracts-list'
|
||||
import _ from 'lodash'
|
||||
import { ContractsGrid, SearchableGrid } from '../components/contracts-list'
|
||||
import { Spacer } from '../components/layout/spacer'
|
||||
import { Page } from '../components/page'
|
||||
import { useContracts } from '../hooks/use-contracts'
|
||||
import { Title } from '../components/title'
|
||||
import { useContracts, useHotContracts } from '../hooks/use-contracts'
|
||||
import { useQueryAndSortParams } from '../hooks/use-sort-and-query-params'
|
||||
import { Contract, listAllContracts } from '../lib/firebase/contracts'
|
||||
import {
|
||||
Contract,
|
||||
getHotContracts,
|
||||
listAllContracts,
|
||||
} from '../lib/firebase/contracts'
|
||||
|
||||
export async function getStaticProps() {
|
||||
const contracts = await listAllContracts().catch((_) => [])
|
||||
const [contracts, hotContractIds] = await Promise.all([
|
||||
listAllContracts().catch((_) => []),
|
||||
getHotContracts().catch(() => []),
|
||||
])
|
||||
|
||||
return {
|
||||
props: {
|
||||
contracts,
|
||||
hotContractIds,
|
||||
},
|
||||
|
||||
revalidate: 60, // regenerate after a minute
|
||||
}
|
||||
}
|
||||
|
||||
export default function Markets(props: { contracts: Contract[] }) {
|
||||
export default function Markets(props: {
|
||||
contracts: Contract[]
|
||||
hotContractIds: string[]
|
||||
}) {
|
||||
const contracts = useContracts()
|
||||
const { query, setQuery, sort, setSort } = useQueryAndSortParams()
|
||||
const hotContractIds = useHotContracts()
|
||||
|
||||
const readyHotContractIds =
|
||||
hotContractIds === 'loading' ? props.hotContractIds : hotContractIds
|
||||
const readyContracts = contracts === 'loading' ? props.contracts : contracts
|
||||
|
||||
const hotContracts = readyHotContractIds.map(
|
||||
(hotId) =>
|
||||
_.find(readyContracts, (contract) => contract.id === hotId) as Contract
|
||||
)
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<div className="w-full bg-indigo-50 border-2 border-indigo-100 p-6 rounded-lg shadow-md">
|
||||
<Title className="mt-0" text="🔥 Markets" />
|
||||
<ContractsGrid contracts={hotContracts} />
|
||||
</div>
|
||||
|
||||
<Spacer h={10} />
|
||||
|
||||
{(props.contracts || contracts !== 'loading') && (
|
||||
<SearchableGrid
|
||||
contracts={contracts === 'loading' ? props.contracts : contracts}
|
||||
contracts={readyContracts}
|
||||
query={query}
|
||||
setQuery={setQuery}
|
||||
sort={sort}
|
||||
|
|
Loading…
Reference in New Issue
Block a user