From 69edf925fbeb53d79b8b8e2b4a99a6f02b891f84 Mon Sep 17 00:00:00 2001 From: ariari04 Date: Fri, 30 Aug 2024 13:46:23 +0600 Subject: [PATCH] Add pagination for tenders --- src/entities/TenderCard.tsx | 16 +- src/features/Pagination/Pagination.scss | 48 ++++++ src/features/Pagination/Pagination.tsx | 138 ++++++++++++++++++ src/features/Pagination/icons/arrow-left.svg | 7 + src/features/Pagination/icons/arrow-right.svg | 7 + src/widgets/TendersList/TendersList.tsx | 43 +++--- 6 files changed, 233 insertions(+), 26 deletions(-) create mode 100644 src/features/Pagination/Pagination.scss create mode 100644 src/features/Pagination/Pagination.tsx create mode 100644 src/features/Pagination/icons/arrow-left.svg create mode 100644 src/features/Pagination/icons/arrow-right.svg diff --git a/src/entities/TenderCard.tsx b/src/entities/TenderCard.tsx index 6703303..7991ee0 100644 --- a/src/entities/TenderCard.tsx +++ b/src/entities/TenderCard.tsx @@ -25,19 +25,17 @@ const TenderCard: React.FC = ({ }: Props) => { return (
-
+
- <Title - text={name_of_buy} - className="text-[18px] font-semibold leading-6 text-[#489FE1] mb-6" - /> - <Title - text={name_of_organization} - className="text-[18px] leading-6 font-normal" - /> + <h2 className="mb-6 text-[18px] font-semibold leading-6 text-blue"> + {name_of_buy} + </h2> + <h2 className="text-[18px] leading-6 font-normal "> + {name_of_organization} + </h2> </div> <div className="w-[285px]"></div> </div> diff --git a/src/features/Pagination/Pagination.scss b/src/features/Pagination/Pagination.scss new file mode 100644 index 0000000..6ee3836 --- /dev/null +++ b/src/features/Pagination/Pagination.scss @@ -0,0 +1,48 @@ +.pagination { + margin-top: 40px; + display: flex; + + button { + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid rgb(208, 213, 221); + background-color: rgb(255, 255, 255); + } + + &__prev, + &__prev-disabled { + border-radius: 8px 0px 0px 8px; + } + + &__next, + &__next-disabled { + border-radius: 0px 8px 8px 0px; + } + + &__next-disabled, + &__prev-disabled { + cursor: auto; + opacity: 0.7; + } + + &__page, + &__page_active { + font-size: 14px; + font-weight: 500; + line-height: 20px; + color: rgb(52, 64, 84); + } + + &__page_active { + background-color: rgb(249, 250, 251) !important; + } + + &__page:hover, + &__prev:hover, + &__next:hover { + background-color: rgb(249, 250, 251); + } +} diff --git a/src/features/Pagination/Pagination.tsx b/src/features/Pagination/Pagination.tsx new file mode 100644 index 0000000..2754660 --- /dev/null +++ b/src/features/Pagination/Pagination.tsx @@ -0,0 +1,138 @@ +import "./Pagination.scss"; +import arrow_right from "./icons/arrow-right.svg"; +import arrow_left from "./icons/arrow-left.svg"; +import Image from "next/image"; + +interface IPaginationProps { + setActivePage: (page: number | ((prev: number) => number)) => void; + activePage: number; + prev: string | null; + next: string | null; + count: number; + current_count: number; + limit: number; +} + +const Pagination: React.FC<IPaginationProps> = ({ + setActivePage, + activePage, + prev, + next, + count, + current_count, + limit, +}: IPaginationProps) => { + const pages_count = Math.ceil(count / limit); + const showPages = () => { + const btns = []; + + for (let i = 1; i <= pages_count; i++) { + btns.push( + <button + onClick={() => setActivePage(i)} + key={i} + className={ + activePage === i ? "pagination__page_active" : "pagination__page" + } + > + {i} + </button> + ); + } + + if (current_count < 8 && activePage === 1) { + return [...btns.slice(0, 1)]; + } + + if (pages_count > 5) { + if (activePage > 2) { + if ( + activePage + 2 === pages_count - 1 || + activePage + 1 === pages_count - 1 || + activePage === pages_count - 1 || + activePage === pages_count + ) { + const newBtns = [ + ...btns.slice(0, 1), + <button key="..." disabled> + ... + </button>, + ...btns.slice( + activePage - (activePage + 2 === pages_count - 1 ? 2 : 1) + ), + ]; + + if (newBtns.length < 6) { + return [ + ...btns.slice(0, 1), + <button key="..." disabled> + ... + </button>, + ...btns.slice(-4), + ]; + } + + return newBtns; + } else { + return [ + ...btns.slice(0, 1), + <button key="...1" disabled> + ... + </button>, + + ...btns.slice( + activePage - (activePage === 3 ? 1 : 2), + activePage + 1 + ), + + <button key="..." disabled> + ... + </button>, + ...btns.slice(-2), + ]; + } + } else { + return [ + ...btns.slice(0, 3), + <button key="..." disabled> + ... + </button>, + ...btns.slice(-2), + ]; + } + } + + return btns; + }; + + const prevPage = () => { + if (activePage - 1 === 0) return; + setActivePage((prev) => prev - 1); + }; + + const nextPage = () => { + if (activePage + 1 > pages_count) return; + setActivePage((prev) => prev + 1); + }; + return ( + <div className="pagination"> + <button + onClick={prevPage} + disabled={prev === null} + className={`pagination__prev${prev === null ? "-disabled" : ""}`} + > + <Image src={arrow_left} alt="" /> + </button> + {showPages().map((btn) => btn)} + <button + onClick={nextPage} + disabled={next === null} + className={`pagination__next${next === null ? "-disabled" : ""}`} + > + <Image src={arrow_right} alt="" /> + </button> + </div> + ); +}; + +export default Pagination; diff --git a/src/features/Pagination/icons/arrow-left.svg b/src/features/Pagination/icons/arrow-left.svg new file mode 100644 index 0000000..61eb8af --- /dev/null +++ b/src/features/Pagination/icons/arrow-left.svg @@ -0,0 +1,7 @@ +<svg width="13.336426" height="13.343750" viewBox="0 0 13.3364 13.3438" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <desc> + Created with Pixso. + </desc> + <defs/> + <path id="Icon" d="M12.5015 6.67188L0.834961 6.67188M6.66846 12.5059L0.834961 6.67188L6.66846 0.838867" stroke="#344054" stroke-opacity="1.000000" stroke-width="1.670000" stroke-linejoin="round"/> +</svg> diff --git a/src/features/Pagination/icons/arrow-right.svg b/src/features/Pagination/icons/arrow-right.svg new file mode 100644 index 0000000..45b4244 --- /dev/null +++ b/src/features/Pagination/icons/arrow-right.svg @@ -0,0 +1,7 @@ +<svg width="13.336426" height="13.343750" viewBox="0 0 13.3364 13.3438" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <desc> + Created with Pixso. + </desc> + <defs/> + <path id="Icon" d="M0.834961 6.67188L12.5015 6.67188M6.66846 0.838867L12.5015 6.67188L6.66846 12.5059" stroke="#344054" stroke-opacity="1.000000" stroke-width="1.670000" stroke-linejoin="round"/> +</svg> diff --git a/src/widgets/TendersList/TendersList.tsx b/src/widgets/TendersList/TendersList.tsx index e3764a4..26dc115 100644 --- a/src/widgets/TendersList/TendersList.tsx +++ b/src/widgets/TendersList/TendersList.tsx @@ -3,9 +3,11 @@ import React, { useEffect, useState } from "react"; import { useTendersStore } from "./tendersStore"; import { data } from "autoprefixer"; import TenderCard from "@/entities/TenderCard"; +import Pagination from "@/features/Pagination/Pagination"; interface Props {} const TendersList = () => { + const [activePage, setActivePage] = useState<number>(1); const [ordering, setOrdering] = useState<number>(1); const { data: tenders, getTenders, isLoading, error } = useTendersStore(); @@ -14,23 +16,30 @@ const TendersList = () => { }, []); console.log(tenders); return ( - <div className="bg-#E4F1FB"> - <div className="flex flex-col gap-2"> - {tenders?.results?.map((tender) => ( - <TenderCard - key={tender.id} - id={tender.id} - id_of_card={tender.id_of_card} - data_rk={tender.data_rk} - name_of_organization={tender.name_of_organization} - type_of_buy={tender.type_of_buy} - name_of_buy={tender.name_of_buy} - date_of_publication_datetime={tender.date_of_publication_datetime} - date_of_offer_datetime={tender.date_of_offer_datetime} - current_timestamp={tender.current_timestamp} - /> - ))} - </div> + <div className="flex flex-col gap-2 pb-[96px] items-center"> + {tenders?.results?.map((tender) => ( + <TenderCard + key={tender.id} + id={tender.id} + id_of_card={tender.id_of_card} + data_rk={tender.data_rk} + name_of_organization={tender.name_of_organization} + type_of_buy={tender.type_of_buy} + name_of_buy={tender.name_of_buy} + date_of_publication_datetime={tender.date_of_publication_datetime} + date_of_offer_datetime={tender.date_of_offer_datetime} + current_timestamp={tender.current_timestamp} + /> + ))} + <Pagination + activePage={activePage} + setActivePage={setActivePage} + prev={tenders.previous} + next={tenders.next} + count={tenders.count as number} + current_count={tenders.results.length} + limit={20} + /> </div> ); };