Sort & query url params (#17)
* Sort query in progress * Search and query url params!
This commit is contained in:
parent
b375256e96
commit
bad7a2b543
|
@ -3,17 +3,13 @@ import Link from 'next/link'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import {
|
import { compute, Contract, listContracts } from '../lib/firebase/contracts'
|
||||||
compute,
|
|
||||||
Contract,
|
|
||||||
listContracts,
|
|
||||||
path,
|
|
||||||
} from '../lib/firebase/contracts'
|
|
||||||
import { User } from '../lib/firebase/users'
|
import { User } from '../lib/firebase/users'
|
||||||
import { Col } from './layout/col'
|
import { Col } from './layout/col'
|
||||||
import { SiteLink } from './site-link'
|
import { SiteLink } from './site-link'
|
||||||
import { parseTags } from '../lib/util/parse'
|
import { parseTags } from '../lib/util/parse'
|
||||||
import { ContractCard } from './contract-card'
|
import { ContractCard } from './contract-card'
|
||||||
|
import { Sort, useQueryAndSortParams } from '../hooks/use-sort-and-query-params'
|
||||||
|
|
||||||
function ContractsGrid(props: { contracts: Contract[] }) {
|
function ContractsGrid(props: { contracts: Contract[] }) {
|
||||||
const [resolvedContracts, activeContracts] = _.partition(
|
const [resolvedContracts, activeContracts] = _.partition(
|
||||||
|
@ -61,7 +57,7 @@ function CreatorContractsGrid(props: { contracts: Contract[] }) {
|
||||||
const { creatorUsername, creatorName } = byCreator[creatorId][0]
|
const { creatorUsername, creatorName } = byCreator[creatorId][0]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className="gap-4">
|
<Col className="gap-4" key={creatorUsername}>
|
||||||
<SiteLink className="text-lg" href={`/${creatorUsername}`}>
|
<SiteLink className="text-lg" href={`/${creatorUsername}`}>
|
||||||
{creatorName}
|
{creatorName}
|
||||||
</SiteLink>
|
</SiteLink>
|
||||||
|
@ -116,7 +112,7 @@ function TagContractsGrid(props: { contracts: Contract[] }) {
|
||||||
<Col className="gap-6">
|
<Col className="gap-6">
|
||||||
{tags.map((tag) => {
|
{tags.map((tag) => {
|
||||||
return (
|
return (
|
||||||
<Col className="gap-4">
|
<Col className="gap-4" key={tag}>
|
||||||
<SiteLink className="text-lg" href={`/tag/${tag}`}>
|
<SiteLink className="text-lg" href={`/tag/${tag}`}>
|
||||||
#{tag}
|
#{tag}
|
||||||
</SiteLink>
|
</SiteLink>
|
||||||
|
@ -152,17 +148,15 @@ function TagContractsGrid(props: { contracts: Contract[] }) {
|
||||||
|
|
||||||
const MAX_CONTRACTS_DISPLAYED = 99
|
const MAX_CONTRACTS_DISPLAYED = 99
|
||||||
|
|
||||||
type Sort = 'creator' | 'tag' | 'createdTime' | 'pool' | 'resolved' | 'all'
|
|
||||||
export function SearchableGrid(props: {
|
export function SearchableGrid(props: {
|
||||||
contracts: Contract[]
|
contracts: Contract[]
|
||||||
defaultSort?: Sort
|
query: string
|
||||||
|
setQuery: (query: string) => void
|
||||||
|
sort: Sort
|
||||||
|
setSort: (sort: Sort) => void
|
||||||
byOneCreator?: boolean
|
byOneCreator?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { contracts, defaultSort, byOneCreator } = props
|
const { contracts, query, setQuery, sort, setSort, byOneCreator } = props
|
||||||
const [query, setQuery] = useState('')
|
|
||||||
const [sort, setSort] = useState(
|
|
||||||
defaultSort || (byOneCreator ? 'pool' : 'creator')
|
|
||||||
)
|
|
||||||
|
|
||||||
function check(corpus: String) {
|
function check(corpus: String) {
|
||||||
return corpus.toLowerCase().includes(query.toLowerCase())
|
return corpus.toLowerCase().includes(query.toLowerCase())
|
||||||
|
@ -175,9 +169,9 @@ export function SearchableGrid(props: {
|
||||||
check(c.creatorUsername)
|
check(c.creatorUsername)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (sort === 'createdTime' || sort === 'resolved' || sort === 'all') {
|
if (sort === 'newest' || sort === 'resolved' || sort === 'all') {
|
||||||
matches.sort((a, b) => b.createdTime - a.createdTime)
|
matches.sort((a, b) => b.createdTime - a.createdTime)
|
||||||
} else if (sort === 'pool' || sort === 'creator' || sort === 'tag') {
|
} else if (sort === 'most-traded' || sort === 'creator' || sort === 'tag') {
|
||||||
matches.sort((a, b) => compute(b).truePool - compute(a).truePool)
|
matches.sort((a, b) => compute(b).truePool - compute(a).truePool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,8 +207,8 @@ export function SearchableGrid(props: {
|
||||||
<option value="creator">By creator</option>
|
<option value="creator">By creator</option>
|
||||||
)}
|
)}
|
||||||
<option value="tag">By tag</option>
|
<option value="tag">By tag</option>
|
||||||
<option value="pool">Most traded</option>
|
<option value="most-traded">Most traded</option>
|
||||||
<option value="createdTime">Newest first</option>
|
<option value="newest">Newest</option>
|
||||||
<option value="resolved">Resolved</option>
|
<option value="resolved">Resolved</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -234,6 +228,10 @@ export function CreatorContractsList(props: { creator: User }) {
|
||||||
const { creator } = props
|
const { creator } = props
|
||||||
const [contracts, setContracts] = useState<Contract[] | 'loading'>('loading')
|
const [contracts, setContracts] = useState<Contract[] | 'loading'>('loading')
|
||||||
|
|
||||||
|
const { query, setQuery, sort, setSort } = useQueryAndSortParams({
|
||||||
|
defaultSort: 'all',
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (creator?.id) {
|
if (creator?.id) {
|
||||||
// TODO: stream changes from firestore
|
// TODO: stream changes from firestore
|
||||||
|
@ -243,5 +241,14 @@ export function CreatorContractsList(props: { creator: User }) {
|
||||||
|
|
||||||
if (contracts === 'loading') return <></>
|
if (contracts === 'loading') return <></>
|
||||||
|
|
||||||
return <SearchableGrid contracts={contracts} byOneCreator defaultSort="all" />
|
return (
|
||||||
|
<SearchableGrid
|
||||||
|
contracts={contracts}
|
||||||
|
byOneCreator
|
||||||
|
query={query}
|
||||||
|
setQuery={setQuery}
|
||||||
|
sort={sort}
|
||||||
|
setSort={setSort}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
40
web/hooks/use-sort-and-query-params.tsx
Normal file
40
web/hooks/use-sort-and-query-params.tsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
|
export type Sort =
|
||||||
|
| 'creator'
|
||||||
|
| 'tag'
|
||||||
|
| 'newest'
|
||||||
|
| 'most-traded'
|
||||||
|
| 'resolved'
|
||||||
|
| 'all'
|
||||||
|
|
||||||
|
export function useQueryAndSortParams(options?: { defaultSort: Sort }) {
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const { s: sort, q: query } = router.query as {
|
||||||
|
q?: string
|
||||||
|
s?: Sort
|
||||||
|
}
|
||||||
|
|
||||||
|
const setSort = (sort: Sort | undefined) => {
|
||||||
|
router.query.s = sort
|
||||||
|
router.push(router, undefined, { shallow: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
const setQuery = (query: string | undefined) => {
|
||||||
|
if (query) {
|
||||||
|
router.query.q = query
|
||||||
|
} else {
|
||||||
|
delete router.query.q
|
||||||
|
}
|
||||||
|
|
||||||
|
router.push(router, undefined, { shallow: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sort: sort ?? options?.defaultSort ?? 'creator',
|
||||||
|
query: query ?? '',
|
||||||
|
setSort,
|
||||||
|
setQuery,
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import { SearchableGrid } from '../components/contracts-list'
|
||||||
import { Col } from '../components/layout/col'
|
import { Col } from '../components/layout/col'
|
||||||
import { NavBar } from '../components/nav-bar'
|
import { NavBar } from '../components/nav-bar'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import { useQueryAndSortParams } from '../hooks/use-sort-and-query-params'
|
||||||
|
|
||||||
export default function LandingPage() {
|
export default function LandingPage() {
|
||||||
return (
|
return (
|
||||||
|
@ -159,13 +160,20 @@ function FeaturesSection() {
|
||||||
|
|
||||||
function ExploreMarketsSection() {
|
function ExploreMarketsSection() {
|
||||||
const contracts = useContracts()
|
const contracts = useContracts()
|
||||||
|
const { query, setQuery, sort, setSort } = useQueryAndSortParams()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-4xl px-4 py-8 mx-auto">
|
<div className="max-w-4xl px-4 py-8 mx-auto">
|
||||||
<p className="my-12 text-3xl leading-8 font-extrabold tracking-tight text-indigo-700 sm:text-4xl">
|
<p className="my-12 text-3xl leading-8 font-extrabold tracking-tight text-indigo-700 sm:text-4xl">
|
||||||
Explore our markets
|
Explore our markets
|
||||||
</p>
|
</p>
|
||||||
<SearchableGrid contracts={contracts === 'loading' ? [] : contracts} />
|
<SearchableGrid
|
||||||
|
contracts={contracts === 'loading' ? [] : contracts}
|
||||||
|
query={query}
|
||||||
|
setQuery={setQuery}
|
||||||
|
sort={sort}
|
||||||
|
setSort={setSort}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { SearchableGrid } from '../components/contracts-list'
|
import { SearchableGrid } from '../components/contracts-list'
|
||||||
import { Page } from '../components/page'
|
import { Page } from '../components/page'
|
||||||
import { useContracts } from '../hooks/use-contracts'
|
import { useContracts } from '../hooks/use-contracts'
|
||||||
|
import { useQueryAndSortParams } from '../hooks/use-sort-and-query-params'
|
||||||
import { Contract, listAllContracts } from '../lib/firebase/contracts'
|
import { Contract, listAllContracts } from '../lib/firebase/contracts'
|
||||||
|
|
||||||
export async function getStaticProps() {
|
export async function getStaticProps() {
|
||||||
|
@ -17,12 +18,17 @@ export async function getStaticProps() {
|
||||||
|
|
||||||
export default function Markets(props: { contracts: Contract[] }) {
|
export default function Markets(props: { contracts: Contract[] }) {
|
||||||
const contracts = useContracts()
|
const contracts = useContracts()
|
||||||
|
const { query, setQuery, sort, setSort } = useQueryAndSortParams()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
{(props.contracts || contracts !== 'loading') && (
|
{(props.contracts || contracts !== 'loading') && (
|
||||||
<SearchableGrid
|
<SearchableGrid
|
||||||
contracts={contracts === 'loading' ? props.contracts : contracts}
|
contracts={contracts === 'loading' ? props.contracts : contracts}
|
||||||
|
query={query}
|
||||||
|
setQuery={setQuery}
|
||||||
|
sort={sort}
|
||||||
|
setSort={setSort}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Page>
|
</Page>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { SearchableGrid } from '../../components/contracts-list'
|
||||||
import { Page } from '../../components/page'
|
import { Page } from '../../components/page'
|
||||||
import { Title } from '../../components/title'
|
import { Title } from '../../components/title'
|
||||||
import { useContracts } from '../../hooks/use-contracts'
|
import { useContracts } from '../../hooks/use-contracts'
|
||||||
|
import { useQueryAndSortParams } from '../../hooks/use-sort-and-query-params'
|
||||||
|
|
||||||
export default function TagPage() {
|
export default function TagPage() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
@ -18,13 +19,23 @@ export default function TagPage() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { query, setQuery, sort, setSort } = useQueryAndSortParams({
|
||||||
|
defaultSort: 'most-traded',
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<Title text={`#${tag}`} />
|
<Title text={`#${tag}`} />
|
||||||
{contracts === 'loading' ? (
|
{contracts === 'loading' ? (
|
||||||
<></>
|
<></>
|
||||||
) : (
|
) : (
|
||||||
<SearchableGrid contracts={contracts} />
|
<SearchableGrid
|
||||||
|
contracts={contracts}
|
||||||
|
query={query}
|
||||||
|
setQuery={setQuery}
|
||||||
|
sort={sort}
|
||||||
|
setSort={setSort}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user