Query hot contracts from volume24Hours field.

This commit is contained in:
jahooma 2022-01-09 14:26:51 -06:00
parent 6b4417d8b8
commit 16ab0e0c37
6 changed files with 70 additions and 80 deletions

View File

@ -1,10 +1,9 @@
import _ from 'lodash' import _ from 'lodash'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Bet, listenForRecentBets } from '../lib/firebase/bets'
import { import {
computeHotContracts,
Contract, Contract,
listenForContracts, listenForContracts,
listenForHotContracts,
} from '../lib/firebase/contracts' } from '../lib/firebase/contracts'
export const useContracts = () => { export const useContracts = () => {
@ -18,14 +17,9 @@ export const useContracts = () => {
} }
export const useHotContracts = () => { export const useHotContracts = () => {
const [recentBets, setRecentBets] = useState<Bet[] | 'loading'>('loading') const [hotContracts, setHotContracts] = useState<Contract[] | undefined>()
useEffect(() => { useEffect(() => listenForHotContracts(setHotContracts), [])
const oneDay = 1000 * 60 * 60 * 24
return listenForRecentBets(oneDay, setRecentBets)
}, [])
if (recentBets === 'loading') return 'loading' return hotContracts
return computeHotContracts(recentBets)
} }

View File

@ -4,7 +4,6 @@ import {
query, query,
onSnapshot, onSnapshot,
where, where,
getDocs,
} from 'firebase/firestore' } from 'firebase/firestore'
import _ from 'lodash' import _ from 'lodash'
import { db } from './init' import { db } from './init'
@ -64,34 +63,3 @@ export function listenForUserBets(
setBets(bets) 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
}

View File

@ -12,10 +12,10 @@ import {
orderBy, orderBy,
getDoc, getDoc,
updateDoc, updateDoc,
limit,
} from 'firebase/firestore' } from 'firebase/firestore'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { Bet, getRecentBets } from './bets' import { getValues, listenForValues } from './utils'
import _ from 'lodash'
export type Contract = { export type Contract = {
id: string id: string
@ -145,16 +145,19 @@ export function listenForContract(
}) })
} }
export function computeHotContracts(recentBets: Bet[]) { const hotContractsQuery = query(
const contractBets = _.groupBy(recentBets, (bet) => bet.contractId) contractCollection,
const hotContractIds = _.sortBy(Object.keys(contractBets), (contractId) => where('isResolved', '==', false),
_.sumBy(contractBets[contractId], (bet) => -1 * bet.amount) orderBy('volume24Hours', 'desc'),
) limit(4)
return hotContractIds )
export function listenForHotContracts(
setHotContracts: (contracts: Contract[]) => void
) {
return listenForValues<Contract>(hotContractsQuery, setHotContracts)
} }
export async function getHotContracts() { export function getHotContracts() {
const oneDay = 1000 * 60 * 60 * 24 return getValues<Contract>(hotContractsQuery)
const recentBets = await getRecentBets(oneDay)
return computeHotContracts(recentBets)
} }

39
web/lib/firebase/utils.ts Normal file
View File

