Merge pull request #37 from Nez27/feat/add-pagination-component

Add pagincation components and update code for table, orderBy, modal components
This commit is contained in:
Loi Phan
2023-11-29 14:48:04 +07:00
committed by GitHub
9 changed files with 176 additions and 21 deletions
@@ -36,7 +36,7 @@ const Button = styled.button<IButtonStyle>`
&:disabled,
&[disabled] {
cursor: no-drop;
cursor: not-allowed;
}
`;
@@ -6,13 +6,6 @@ const StyledModal = styled.div`
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--color-grey-0);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-lg);
padding: 3.2rem 4rem;
transition: all 0.5s;
`;
@@ -26,7 +26,6 @@ const OrderBy = ({ options }: IOrderProps) => {
<OrderButton
key={option.value}
onClick={() => handleClick(option.value)}
active={option.value === currentOrder}
disabled={option.value === currentOrder}
>
{option.label}
@@ -9,7 +9,7 @@ const StyledOrder = styled.div`
`;
interface IOrderBtn {
active: boolean;
disabled: boolean;
}
const OrderButton = styled.button<IOrderBtn>`
@@ -25,11 +25,11 @@ const OrderButton = styled.button<IOrderBtn>`
padding: 5px 10px;
${(props) =>
props.active &&
props.disabled &&
css`
background-color: var(--primary-color);
color: var(--light-text);
cursor: no-drop;
cursor: not-allowed;
`}
&:hover:not(:disabled) {
@@ -0,0 +1,80 @@
import { useCallback, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
// Constants
import { DEFAULT_PAGE_SIZE } from '@constant/config';
// Styled
import { Buttons, PaginationBtn, StyledPagination } from './styled';
// Components
import { MdKeyboardArrowRight, MdKeyboardArrowLeft } from 'react-icons/md';
interface IPagination {
count: number;
}
const Pagination = ({ count }: IPagination) => {
const [searchParams, setSearchParams] = useSearchParams();
const currentPage = !searchParams.get('page')
? 1
: Number(searchParams.get('page'));
const totalPage = Math.ceil(count / DEFAULT_PAGE_SIZE);
const nextPage = useCallback(() => {
const next = currentPage === totalPage
? currentPage
: currentPage + 1;
searchParams.set('page', next.toString());
setSearchParams(searchParams);
}, [currentPage, searchParams, totalPage, setSearchParams]);
const previousPage = useCallback(() => {
const previous = currentPage === 1
? currentPage
: currentPage - 1;
searchParams.set('page', previous.toString());
setSearchParams(searchParams);
}, [currentPage, searchParams, setSearchParams]);
const fromIndex = useMemo(
() => (currentPage - 1) * DEFAULT_PAGE_SIZE + 1,
[currentPage]
);
const toIndex = useMemo(
() => (currentPage === totalPage
? count
: currentPage * DEFAULT_PAGE_SIZE),
[currentPage, count, totalPage]
);
return (
totalPage > 1 && (
<StyledPagination>
<p>
Showing {fromIndex} to {toIndex} of <span>{count}</span> results
</p>
<Buttons>
<PaginationBtn onClick={previousPage} disabled={currentPage === 1}>
<MdKeyboardArrowLeft /> <span>Previous</span>
</PaginationBtn>
<PaginationBtn
onClick={nextPage}
disabled={currentPage === totalPage}
>
<span>Next</span>
<MdKeyboardArrowRight />
</PaginationBtn>
</Buttons>
</StyledPagination>
)
);
};
export default Pagination;
@@ -0,0 +1,50 @@
import styled from 'styled-components';
interface IPaginationBtn {
disabled: boolean;
}
const StyledPagination = styled.div`
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
font-size: var(--fs-sm-x);
`;
const Buttons = styled.div`
display: flex;
gap: 30px;
`;
const PaginationBtn = styled.button<IPaginationBtn>`
background-color: var(--secondary-btn-color);
border: none;
border-radius: var(--radius-sm);
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
padding: 5px 10px;
transition: all 0.3s;
& svg {
height: 20px;
width: 20px;
}
&:hover:not(:disabled) {
background-color: var(--primary-color);
color: var(--light-text);
}
&:disabled {
cursor: not-allowed;
}
`;
export { StyledPagination, PaginationBtn, Buttons };
@@ -1,7 +1,13 @@
import { ReactNode, useContext } from 'react';
// Components
import { StyledBody, StyledHeader, StyledRow, StyledTable } from './styled';
// Styled
import {
StyledBody,
StyledHeader,
StyledRow,
StyledTable,
StyledFooter,
} from './styled';
// Contexts
import TableContext from '@context/TableContext';
@@ -33,9 +39,13 @@ const Table = ({ columns, children }: ITable) => {
const Header = ({ headerColumn }: IHeader) => {
const { columns } = useContext(TableContext);
return <StyledHeader columns={columns}>
{headerColumn.map((item) => <div key={item}>{item}</div>)}
</StyledHeader>;
return (
<StyledHeader columns={columns}>
{headerColumn.map((item) => (
<div key={item}>{item}</div>
))}
</StyledHeader>
);
};
const Body = <T,>({ data, render }: ITableBody<T>) => {
@@ -55,5 +65,6 @@ const Row = ({ children }: ITable) => {
Table.Header = Header;
Table.Body = Body;
Table.Row = Row;
Table.Footer = StyledFooter;
export default Table;
@@ -43,4 +43,19 @@ const StyledHeader = styled(CommonRow)`
font-weight: 600;
`;
export { StyledBody, StyledHeader, StyledRow, StyledTable };
const StyledFooter = styled.div`
display: flex;
justify-content: center;
padding: 15px;
background-color: var(--footer-table-color);
border-bottom-left-radius: var(--radius-md);
border-bottom-right-radius: var(--radius-md);
border-top: 1px solid var(--border-color);
&:not(:has(*)) {
display: none;
}
`;
export { StyledBody, StyledHeader, StyledRow, StyledTable, StyledFooter };
+10 -3
View File
@@ -1,6 +1,13 @@
const DEFAULT_SORT_BY = 'id';
const DEFAULT_ORDER_BY = 'asc';
const supabaseUrl = 'https://pjqujsjzzdrlrgqbxepe.supabase.co'
const supabaseKey = process.env.VITE_SUPABASE_KEY
const DEFAULT_PAGE_SIZE = 5;
const supabaseUrl = 'https://pjqujsjzzdrlrgqbxepe.supabase.co';
const supabaseKey = process.env.VITE_SUPABASE_KEY;
export { DEFAULT_SORT_BY, DEFAULT_ORDER_BY, supabaseKey, supabaseUrl };
export {
DEFAULT_SORT_BY,
DEFAULT_ORDER_BY,
supabaseKey,
supabaseUrl,
DEFAULT_PAGE_SIZE,
};