diff --git a/web/components/contract-card.tsx b/web/components/contract-card.tsx index d40089d7..c3d9595d 100644 --- a/web/components/contract-card.tsx +++ b/web/components/contract-card.tsx @@ -12,15 +12,16 @@ import { import { Col } from './layout/col' import { parseTags } from '../lib/util/parse' import dayjs from 'dayjs' -import { TrendingUpIcon } from '@heroicons/react/solid' +import { TrendingUpIcon, ClockIcon } from '@heroicons/react/solid' import { DateTimeTooltip } from './datetime-tooltip' export function ContractCard(props: { contract: Contract showHotVolume?: boolean + showCloseTime?: boolean className?: string }) { - const { contract, showHotVolume, className } = props + const { contract, showHotVolume, showCloseTime, className } = props const { question, resolution } = contract const { probPercent } = contractMetrics(contract) @@ -42,7 +43,11 @@ export function ContractCard(props: { probPercent={probPercent} /> - + ) } @@ -99,9 +104,10 @@ export function ResolutionOrChance(props: { export function AbbrContractDetails(props: { contract: Contract showHotVolume?: boolean + showCloseTime?: boolean }) { - const { contract, showHotVolume } = props - const { volume24Hours, creatorName, creatorUsername } = contract + const { contract, showHotVolume, showCloseTime } = props + const { volume24Hours, creatorName, creatorUsername, closeTime } = contract const { truePool } = contractMetrics(contract) return ( @@ -118,6 +124,11 @@ export function AbbrContractDetails(props: { {' '} {formatMoney(volume24Hours)} + ) : showCloseTime ? ( +
+ {' '} + {dayjs(closeTime).format('MMM D')} +
) : (
{formatMoney(truePool)} pool
)} diff --git a/web/components/contracts-list.tsx b/web/components/contracts-list.tsx index f90eb4db..d19c0212 100644 --- a/web/components/contracts-list.tsx +++ b/web/components/contracts-list.tsx @@ -18,8 +18,9 @@ import { Sort, useQueryAndSortParams } from '../hooks/use-sort-and-query-params' export function ContractsGrid(props: { contracts: Contract[] showHotVolume?: boolean + showCloseTime?: boolean }) { - const { showHotVolume } = props + const { showHotVolume, showCloseTime } = props const [resolvedContracts, activeContracts] = _.partition( props.contracts, @@ -51,6 +52,7 @@ export function ContractsGrid(props: { contract={contract} key={contract.id} showHotVolume={showHotVolume} + showCloseTime={showCloseTime} /> ))} diff --git a/web/lib/firebase/contracts.ts b/web/lib/firebase/contracts.ts index b674296a..d98fa2db 100644 --- a/web/lib/firebase/contracts.ts +++ b/web/lib/firebase/contracts.ts @@ -14,6 +14,7 @@ import { updateDoc, limit, } from 'firebase/firestore' +import _ from 'lodash' import { app } from './init' import { getValues, listenForValues } from './utils' @@ -123,6 +124,13 @@ export function listenForContract( }) } +function chooseRandomSubset(contracts: Contract[], count: number) { + const fiveMinutes = 5 * 60 * 1000 + const seed = Math.round(Date.now() / fiveMinutes).toString() + shuffle(contracts, createRNG(seed)) + return contracts.slice(0, count) +} + const hotContractsQuery = query( contractCollection, where('isResolved', '==', false), @@ -131,21 +139,38 @@ const hotContractsQuery = query( limit(16) ) -function chooseHotContracts(contracts: Contract[]) { - const fiveMinutes = 5 * 60 * 1000 - const seed = Math.round(Date.now() / fiveMinutes).toString() - shuffle(contracts, createRNG(seed)) - return contracts.slice(0, 4) -} - export function listenForHotContracts( setHotContracts: (contracts: Contract[]) => void ) { - return listenForValues(hotContractsQuery, (contracts) => - setHotContracts(chooseHotContracts(contracts)) + return listenForValues(hotContractsQuery, (contracts) => { + const hotContracts = _.sortBy( + chooseRandomSubset(contracts, 4), + (contract) => contract.volume24Hours + ) + setHotContracts(hotContracts) + }) +} + +export async function getHotContracts() { + const contracts = await getValues(hotContractsQuery) + return _.sortBy( + chooseRandomSubset(contracts, 4), + (contract) => -1 * contract.volume24Hours ) } -export function getHotContracts() { - return getValues(hotContractsQuery).then(chooseHotContracts) +const closingSoonQuery = query( + contractCollection, + where('isResolved', '==', false), + where('closeTime', '>', Date.now()), + orderBy('closeTime', 'asc'), + limit(6) +) + +export async function getClosingSoonContracts() { + const contracts = await getValues(closingSoonQuery) + return _.sortBy( + chooseRandomSubset(contracts, 2), + (contract) => contract.closeTime + ) } diff --git a/web/pages/index.tsx b/web/pages/index.tsx index 727253b0..acf1eb2a 100644 --- a/web/pages/index.tsx +++ b/web/pages/index.tsx @@ -2,6 +2,7 @@ import React from 'react' import _ from 'lodash' import { Contract, + getClosingSoonContracts, getHotContracts, listAllContracts, } from '../lib/firebase/contracts' @@ -14,16 +15,17 @@ import { Comment, listAllComments, } from '../lib/firebase/comments' -import { Col } from '../components/layout/col' -import { ContractCard } from '../components/contract-card' import { Bet, listAllBets } from '../lib/firebase/bets' +import { ContractsGrid } from '../components/contracts-list' export async function getStaticProps() { - const [contracts, hotContracts, recentComments] = await Promise.all([ - listAllContracts().catch((_) => []), - getHotContracts().catch(() => []), - getRecentComments().catch(() => []), - ]) + const [contracts, hotContracts, closingSoonContracts, recentComments] = + await Promise.all([ + listAllContracts().catch((_) => []), + getHotContracts().catch(() => []), + getClosingSoonContracts().catch(() => []), + getRecentComments().catch(() => []), + ]) const activeContracts = findActiveContracts(contracts, recentComments) const activeContractBets = await Promise.all( @@ -39,6 +41,7 @@ export async function getStaticProps() { activeContractBets, activeContractComments, hotContracts, + closingSoonContracts, }, revalidate: 60, // regenerate after a minute @@ -50,17 +53,21 @@ const Home = (props: { activeContractBets: Bet[][] activeContractComments: Comment[][] hotContracts: Contract[] + closingSoonContracts: Contract[] }) => { const { activeContracts, activeContractBets, activeContractComments, hotContracts, + closingSoonContracts, } = props return ( - + + + { - const { hotContracts } = props - if (hotContracts.length < 4) return <> - - const [c1, c2, c3, c4] = hotContracts +const HotMarkets = (props: { contracts: Contract[] }) => { + const { contracts } = props + if (contracts.length === 0) return <> return (
- <Col className="gap-6"> - <Col className="md:flex-row items-start gap-6"> - <ContractCard className="flex-1" contract={c1} showHotVolume /> - <ContractCard className="flex-1" contract={c2} showHotVolume /> - </Col> - <Col className="md:flex-row items-start gap-6"> - <ContractCard className="flex-1" contract={c3} showHotVolume /> - <ContractCard className="flex-1" contract={c4} showHotVolume /> - </Col> - </Col> + <ContractsGrid contracts={contracts} showHotVolume /> + </div> + ) +} + +const ClosingSoonMarkets = (props: { contracts: Contract[] }) => { + const { contracts } = props + if (contracts.length === 0) return <></> + + return ( + <div className="w-full bg-green-50 border-2 border-green-100 p-6 rounded-lg shadow-md"> + <Title className="mt-0" text="⏰ Closing soon" /> + <ContractsGrid contracts={contracts} showCloseTime /> </div> ) }