From 65a700dad7a7ff66b00a40312129b5ec1dfbb5fc Mon Sep 17 00:00:00 2001 From: Alibek Date: Fri, 1 Mar 2024 14:14:32 +0600 Subject: [PATCH] added dynamic pagination in reviews-section --- src/app/[locale]/report/[id]/page.tsx | 2 +- src/shared/types/list-type.ts | 2 +- src/shared/ui/components/Loader/Loader.tsx | 13 +++- src/widgets/ReviewSection/ReviewSection.scss | 5 ++ src/widgets/ReviewSection/ReviewSection.tsx | 75 ++++++++++++++++++-- 5 files changed, 88 insertions(+), 9 deletions(-) diff --git a/src/app/[locale]/report/[id]/page.tsx b/src/app/[locale]/report/[id]/page.tsx index ca97f3b..bc18787 100644 --- a/src/app/[locale]/report/[id]/page.tsx +++ b/src/app/[locale]/report/[id]/page.tsx @@ -33,7 +33,7 @@ const ReportDetails = async ({ return res.json(); }; - const report: IReport = await getReportDetails(); + const report: IReport = (await getReportDetails()) || {}; return (
diff --git a/src/shared/types/list-type.ts b/src/shared/types/list-type.ts index 5676a34..b425a68 100644 --- a/src/shared/types/list-type.ts +++ b/src/shared/types/list-type.ts @@ -1,5 +1,5 @@ export interface IList { - count: number | null; + count: number; previous: string | null; next: string | null; } diff --git a/src/shared/ui/components/Loader/Loader.tsx b/src/shared/ui/components/Loader/Loader.tsx index 6842803..e75796f 100644 --- a/src/shared/ui/components/Loader/Loader.tsx +++ b/src/shared/ui/components/Loader/Loader.tsx @@ -1,7 +1,16 @@ import "./Loader.scss"; -const Loader = () => { - return ; +interface ILoader { + color?: string; +} + +const Loader: React.FC = ({ color }: ILoader) => { + return ( + + ); }; export default Loader; diff --git a/src/widgets/ReviewSection/ReviewSection.scss b/src/widgets/ReviewSection/ReviewSection.scss index 17cb30b..9d5a673 100644 --- a/src/widgets/ReviewSection/ReviewSection.scss +++ b/src/widgets/ReviewSection/ReviewSection.scss @@ -46,6 +46,11 @@ } } + &__loader { + display: flex; + justify-content: center; + } + form { margin-bottom: 70px; display: flex; diff --git a/src/widgets/ReviewSection/ReviewSection.tsx b/src/widgets/ReviewSection/ReviewSection.tsx index 3bbeffb..868879c 100644 --- a/src/widgets/ReviewSection/ReviewSection.tsx +++ b/src/widgets/ReviewSection/ReviewSection.tsx @@ -4,7 +4,7 @@ import "./ReviewSection.scss"; import { apiInstance } from "@/shared/config/apiConfig"; import { IReviewList } from "@/shared/types/review-type"; import { signIn, useSession } from "next-auth/react"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import calendar from "./icons/calendar.svg"; import Image from "next/image"; import { @@ -12,6 +12,7 @@ import { usePathname, useRouter, } from "@/shared/config/navigation"; +import Loader from "@/shared/ui/components/Loader/Loader"; interface IReviewsSectionProps { endpoint: string; @@ -22,7 +23,30 @@ const ReviewSection: React.FC = ({ endpoint, id, }: IReviewsSectionProps) => { - const [reviews, setReviews] = useState(); + const lastElement = useRef(null); + const observer = useRef(null); + const [reviews, setReviews] = useState({ + count: 0, + next: null, + previous: null, + results: [ + { + id: 0, + author: { + image: "", + id: 0, + first_name: "", + last_name: "", + govern_status: null, + }, + review: "", + created_at: "", + }, + ], + }); + const [pageSize, setPageSize] = useState(8); + const [reviewCount, setReviewCount] = useState(0); + const [loader, setLoader] = useState(false); const pathname = usePathname(); const session = useSession(); const handleSubmit: React.MouseEventHandler< @@ -55,6 +79,7 @@ const ReviewSection: React.FC = ({ formData, config ); + getReviews(); } catch (error) { console.log(error); @@ -62,15 +87,45 @@ const ReviewSection: React.FC = ({ }; const getReviews = async () => { + setLoader(true); const response = await apiInstance.get( - `/${endpoint}/${id}/reviews/?page_size=8` + `/${endpoint}/${id}/reviews/?page_size=${pageSize}` ); + + setReviewCount(response.data.count); + setLoader(false); + setReviews({ + count: response.data.count, + next: response.data.next, + previous: response.data.previous, + results: [...reviews?.results, ...response.data.results], + }); setReviews(response?.data); }; + useEffect(() => { + if (loader) return; + if (observer.current) observer.current.disconnect(); + const callback = function (entries: any) { + console.log(reviewCount, pageSize); + if ( + entries[0].isIntersecting && + (reviews?.results.length as number) <= reviewCount + ) { + if (pageSize < reviewCount) { + setPageSize((prev) => prev + 8); + } else { + setPageSize(reviewCount); + } + } + }; + observer.current = new IntersectionObserver(callback); + observer.current.observe(lastElement.current as HTMLDivElement); + }, [loader]); + useEffect(() => { getReviews(); - }, []); + }, [pageSize]); const months: Record = { "01": "Январь", @@ -86,6 +141,7 @@ const ReviewSection: React.FC = ({ "11": "Ноябрь", "12": "Декабрь", }; + return (

@@ -116,7 +172,7 @@ const ReviewSection: React.FC = ({

{reviews?.results.length !== 0 ? ( -
    +
      {reviews?.results.map((review) => (
    • @@ -152,6 +208,15 @@ const ReviewSection: React.FC = ({ Оставьте комментарий первым :)

      )} + {loader ? ( +
      + +
      + ) : null} +
);