WIP: Pagination
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
import { ChakraProvider } from '@chakra-ui/react'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import Layout from '~/components/layout'
|
||||
import theme from './theme'
|
||||
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<ChakraProvider>
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</ChakraProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ChakraProvider theme={theme}>
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</ChakraProvider>
|
||||
</QueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
40
frontend/pages/theme.js
Normal file
40
frontend/pages/theme.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { extendTheme } from '@chakra-ui/react'
|
||||
import { defineStyle, defineStyleConfig } from '@chakra-ui/react'
|
||||
|
||||
const pagination = defineStyle({
|
||||
whiteSpace: 'nowrap',
|
||||
bg: 'transparent',
|
||||
gap: 3,
|
||||
paddingInlineStart: 3,
|
||||
paddingInlineEnd: 3,
|
||||
lineHeight: 10,
|
||||
borderRadius: 'md',
|
||||
border: '1px solid',
|
||||
borderColor: 'inherit',
|
||||
width: '100%',
|
||||
_hover: {
|
||||
textDecor: 'none',
|
||||
},
|
||||
'&.current': {
|
||||
bg: 'var(--chakra-colors-gray-300)',
|
||||
border: '1px solid transparent',
|
||||
},
|
||||
_dark: {
|
||||
bg: 'var(--chakra-colors-gray-900)',
|
||||
'&.current': {
|
||||
bg: 'var(--chakra-colors-gray-700)',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const linkTheme = defineStyleConfig({
|
||||
variants: { pagination },
|
||||
})
|
||||
|
||||
const theme = extendTheme({
|
||||
components: {
|
||||
Link: linkTheme,
|
||||
},
|
||||
})
|
||||
|
||||
export default theme
|
||||
139
frontend/pages/vendors/index.js
vendored
139
frontend/pages/vendors/index.js
vendored
@@ -1,108 +1,73 @@
|
||||
import {
|
||||
Pagination,
|
||||
PaginationContainer,
|
||||
PaginationNext,
|
||||
PaginationPage,
|
||||
PaginationPageGroup,
|
||||
PaginationPrevious,
|
||||
usePagination,
|
||||
} from '@ajna/pagination'
|
||||
import { Link } from '@chakra-ui/next-js'
|
||||
import { Card, CardBody, Heading, Image, LinkBox, LinkOverlay, SimpleGrid, Text } from '@chakra-ui/react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import directus from '~/lib/directus'
|
||||
import { Card, CardBody, Heading, Image, LinkBox, LinkOverlay, SimpleGrid, Text, Skeleton } from '@chakra-ui/react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useRouter } from 'next/router'
|
||||
import Pagination from '~/components/pagination'
|
||||
|
||||
const PER_PAGE = 12
|
||||
|
||||
export const getServerSideProps = async ({ query }) => {
|
||||
const page = query?.page || 1
|
||||
const sort = query?.sort || 'name'
|
||||
|
||||
const { data: vendors, meta } = await directus.items('vendors').readByQuery({
|
||||
fields: [
|
||||
//
|
||||
'*',
|
||||
],
|
||||
limit: PER_PAGE,
|
||||
page,
|
||||
meta: ['filter_count'],
|
||||
sort,
|
||||
})
|
||||
return { props: { vendors, meta, page } }
|
||||
}
|
||||
|
||||
export default function VendorsPage({ vendors, meta, page }) {
|
||||
export default function VendorsPage() {
|
||||
const router = useRouter()
|
||||
const {
|
||||
query: { page = 1 },
|
||||
} = router
|
||||
|
||||
const { pages, pagesCount, currentPage, setCurrentPage, isDisabled } = usePagination({
|
||||
total: meta.filter_count,
|
||||
limits: {
|
||||
outer: 1,
|
||||
inner: 1,
|
||||
},
|
||||
initialState: {
|
||||
pageSize: PER_PAGE,
|
||||
isDisabled: false,
|
||||
currentPage: page,
|
||||
const { data, isFetching } = useQuery({
|
||||
queryKey: ['vendors', page],
|
||||
queryFn: async (...props2) => {
|
||||
await new Promise((r) => setTimeout(r, 2000))
|
||||
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_DIRECTUS_API_URL}/items/vendors?fields[]=*&limit=12&page=${page}&meta[]=filter_count&sort=name`
|
||||
)
|
||||
if (!res.ok) {
|
||||
throw new Error('wrong')
|
||||
}
|
||||
|
||||
return res.json()
|
||||
},
|
||||
keepPreviousData: true,
|
||||
cacheTime: 1000 * 60 * 30,
|
||||
staleTime: 1000 * 60 * 30,
|
||||
})
|
||||
|
||||
const handlePageChange = (nextPage) => {
|
||||
setCurrentPage(nextPage)
|
||||
router.replace(`?page=${nextPage}`)
|
||||
}
|
||||
const { meta, data: vendors } = data || { meta: {}, data: [] }
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Heading size="lg" my={8}>
|
||||
Vendors
|
||||
</Heading>
|
||||
|
||||
<SimpleGrid columns={[1, 2, 3, 4]} spacing={3}>
|
||||
{vendors.map((v) => (
|
||||
<LinkBox as={Card} rounded={4} key={v.id}>
|
||||
<Image
|
||||
roundedTop={4}
|
||||
objectFit="cover"
|
||||
src="https://images.unsplash.com/photo-1531403009284-440f080d1e12?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=250&q=80"
|
||||
alt="Chakra UI"
|
||||
/>
|
||||
<CardBody>
|
||||
<LinkOverlay as={Link} href={`/vendors/${v.slug}`} prefetch={false}>
|
||||
{v.name}
|
||||
</LinkOverlay>
|
||||
</CardBody>
|
||||
</LinkBox>
|
||||
))}
|
||||
{isFetching &&
|
||||
new Array(PER_PAGE).fill(true).map((v, k) => (
|
||||
<Card key={k}>
|
||||
<Skeleton h="40" />
|
||||
<CardBody>
|
||||
<Skeleton h="4" />
|
||||
</CardBody>
|
||||
</Card>
|
||||
))}
|
||||
{!isFetching &&
|
||||
vendors.map((v) => (
|
||||
<LinkBox as={Card} rounded={4} key={v.id}>
|
||||
<Image
|
||||
roundedTop={4}
|
||||
objectFit="cover"
|
||||
src="https://images.unsplash.com/photo-1531403009284-440f080d1e12?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=250&q=80"
|
||||
alt={v.name}
|
||||
/>
|
||||
<CardBody>
|
||||
<LinkOverlay as={Link} href={`/vendors/${v.slug}`} prefetch={false}>
|
||||
{v.name}
|
||||
</LinkOverlay>
|
||||
</CardBody>
|
||||
</LinkBox>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
|
||||
<Pagination
|
||||
pagesCount={pagesCount}
|
||||
currentPage={currentPage}
|
||||
isDisabled={isDisabled}
|
||||
onPageChange={handlePageChange}
|
||||
>
|
||||
<PaginationContainer align="center" my={4} w={'full'} justifyContent={'space-between'}>
|
||||
<PaginationPrevious>
|
||||
<Text>«</Text>
|
||||
</PaginationPrevious>
|
||||
<PaginationPageGroup align="center" mx={4}>
|
||||
{pages.map((page) => (
|
||||
<PaginationPage
|
||||
w={10}
|
||||
key={`pagination_page_${page}`}
|
||||
page={page}
|
||||
fontSize="sm"
|
||||
_current={{
|
||||
bg: 'gray.400',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</PaginationPageGroup>
|
||||
<PaginationNext>
|
||||
<Text>»</Text>
|
||||
</PaginationNext>
|
||||
</PaginationContainer>
|
||||
</Pagination>
|
||||
<Pagination page={Number(page)} itemsPerPage={PER_PAGE} totalItems={meta.filter_count} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user