SWR, improved vendors list

This commit is contained in:
2023-07-08 02:25:54 +04:00
parent 6090e97fa2
commit e487ad224c
6 changed files with 223 additions and 322 deletions

View File

@@ -1,6 +1,7 @@
export const getStaticPaths = async () => {
const url = new URL(`${process.env.NEXT_PUBLIC_DIRECTUS_API_URL}/items/pages`)
url.searchParams.append('fields[]', 'slug')
url.searchParams.append('limit', -1)
const res = await fetch(url.toString())
const { data: pages } = await res.json()

View File

@@ -1,18 +1,13 @@
import { ChakraProvider } from '@chakra-ui/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import Layout from '~/components/layout'
import theme from '~/src/theme'
const queryClient = new QueryClient()
export default function MyApp({ Component, pageProps }) {
return (
<QueryClientProvider client={queryClient}>
<ChakraProvider theme={theme}>
<Layout>
<Component {...pageProps} />
</Layout>
</ChakraProvider>
</QueryClientProvider>
<ChakraProvider theme={theme}>
<Layout>
<Component {...pageProps} />
</Layout>
</ChakraProvider>
)
}

View File

@@ -1,7 +1,32 @@
import { Link } from '@chakra-ui/next-js'
import { Card, CardBody, Heading, Image, LinkBox, LinkOverlay, SimpleGrid, Skeleton } from '@chakra-ui/react'
import { useQuery } from '@tanstack/react-query'
import {
Alert,
AlertIcon,
Box,
Button,
ButtonGroup,
Card,
CardBody,
Flex,
HStack,
Heading,
IconButton,
Image,
LinkBox,
LinkOverlay,
SimpleGrid,
Skeleton,
Spinner,
Table,
Tbody,
Td,
Text,
Tr,
} from '@chakra-ui/react'
import { useLocalStorageValue } from '@react-hookz/web'
import { useRouter } from 'next/router'
import { TbLayoutGrid, TbLayoutList } from 'react-icons/tb'
import useSWR from 'swr'
import Pagination from '~/components/pagination'
const PER_PAGE = 12
@@ -12,65 +37,157 @@ export default function VendorsPage() {
query: { page = 1 },
} = router
const { data, isFetching } = useQuery({
queryKey: ['vendors', page],
queryFn: async (...props2) => {
const url = new URL(`${process.env.NEXT_PUBLIC_DIRECTUS_API_URL}/items/vendors`)
url.searchParams.append('fields[]', '*')
url.searchParams.append('limit', PER_PAGE)
url.searchParams.append('page', page)
url.searchParams.append('sort', 'name')
url.searchParams.append('meta[]', 'filter_count')
const { value: perPage, set: setPerPage } = useLocalStorageValue('perPage', {
defaultValue: PER_PAGE,
initializeWithValue: false,
})
const res = await fetch(url.toString())
if (!res.ok) {
throw new Error('Oops')
}
const { value: layout, set: setLayout } = useLocalStorageValue('layout', {
defaultValue: 'GRID',
initializeWithValue: false,
})
return res.json()
},
keepPreviousData: true,
cacheTime: 1000 * 60 * 30,
staleTime: 1000 * 60 * 30,
const { data, error, isLoading, isValidating } = useSWR(['vendors', page, perPage], async () => {
// await new Promise((r) => setTimeout(r, 2000))
const url = new URL(`${process.env.NEXT_PUBLIC_DIRECTUS_API_URL}/items/vendors`)
url.searchParams.append('fields[]', '*')
url.searchParams.append('limit', perPage)
url.searchParams.append('page', page)
url.searchParams.append('sort', 'name')
url.searchParams.append('meta[]', 'filter_count')
const res = await fetch(url.toString())
if (!res.ok) {
throw new Error('Oops')
}
return res.json()
})
const { meta, data: vendors } = data || { meta: {}, data: [] }
return (
<div>
<Heading size="lg" my={8}>
Vendors
</Heading>
<Flex alignItems="center" justifyContent="space-between">
<Heading size="lg" my={8}>
Vendors
</Heading>
<Box>{isValidating && <Spinner />}</Box>
<ButtonGroup isAttached>
<IconButton icon={<TbLayoutGrid />} onClick={() => setLayout('GRID')} isDisabled={layout === 'GRID'} />
<IconButton icon={<TbLayoutList />} onClick={() => setLayout('LIST')} isDisabled={layout === 'LIST'} />
</ButtonGroup>
</Flex>
<SimpleGrid columns={[1, 2, 3, 4]} spacing={3}>
{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>
{error && (
<Alert status="error" marginY={3}>
<AlertIcon />
There was an error processing your request
</Alert>
)}
<Pagination page={Number(page)} itemsPerPage={PER_PAGE} totalItems={meta.filter_count} />
{layout === 'GRID' && (
<SimpleGrid columns={[1, 2, 3, 4]} spacing={3}>
{isLoading &&
new Array(perPage).fill(true).map((v, k) => (
<Card key={k}>
<Skeleton h="40" />
<CardBody>
<Skeleton h="6" mb="2" />
<Skeleton h="4" mb="1" />
<Skeleton h="4" />
</CardBody>
</Card>
))}
{!isLoading &&
vendors.map((v) => (
<LinkBox as={Card} rounded={4} key={v.id}>
<Image
roundedTop={4}
objectFit="cover"
src={`${process.env.NEXT_PUBLIC_DIRECTUS_API_URL}/assets/${v.logo}?key=logo-card`}
alt={v.name}
width="250"
height="150"
style={{ objectFit: 'contain', background: '#fff' }}
/>
<CardBody>
<LinkOverlay as={Link} href={`/vendors/${v.slug}`} prefetch={false}>
<Text mb="2" fontWeight="900">
{v.name}
</Text>
<Text fontSize="sm">
{v?.description?.substring(0, v?.description?.substring(0, 80).lastIndexOf(' '))} &hellip;
</Text>
</LinkOverlay>
</CardBody>
</LinkBox>
))}
</SimpleGrid>
)}
{layout === 'LIST' && (
<>
{isLoading && (
<Table>
<Tbody>
{new Array(perPage).fill(true).map((v, k) => (
<Tr key={k}>
<Td w="10%">
<Skeleton h="12" w="12" />
</Td>
<Td w="30%">
<Skeleton h="6" />
</Td>
<Td w="60%">
<Skeleton h="6" />
</Td>
</Tr>
))}
</Tbody>
</Table>
)}
{!isLoading && (
<Table>
<Tbody>
{vendors.map((v) => (
<Link key={v.id} href={`/vendors/${v.slug}`} prefetch={false} display="contents">
<Tr verticalAlign="middle">
<Td>
<Image
rounded="md"
src={`${process.env.NEXT_PUBLIC_DIRECTUS_API_URL}/assets/${v.logo}?key=logo-card`}
alt={v.name}
width="12"
height="12"
style={{ objectFit: 'contain', background: '#fff' }}
/>
</Td>
<Td>{v.name}</Td>
<Td>
<Text fontSize="sm">
{v?.description?.substring(0, v?.description?.substring(0, 80).lastIndexOf(' '))} &hellip;
</Text>
</Td>
</Tr>
</Link>
))}
</Tbody>
</Table>
)}
</>
)}
<Pagination page={Number(page)} itemsPerPage={perPage} totalItems={meta.filter_count} />
<HStack>
<Text>Results per page:</Text>
<ButtonGroup isAttached>
{[12, 24, 48].map((n) => (
<Button key={n} onClick={() => setPerPage(n)} isDisabled={perPage === n}>
{n}
</Button>
))}
</ButtonGroup>
</HStack>
</div>
)
}