Recommend contracts you haven't bet on

This commit is contained in:
James Grugett 2022-08-30 00:22:11 -05:00
parent 1369f3b967
commit c7452796f0
2 changed files with 33 additions and 34 deletions

View File

@ -13,7 +13,7 @@ import {
updateDoc, updateDoc,
where, where,
} from 'firebase/firestore' } from 'firebase/firestore'
import { sortBy, sum, uniqBy } from 'lodash' import { partition, sortBy, sum, uniqBy } from 'lodash'
import { coll, getValues, listenForValue, listenForValues } from './utils' import { coll, getValues, listenForValue, listenForValues } from './utils'
import { BinaryContract, Contract } from 'common/contract' import { BinaryContract, Contract } from 'common/contract'
@ -303,62 +303,63 @@ export async function getClosingSoonContracts() {
return sortBy(chooseRandomSubset(data, 2), (contract) => contract.closeTime) return sortBy(chooseRandomSubset(data, 2), (contract) => contract.closeTime)
} }
export const getRandTopCreatorContracts = async ( export const getTopCreatorContracts = async (
creatorId: string, creatorId: string,
count: number, count: number
excluding: string[] = []
) => { ) => {
const creatorContractsQuery = query( const creatorContractsQuery = query(
contracts, contracts,
where('isResolved', '==', false), where('isResolved', '==', false),
where('creatorId', '==', creatorId), where('creatorId', '==', creatorId),
orderBy('popularityScore', 'desc'), orderBy('popularityScore', 'desc'),
limit(count * 2) limit(count)
) )
const data = await getValues<Contract>(creatorContractsQuery) return await getValues<Contract>(creatorContractsQuery)
const open = data
.filter((c) => c.closeTime && c.closeTime > Date.now())
.filter((c) => !excluding.includes(c.id))
return chooseRandomSubset(open, count)
} }
export const getRandTopGroupContracts = async ( export const getTopGroupContracts = async (
groupSlug: string, groupSlug: string,
count: number, count: number
excluding: string[] = []
) => { ) => {
const creatorContractsQuery = query( const creatorContractsQuery = query(
contracts, contracts,
where('groupSlugs', 'array-contains', groupSlug), where('groupSlugs', 'array-contains', groupSlug),
where('isResolved', '==', false), where('isResolved', '==', false),
orderBy('popularityScore', 'desc'), orderBy('popularityScore', 'desc'),
limit(count * 2) limit(count)
) )
const data = await getValues<Contract>(creatorContractsQuery) return await getValues<Contract>(creatorContractsQuery)
const open = data
.filter((c) => c.closeTime && c.closeTime > Date.now())
.filter((c) => !excluding.includes(c.id))
return chooseRandomSubset(open, count)
} }
export const getRecommendedContracts = async ( export const getRecommendedContracts = async (
contract: Contract, contract: Contract,
excludeBettorId: string,
count: number count: number
) => { ) => {
const { creatorId, groupSlugs, id } = contract const { creatorId, groupSlugs, id } = contract
const [userContracts, groupContracts] = await Promise.all([ const [userContracts, groupContracts] = await Promise.all([
getRandTopCreatorContracts(creatorId, count, [id]), getTopCreatorContracts(creatorId, count * 2),
groupSlugs && groupSlugs[0] groupSlugs && groupSlugs[0]
? getRandTopGroupContracts(groupSlugs[0], count, [id]) ? getTopGroupContracts(groupSlugs[0], count * 2)
: [], : [],
]) ])
const combined = uniqBy([...userContracts, ...groupContracts], (c) => c.id) const combined = uniqBy([...userContracts, ...groupContracts], (c) => c.id)
return chooseRandomSubset(combined, count) const open = combined
.filter((c) => c.closeTime && c.closeTime > Date.now())
.filter((c) => c.id !== id)
const [betOnContracts, nonBetOnContracts] = partition(
open,
(c) => c.uniqueBettorIds && c.uniqueBettorIds.includes(excludeBettorId)
)
const chosen = chooseRandomSubset(nonBetOnContracts, count)
if (chosen.length < count)
chosen.push(...chooseRandomSubset(betOnContracts, count - chosen.length))
return chosen
} }
export async function getRecentBetsAndComments(contract: Contract) { export async function getRecentBetsAndComments(contract: Contract) {

View File

@ -52,10 +52,9 @@ export async function getStaticPropz(props: {
const contract = (await getContractFromSlug(contractSlug)) || null const contract = (await getContractFromSlug(contractSlug)) || null
const contractId = contract?.id const contractId = contract?.id
const [bets, comments, recommendedContracts] = await Promise.all([ const [bets, comments] = await Promise.all([
contractId ? listAllBets(contractId) : [], contractId ? listAllBets(contractId) : [],
contractId ? listAllComments(contractId) : [], contractId ? listAllComments(contractId) : [],
contract ? getRecommendedContracts(contract, 6) : [],
]) ])
return { return {
@ -66,7 +65,6 @@ export async function getStaticPropz(props: {
// Limit the data sent to the client. Client will still load all bets and comments directly. // Limit the data sent to the client. Client will still load all bets and comments directly.
bets: bets.slice(0, 5000), bets: bets.slice(0, 5000),
comments: comments.slice(0, 1000), comments: comments.slice(0, 1000),
recommendedContracts,
}, },
revalidate: 60, // regenerate after a minute revalidate: 60, // regenerate after a minute
@ -83,7 +81,6 @@ export default function ContractPage(props: {
bets: Bet[] bets: Bet[]
comments: ContractComment[] comments: ContractComment[]
slug: string slug: string
recommendedContracts: Contract[]
backToHome?: () => void backToHome?: () => void
}) { }) {
props = usePropz(props, getStaticPropz) ?? { props = usePropz(props, getStaticPropz) ?? {
@ -91,7 +88,6 @@ export default function ContractPage(props: {
username: '', username: '',
comments: [], comments: [],
bets: [], bets: [],
recommendedContracts: [],
slug: '', slug: '',
} }
@ -188,15 +184,17 @@ export function ContractPageContent(
setShowConfetti(shouldSeeConfetti) setShowConfetti(shouldSeeConfetti)
}, [contract, user]) }, [contract, user])
const [recommendedContracts, setRecommendedMarkets] = useState( const [recommendedContracts, setRecommendedContracts] = useState<Contract[]>(
props.recommendedContracts []
) )
useEffect(() => { useEffect(() => {
if (contract && recommendedContracts.length === 0) { if (contract && user) {
getRecommendedContracts(contract, 6).then(setRecommendedMarkets) getRecommendedContracts(contract, user.id, 6).then(
setRecommendedContracts
)
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [contract.id, recommendedContracts]) }, [contract.id, user?.id])
const { isResolved, question, outcomeType } = contract const { isResolved, question, outcomeType } = contract