Score & sort by unique bettors in last 3 days
This commit is contained in:
parent
58d6286361
commit
2152e5286a
|
@ -48,6 +48,7 @@ export type Contract<T extends AnyContractType = AnyContractType> = {
|
|||
groupSlugs?: string[]
|
||||
uniqueBettorIds?: string[]
|
||||
uniqueBettorCount?: number
|
||||
popularityScore?: number
|
||||
} & T
|
||||
|
||||
export type BinaryContract = Contract & Binary
|
||||
|
|
|
@ -22,6 +22,7 @@ export * from './on-update-user'
|
|||
export * from './on-create-comment-on-group'
|
||||
export * from './on-create-txn'
|
||||
export * from './on-delete-group'
|
||||
export * from './score-contracts'
|
||||
|
||||
// v2
|
||||
export * from './health'
|
||||
|
|
41
functions/src/score-contracts.ts
Normal file
41
functions/src/score-contracts.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import * as functions from 'firebase-functions'
|
||||
import * as admin from 'firebase-admin'
|
||||
import { Bet } from 'common/bet'
|
||||
import { uniq } from 'lodash'
|
||||
import { Contract } from 'common/contract'
|
||||
|
||||
export const scoreContracts = functions.pubsub
|
||||
.schedule('every 1 hours')
|
||||
.onRun(async () => {
|
||||
await scoreContractsInternal()
|
||||
})
|
||||
const firestore = admin.firestore()
|
||||
|
||||
async function scoreContractsInternal() {
|
||||
const now = Date.now()
|
||||
const lastHour = now - 3600000
|
||||
const last3Days = now - 2592000000
|
||||
|
||||
const contracts = await firestore
|
||||
.collection('contracts')
|
||||
.where('lastUpdatedTime', '>', lastHour)
|
||||
.get()
|
||||
|
||||
for (const contractSnap of contracts.docs) {
|
||||
const contract = contractSnap.data() as Contract
|
||||
const contractId = contractSnap.id
|
||||
const bets = await firestore
|
||||
.collection(`contracts/${contractId}/bets`)
|
||||
.where('createdTime', '>', last3Days)
|
||||
.get()
|
||||
const bettors = bets.docs
|
||||
.map((doc) => doc.data() as Bet)
|
||||
.map((bet) => bet.userId)
|
||||
const score = uniq(bettors).length
|
||||
if (contract.popularityScore !== score)
|
||||
await firestore
|
||||
.collection('contracts')
|
||||
.doc(contractId)
|
||||
.update({ popularityScore: score })
|
||||
}
|
||||
}
|
|
@ -39,13 +39,14 @@ const indexPrefix = ENV === 'DEV' ? 'dev-' : ''
|
|||
const sortIndexes = [
|
||||
{ label: 'Newest', value: indexPrefix + 'contracts-newest' },
|
||||
{ label: 'Oldest', value: indexPrefix + 'contracts-oldest' },
|
||||
{ label: 'Most popular', value: indexPrefix + 'contracts-most-popular' },
|
||||
{ label: 'Most popular', value: indexPrefix + 'contracts-score' },
|
||||
{ label: 'Most traded', value: indexPrefix + 'contracts-most-traded' },
|
||||
{ label: '24h volume', value: indexPrefix + 'contracts-24-hour-vol' },
|
||||
{ label: 'Last updated', value: indexPrefix + 'contracts-last-updated' },
|
||||
{ label: 'Close date', value: indexPrefix + 'contracts-close-date' },
|
||||
{ label: 'Resolve date', value: indexPrefix + 'contracts-resolve-date' },
|
||||
]
|
||||
export const DEFAULT_SORT = 'score'
|
||||
|
||||
type filter = 'personal' | 'open' | 'closed' | 'resolved' | 'all'
|
||||
const filterOptions: { [label: string]: filter } = {
|
||||
|
@ -95,7 +96,7 @@ export function ContractSearch(props: {
|
|||
.map(({ value }) => value)
|
||||
.includes(`${indexPrefix}contracts-${initialSort ?? ''}`)
|
||||
? initialSort
|
||||
: querySortOptions?.defaultSort ?? 'most-popular'
|
||||
: querySortOptions?.defaultSort ?? DEFAULT_SORT
|
||||
|
||||
const [filter, setFilter] = useState<filter>(
|
||||
querySortOptions?.defaultFilter ?? 'open'
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useRouter } from 'next/router'
|
|||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useSearchBox } from 'react-instantsearch-hooks-web'
|
||||
import { track } from 'web/lib/service/analytics'
|
||||
import { DEFAULT_SORT } from 'web/components/contract-search'
|
||||
|
||||
const MARKETS_SORT = 'markets_sort'
|
||||
|
||||
|
@ -10,11 +11,11 @@ export type Sort =
|
|||
| 'newest'
|
||||
| 'oldest'
|
||||
| 'most-traded'
|
||||
| 'most-popular'
|
||||
| '24-hour-vol'
|
||||
| 'close-date'
|
||||
| 'resolve-date'
|
||||
| 'last-updated'
|
||||
| 'score'
|
||||
|
||||
export function getSavedSort() {
|
||||
// TODO: this obviously doesn't work with SSR, common sense would suggest
|
||||
|
@ -31,7 +32,7 @@ export function useInitialQueryAndSort(options?: {
|
|||
shouldLoadFromStorage?: boolean
|
||||
}) {
|
||||
const { defaultSort, shouldLoadFromStorage } = defaults(options, {
|
||||
defaultSort: 'most-popular',
|
||||
defaultSort: DEFAULT_SORT,
|
||||
shouldLoadFromStorage: true,
|
||||
})
|
||||
const router = useRouter()
|
||||
|
|
|
@ -54,10 +54,8 @@ export default function ContractSearchFirestore(props: {
|
|||
)
|
||||
} else if (sort === 'most-traded') {
|
||||
matches.sort((a, b) => b.volume - a.volume)
|
||||
} else if (sort === 'most-popular') {
|
||||
matches.sort(
|
||||
(a, b) => (b.uniqueBettorCount ?? 0) - (a.uniqueBettorCount ?? 0)
|
||||
)
|
||||
} else if (sort === 'score') {
|
||||
matches.sort((a, b) => (b.popularityScore ?? 0) - (a.popularityScore ?? 0))
|
||||
} else if (sort === '24-hour-vol') {
|
||||
// Use lodash for stable sort, so previous sort breaks all ties.
|
||||
matches = sortBy(matches, ({ volume7Days }) => -1 * volume7Days)
|
||||
|
@ -104,7 +102,7 @@ export default function ContractSearchFirestore(props: {
|
|||
>
|
||||
<option value="newest">Newest</option>
|
||||
<option value="oldest">Oldest</option>
|
||||
<option value="most-popular">Most popular</option>
|
||||
<option value="score">Most popular</option>
|
||||
<option value="most-traded">Most traded</option>
|
||||
<option value="24-hour-vol">24h volume</option>
|
||||
<option value="close-date">Closing soon</option>
|
||||
|
|
|
@ -5,7 +5,7 @@ import { PlusSmIcon } from '@heroicons/react/solid'
|
|||
import { Page } from 'web/components/page'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { getSavedSort } from 'web/hooks/use-sort-and-query-params'
|
||||
import { ContractSearch } from 'web/components/contract-search'
|
||||
import { ContractSearch, DEFAULT_SORT } from 'web/components/contract-search'
|
||||
import { Contract } from 'common/contract'
|
||||
import { ContractPageContent } from './[username]/[contractSlug]'
|
||||
import { getContractFromSlug } from 'web/lib/firebase/contracts'
|
||||
|
@ -28,7 +28,7 @@ const Home = () => {
|
|||
<ContractSearch
|
||||
querySortOptions={{
|
||||
shouldLoadFromStorage: true,
|
||||
defaultSort: getSavedSort() ?? 'most-popular',
|
||||
defaultSort: getSavedSort() ?? DEFAULT_SORT,
|
||||
}}
|
||||
onContractClick={(c) => {
|
||||
// Show contract without navigating to contract page.
|
||||
|
|
Loading…
Reference in New Issue
Block a user