@ -0,0 +1,39 @@
import { db } from './init'
import {
doc,
getDoc,
getDocs,
onSnapshot,
Query,
DocumentReference,
} from 'firebase/firestore'
export const getValue = async <T>(collectionName: string, docName: string) => {
const snap = await getDoc(doc(db, collectionName, docName))
return snap.exists() ? (snap.data() as T) : null
}
export const getValues = async <T>(query: Query) => {
const snap = await getDocs(query)
return snap.docs.map((doc) => doc.data() as T)
}
export function listenForValue<T>(
docRef: DocumentReference,
setValue: (value: T | null) => void
) {
return onSnapshot(docRef, (snapshot) => {
const value = snapshot.exists() ? (snapshot.data() as T) : null
setValue(value)
})
}
export function listenForValues<T>(
query: Query,
setValues: (values: T[]) => void
) {
return onSnapshot(query, (snapshot) => {
const values = snapshot.docs.map((doc) => doc.data() as T)
setValues(values)
})
}

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import _ from 'lodash'
import { useUser } from '../hooks/use-user' import { useUser } from '../hooks/use-user'
import Markets from './markets' import Markets from './markets'
import LandingPage from './landing-page' import LandingPage from './landing-page'
@ -8,10 +8,9 @@ import {
getHotContracts, getHotContracts,
listAllContracts, listAllContracts,
} from '../lib/firebase/contracts' } from '../lib/firebase/contracts'
import _ from 'lodash'
export async function getStaticProps() { export async function getStaticProps() {
const [contracts, hotContractIds] = await Promise.all([ const [contracts, hotContracts] = await Promise.all([
listAllContracts().catch((_) => []), listAllContracts().catch((_) => []),
getHotContracts().catch(() => []), getHotContracts().catch(() => []),
]) ])
@ -19,26 +18,22 @@ export async function getStaticProps() {
return { return {
props: { props: {
contracts, contracts,
hotContractIds, hotContracts,
}, },
revalidate: 60, // regenerate after a minute revalidate: 60, // regenerate after a minute
} }
} }
const Home = (props: { contracts: Contract[]; hotContractIds: string[] }) => { const Home = (props: { contracts: Contract[]; hotContracts: Contract[] }) => {
const user = useUser() const user = useUser()
if (user === undefined) return <></> if (user === undefined) return <></>
const { contracts, hotContractIds } = props const { contracts, hotContracts } = props
const hotContracts = hotContractIds
.map((id) => contracts.find((contract) => contract.id === id) as Contract)
.filter((contract) => !contract.isResolved)
.slice(0, 4)
return user ? ( return user ? (
<Markets contracts={contracts} hotContractIds={hotContractIds} /> <Markets contracts={contracts} hotContracts={hotContracts} />
) : ( ) : (
<LandingPage hotContracts={hotContracts} /> <LandingPage hotContracts={hotContracts} />
) )

View File

@ -12,7 +12,7 @@ import {
} from '../lib/firebase/contracts' } from '../lib/firebase/contracts'
export async function getStaticProps() { export async function getStaticProps() {
const [contracts, hotContractIds] = await Promise.all([ const [contracts, hotContracts] = await Promise.all([
listAllContracts().catch((_) => []), listAllContracts().catch((_) => []),
getHotContracts().catch(() => []), getHotContracts().catch(() => []),
]) ])
@ -20,7 +20,7 @@ export async function getStaticProps() {
return { return {
props: { props: {
contracts, contracts,
hotContractIds, hotContracts,
}, },
revalidate: 60, // regenerate after a minute revalidate: 60, // regenerate after a minute
@ -29,29 +29,20 @@ export async function getStaticProps() {
export default function Markets(props: { export default function Markets(props: {
contracts: Contract[] contracts: Contract[]
hotContractIds: string[] hotContracts: Contract[]
}) { }) {
const contracts = useContracts() const contracts = useContracts()
const hotContracts = useHotContracts()
const { query, setQuery, sort, setSort } = useQueryAndSortParams() const { query, setQuery, sort, setSort } = useQueryAndSortParams()
const hotContractIds = useHotContracts()
const readyHotContractIds = const readyHotContracts = hotContracts ?? props.hotContracts
hotContractIds === 'loading' ? props.hotContractIds : hotContractIds
const readyContracts = contracts === 'loading' ? props.contracts : contracts const readyContracts = contracts === 'loading' ? props.contracts : contracts
const hotContracts = readyHotContractIds
.map(
(hotId) =>
_.find(readyContracts, (contract) => contract.id === hotId) as Contract
)
.filter((contract) => !contract.isResolved)
.slice(0, 4)
return ( return (
<Page> <Page>
<div className="w-full bg-indigo-50 border-2 border-indigo-100 p-6 rounded-lg shadow-md"> <div className="w-full bg-indigo-50 border-2 border-indigo-100 p-6 rounded-lg shadow-md">
<Title className="mt-0" text="🔥 Markets" /> <Title className="mt-0" text="🔥 Markets" />
<ContractsGrid contracts={hotContracts} /> <ContractsGrid contracts={readyHotContracts} />
</div> </div>
<Spacer h={10} /> <Spacer h={10} />