Paginate bets list
This commit is contained in:
parent
5c6a143614
commit
162e73912e
|
@ -1,7 +1,7 @@
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { uniq, groupBy, mapValues, sortBy, partition, sumBy } from 'lodash'
|
import { uniq, groupBy, mapValues, sortBy, partition, sumBy } from 'lodash'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
import { Bet } from 'web/lib/firebase/bets'
|
import { Bet } from 'web/lib/firebase/bets'
|
||||||
|
@ -46,10 +46,13 @@ import { SellSharesModal } from './sell-modal'
|
||||||
import { useUnfilledBets } from 'web/hooks/use-bets'
|
import { useUnfilledBets } from 'web/hooks/use-bets'
|
||||||
import { LimitBet } from 'common/bet'
|
import { LimitBet } from 'common/bet'
|
||||||
import { floatingEqual } from 'common/util/math'
|
import { floatingEqual } from 'common/util/math'
|
||||||
|
import { Pagination } from './pagination'
|
||||||
|
|
||||||
type BetSort = 'newest' | 'profit' | 'closeTime' | 'value'
|
type BetSort = 'newest' | 'profit' | 'closeTime' | 'value'
|
||||||
type BetFilter = 'open' | 'sold' | 'closed' | 'resolved' | 'all'
|
type BetFilter = 'open' | 'sold' | 'closed' | 'resolved' | 'all'
|
||||||
|
|
||||||
|
const CONTRACTS_PER_PAGE = 20
|
||||||
|
|
||||||
export function BetsList(props: {
|
export function BetsList(props: {
|
||||||
user: User
|
user: User
|
||||||
bets: Bet[] | undefined
|
bets: Bet[] | undefined
|
||||||
|
@ -62,13 +65,17 @@ export function BetsList(props: {
|
||||||
|
|
||||||
// Hide bets before 06-01-2022 if this isn't your own profile
|
// Hide bets before 06-01-2022 if this isn't your own profile
|
||||||
// NOTE: This means public profits also begin on 06-01-2022 as well.
|
// NOTE: This means public profits also begin on 06-01-2022 as well.
|
||||||
const bets = allBets?.filter(
|
const bets = useMemo(
|
||||||
(bet) => bet.createdTime >= (hideBetsBefore ?? 0)
|
() => allBets?.filter((bet) => bet.createdTime >= (hideBetsBefore ?? 0)),
|
||||||
|
[allBets, hideBetsBefore]
|
||||||
)
|
)
|
||||||
const [contracts, setContracts] = useState<Contract[] | undefined>()
|
const [contracts, setContracts] = useState<Contract[] | undefined>()
|
||||||
|
|
||||||
const [sort, setSort] = useState<BetSort>('newest')
|
const [sort, setSort] = useState<BetSort>('newest')
|
||||||
const [filter, setFilter] = useState<BetFilter>('open')
|
const [filter, setFilter] = useState<BetFilter>('open')
|
||||||
|
const [page, setPage] = useState(0)
|
||||||
|
const start = page * CONTRACTS_PER_PAGE
|
||||||
|
const end = start + CONTRACTS_PER_PAGE
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (bets) {
|
if (bets) {
|
||||||
|
@ -85,16 +92,14 @@ export function BetsList(props: {
|
||||||
disposed = true
|
disposed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [bets])
|
||||||
}, [allBets, hideBetsBefore])
|
|
||||||
|
|
||||||
const getTime = useTimeSinceFirstRender()
|
const getTime = useTimeSinceFirstRender()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (bets && contracts) {
|
if (bets && contracts) {
|
||||||
trackLatency('portfolio', getTime())
|
trackLatency('portfolio', getTime())
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [bets, contracts, getTime])
|
||||||
}, [!!bets, !!contracts])
|
|
||||||
|
|
||||||
if (!bets || !contracts) {
|
if (!bets || !contracts) {
|
||||||
return <LoadingIndicator />
|
return <LoadingIndicator />
|
||||||
|
@ -130,7 +135,7 @@ export function BetsList(props: {
|
||||||
(filter === 'open' ? -1 : 1) *
|
(filter === 'open' ? -1 : 1) *
|
||||||
(c.resolutionTime ?? c.closeTime ?? Infinity),
|
(c.resolutionTime ?? c.closeTime ?? Infinity),
|
||||||
}
|
}
|
||||||
const displayedContracts = sortBy(contracts, SORTS[sort])
|
const filteredContracts = sortBy(contracts, SORTS[sort])
|
||||||
.reverse()
|
.reverse()
|
||||||
.filter(FILTERS[filter])
|
.filter(FILTERS[filter])
|
||||||
.filter((c) => {
|
.filter((c) => {
|
||||||
|
@ -141,6 +146,7 @@ export function BetsList(props: {
|
||||||
if (filter === 'sold') return !hasShares
|
if (filter === 'sold') return !hasShares
|
||||||
return hasShares
|
return hasShares
|
||||||
})
|
})
|
||||||
|
const displayedContracts = filteredContracts.slice(start, end)
|
||||||
|
|
||||||
const unsettled = contracts.filter(
|
const unsettled = contracts.filter(
|
||||||
(c) => !c.isResolved && contractsMetrics[c.id].invested !== 0
|
(c) => !c.isResolved && contractsMetrics[c.id].invested !== 0
|
||||||
|
@ -227,6 +233,13 @@ export function BetsList(props: {
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
|
<Pagination
|
||||||
|
page={page}
|
||||||
|
itemsPerPage={CONTRACTS_PER_PAGE}
|
||||||
|
totalItems={filteredContracts.length}
|
||||||
|
setPage={setPage}
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
42
web/components/pagination.tsx
Normal file
42
web/components/pagination.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
export function Pagination(props: {
|
||||||
|
page: number
|
||||||
|
itemsPerPage: number
|
||||||
|
totalItems: number
|
||||||
|
setPage: (page: number) => void
|
||||||
|
}) {
|
||||||
|
const { page, itemsPerPage, totalItems, setPage } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav
|
||||||
|
className="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6"
|
||||||
|
aria-label="Pagination"
|
||||||
|
>
|
||||||
|
<div className="hidden sm:block">
|
||||||
|
<p className="text-sm text-gray-700">
|
||||||
|
Showing{' '}
|
||||||
|
<span className="font-medium">
|
||||||
|
{page === 0 ? page + 1 : page * itemsPerPage}
|
||||||
|
</span>{' '}
|
||||||
|
to <span className="font-medium">{(page + 1) * itemsPerPage}</span> of{' '}
|
||||||
|
<span className="font-medium">{totalItems}</span> results
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-1 justify-between sm:justify-end">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
className="relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
||||||
|
onClick={() => page > 1 && setPage(page - 1)}
|
||||||
|
>
|
||||||
|
Previous
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
className="relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
||||||
|
onClick={() => page < totalItems / itemsPerPage && setPage(page + 1)}
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user