Browse Source

feat: added filter, sort and new design to pagination

hover-contact
ntasicc 3 years ago
parent
commit
a042c72b9a

+ 132
- 16
components/pagination/react-query/PaginationComponentRQ.jsx View File

@@ -1,29 +1,145 @@
import {
Box,
Button,
Divider,
FormControl,
Grid,
InputLabel,
MenuItem,
Paper,
Select,
TextField,
Typography,
} from '@mui/material';
import { useTranslation } from 'next-i18next';
import { useState } from 'react';
import useDebounce from '../../../hooks/use-debounce';
import { usePagination } from '../../../hooks/use-pagination';
import { compare } from '../../../utils/helpers/sortHelpers';

const PaginationComponentRQ = () => {
const [pageIndex, setPageIndex] = useState(1);

const [filter, setFilter] = useState('');
const [sort, setSort] = useState('');
const { t } = useTranslation('pagination');
const { data: paginationData } = usePagination(pageIndex);

const debouncedFilter = useDebounce(filter, 500);

const handleFilterTextChange = (event) => {
const filterText = event.target.value;
setFilter(filterText);
};

const handleSortChange = (event) => {
const sort = event.target.value;
setSort(sort);
};

const dataToDisplay = paginationData?.data
.filter((item) =>
item.name.toLowerCase().startsWith(debouncedFilter.toLowerCase())
)
.sort((a, b) => compare(a.name, b.name, sort))
.map((item, index) => (
// ! DON'T USE index for key, this is for example only
<Grid item sx={{ p: 2 }} xs={12} sm={6} md={4} lg={3} key={index}>
{/* TODO separate into component */}
<Paper sx={{ p: 3, height: '100%' }} elevation={3}>
<Typography sx={{ fontWeight: 600 }}>{t('Name')}</Typography>
<Typography display="inline"> {item.name}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>{t('Age')}</Typography>
<Typography display="inline"> {item.age}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>{t('Gender')}</Typography>
<Typography display="inline"> {item.gender}</Typography>
<Divider />
</Paper>
</Grid>
));

return (
<div>
{paginationData?.data.map((item) => (
<div key={item._id}>{item.name}</div>
))}
<button
disabled={pageIndex === 1}
onClick={() => setPageIndex(pageIndex - 1)}
<Paper
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'start',
py: 2,
minHeight: 400,
marginTop: 5,
}}
elevation={5}
>
<Typography sx={{ my: 4 }} variant="h4" gutterBottom align="center">
{t('Title')}
</Typography>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
flexWrap: 'wrap',
mx: 2,
}}
>
Previous
</button>
<button
disabled={pageIndex * 5 > paginationData?.dataCount}
onClick={() => setPageIndex(pageIndex + 1)}
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
width: '100%',
}}
>
<FormControl sx={{ flexGrow: 1 }}>
<InputLabel id="sort-label">Sort</InputLabel>
<Select
label="Sort"
labelId="sort-label"
id="sort-select-helper"
value={sort}
onChange={handleSortChange}
>
<MenuItem value="asc">Name - A-Z</MenuItem>
<MenuItem value="desc">Name - Z-A</MenuItem>
</Select>
</FormControl>
<TextField
sx={{ flexGrow: 1 }}
variant="outlined"
label="Filter"
placeholder="Filter"
value={filter}
onChange={handleFilterTextChange}
/>
</Box>
</Box>
<Grid container>{dataToDisplay}</Grid>
<Box
sx={{
width: '100%',
textAlign: 'center',
marginTop: 3,
}}
>
Next
</button>
</div>
<Button
disabled={pageIndex === 1}
onClick={() => setPageIndex(pageIndex - 1)}
sx={{
marginRight: 5,
}}
>
{t('Btns.PrevBtn')}
</Button>
<Button
disabled={pageIndex * 4 > paginationData?.dataCount}
onClick={() => setPageIndex(pageIndex + 1)}
sx={{
marginRight: 5,
}}
>
{t('Btns.NextBtn')}
</Button>
</Box>
</Paper>
);
};


+ 17
- 0
hooks/use-debounce.js View File

@@ -0,0 +1,17 @@
import { useEffect, useState } from 'react';

const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);

useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay || 500);

return () => {
clearTimeout(timer);
};
}, [value, delay]);

return debouncedValue;
};

export default useDebounce;

+ 3
- 3
pages/api/data.js View File

@@ -19,7 +19,7 @@ async function handler(req, res) {

const dataCount = await db.collection('randomData').countDocuments();

if ((pageIndex - 1) * 5 >= dataCount) {
if ((pageIndex - 1) * 4 >= dataCount) {
res.status(422).json({
message: 'Page does not exist ',
});
@@ -30,8 +30,8 @@ async function handler(req, res) {
const dataFromDB = await db
.collection('randomData')
.find()
.skip((pageIndex - 1) * 5)
.limit(5)
.skip((pageIndex - 1) * 4)
.limit(4)
.toArray();

if (!dataFromDB) {

+ 3
- 2
pages/index.js View File

@@ -1,17 +1,17 @@
import { dehydrate, QueryClient } from '@tanstack/react-query';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import PaginationComponentRQ from '../components/pagination/react-query/PaginationComponentRQ';
import { getData } from '../requests/dataRequest';

const Home = () => {
return (
<>
<h1>Home</h1>
<PaginationComponentRQ></PaginationComponentRQ>
</>
);
};

export async function getServerSideProps() {
export async function getStaticProps({ locale }) {
const queryClient = new QueryClient();

await queryClient.prefetchQuery(['randomData', 1], () => getData(1));
@@ -19,6 +19,7 @@ export async function getServerSideProps() {
return {
props: {
dehydratedState: dehydrate(queryClient),
...(await serverSideTranslations(locale, ['pagination'])),
},
};
}

+ 12
- 0
public/locales/en/pagination.json View File

@@ -0,0 +1,12 @@
{
"Title": "Pagination, Filtering and Sorting",
"Card": {
"Name": "Name: ",
"Age": "Age: ",
"Gender": "Gender: "
},
"Btns": {
"NextBtn": "Next",
"PrevBtn": "Previous"
}
}

+ 11
- 0
utils/helpers/sortHelpers.js View File

@@ -0,0 +1,11 @@
export const compare = (a, b, sort) => {
if (sort === 'asc') {
if (a > b) return 1;
else if (b > a) return -1;
return 0;
} else if (sort === 'desc') {
if (a > b) return -1;
else if (b > a) return 1;
return 0;
}
};

Loading…
Cancel
Save