2022-08-30 04:56:11 +00:00
|
|
|
import { useRouter } from 'next/router'
|
2022-06-14 09:35:51 +00:00
|
|
|
import { Answer } from 'common/answer'
|
2022-07-15 21:16:00 +00:00
|
|
|
import { searchInAny } from 'common/util/parse'
|
2022-06-14 09:35:51 +00:00
|
|
|
import { sortBy } from 'lodash'
|
2022-08-06 00:46:32 +00:00
|
|
|
import { ContractsGrid } from 'web/components/contract/contracts-grid'
|
2022-06-14 09:35:51 +00:00
|
|
|
import { useContracts } from 'web/hooks/use-contracts'
|
2022-08-30 04:56:11 +00:00
|
|
|
import {
|
|
|
|
usePersistentState,
|
|
|
|
urlParamStore,
|
|
|
|
} from 'web/hooks/use-persistent-state'
|
2022-09-15 15:12:56 +00:00
|
|
|
import { PAST_BETS } from 'common/user'
|
2022-10-10 02:37:24 +00:00
|
|
|
import { Input } from 'web/components/input'
|
2022-10-13 18:23:42 +00:00
|
|
|
import { Select } from 'web/components/select'
|
2022-06-14 09:35:51 +00:00
|
|
|
|
2022-07-01 16:26:45 +00:00
|
|
|
const MAX_CONTRACTS_RENDERED = 100
|
|
|
|
|
2022-06-22 23:45:48 +00:00
|
|
|
export default function ContractSearchFirestore(props: {
|
2022-06-24 17:08:06 +00:00
|
|
|
additionalFilter?: {
|
|
|
|
creatorId?: string
|
|
|
|
tag?: string
|
2022-08-05 19:01:16 +00:00
|
|
|
excludeContractIds?: string[]
|
|
|
|
groupSlug?: string
|
2022-06-24 17:08:06 +00:00
|
|
|
}
|
2022-06-14 09:35:51 +00:00
|
|
|
}) {
|
2022-08-15 05:09:25 +00:00
|
|
|
const { additionalFilter } = props
|
2022-08-30 04:56:11 +00:00
|
|
|
const contracts = useContracts()
|
|
|
|
const router = useRouter()
|
|
|
|
const store = urlParamStore(router)
|
|
|
|
const [query, setQuery] = usePersistentState('', { key: 'q', store })
|
|
|
|
const [sort, setSort] = usePersistentState('score', { key: 'sort', store })
|
2022-06-14 09:35:51 +00:00
|
|
|
|
2022-07-15 21:16:00 +00:00
|
|
|
let matches = (contracts ?? []).filter((c) =>
|
|
|
|
searchInAny(
|
|
|
|
query,
|
|
|
|
c.question,
|
|
|
|
c.creatorName,
|
|
|
|
c.lowercaseTags.map((tag) => `#${tag}`).join(' '),
|
|
|
|
((c as any).answers ?? []).map((answer: Answer) => answer.text).join(' ')
|
|
|
|
)
|
2022-06-14 09:35:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if (sort === 'newest') {
|
|
|
|
matches.sort((a, b) => b.createdTime - a.createdTime)
|
|
|
|
} else if (sort === 'resolve-date') {
|
|
|
|
matches = sortBy(matches, (contract) => -1 * (contract.resolutionTime ?? 0))
|
|
|
|
} else if (sort === 'close-date') {
|
|
|
|
matches = sortBy(matches, ({ volume24Hours }) => -1 * volume24Hours)
|
2022-08-07 23:43:53 +00:00
|
|
|
matches = sortBy(matches, (contract) => contract.closeTime ?? Infinity)
|
2022-06-14 09:35:51 +00:00
|
|
|
} else if (sort === 'most-traded') {
|
|
|
|
matches.sort((a, b) => b.volume - a.volume)
|
2022-07-19 22:29:41 +00:00
|
|
|
} else if (sort === 'score') {
|
|
|
|
matches.sort((a, b) => (b.popularityScore ?? 0) - (a.popularityScore ?? 0))
|
2022-06-14 09:35:51 +00:00
|
|
|
} else if (sort === '24-hour-vol') {
|
|
|
|
// Use lodash for stable sort, so previous sort breaks all ties.
|
|
|
|
matches = sortBy(matches, ({ volume7Days }) => -1 * volume7Days)
|
|
|
|
matches = sortBy(matches, ({ volume24Hours }) => -1 * volume24Hours)
|
|
|
|
}
|
|
|
|
|
2022-06-24 17:08:06 +00:00
|
|
|
if (additionalFilter) {
|
2022-08-05 19:01:16 +00:00
|
|
|
const { creatorId, tag, groupSlug, excludeContractIds } = additionalFilter
|
2022-06-24 17:08:06 +00:00
|
|
|
|
|
|
|
if (creatorId) {
|
|
|
|
matches = matches.filter((c) => c.creatorId === creatorId)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tag) {
|
|
|
|
matches = matches.filter((c) =>
|
|
|
|
c.lowercaseTags.includes(tag.toLowerCase())
|
|
|
|
)
|
|
|
|
}
|
2022-08-05 19:01:16 +00:00
|
|
|
|
|
|
|
if (groupSlug) {
|
|
|
|
matches = matches.filter((c) => c.groupSlugs?.includes(groupSlug))
|
|
|
|
}
|
|
|
|
|
|
|
|
if (excludeContractIds) {
|
|
|
|
matches = matches.filter((c) => !excludeContractIds.includes(c.id))
|
|
|
|
}
|
2022-06-24 17:08:06 +00:00
|
|
|
}
|
|
|
|
|
2022-07-01 16:26:45 +00:00
|
|
|
matches = matches.slice(0, MAX_CONTRACTS_RENDERED)
|
|
|
|
|
2022-06-23 17:12:57 +00:00
|
|
|
const showTime = ['close-date', 'closed'].includes(sort)
|
|
|
|
? 'close-date'
|
|
|
|
: sort === 'resolve-date'
|
|
|
|
? 'resolve-date'
|
|
|
|
: undefined
|
|
|
|
|
2022-06-14 09:35:51 +00:00
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
{/* Show a search input next to a sort dropdown */}
|
|
|
|
<div className="mt-2 mb-8 flex justify-between gap-2">
|
2022-10-10 02:37:24 +00:00
|
|
|
<Input
|
2022-06-14 09:35:51 +00:00
|
|
|
type="text"
|
|
|
|
value={query}
|
|
|
|
onChange={(e) => setQuery(e.target.value)}
|
|
|
|
placeholder="Search markets"
|
2022-10-10 02:37:24 +00:00
|
|
|
className="w-full"
|
2022-06-14 09:35:51 +00:00
|
|
|
/>
|
2022-10-13 18:23:42 +00:00
|
|
|
<Select value={sort} onChange={(e) => setSort(e.target.value)}>
|
2022-08-01 15:03:46 +00:00
|
|
|
<option value="score">Trending</option>
|
2022-08-07 23:43:53 +00:00
|
|
|
<option value="newest">Newest</option>
|
2022-09-15 15:12:56 +00:00
|
|
|
<option value="most-traded">Most ${PAST_BETS}</option>
|
2022-06-14 09:35:51 +00:00
|
|
|
<option value="24-hour-vol">24h volume</option>
|
|
|
|
<option value="close-date">Closing soon</option>
|
2022-10-13 18:23:42 +00:00
|
|
|
</Select>
|
2022-06-14 09:35:51 +00:00
|
|
|
</div>
|
2022-08-09 22:28:27 +00:00
|
|
|
<ContractsGrid contracts={matches} showTime={showTime} />
|
2022-06-14 09:35:51 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|