From 8261d1985505d375d6b12234472cae30fb4230f6 Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Fri, 27 Jun 2025 18:24:11 +0600 Subject: [PATCH] feat: review carousel --- .../SQLCourseVariant/ReviewCarousel.tsx | 96 +++++++++++++++---- 1 file changed, 75 insertions(+), 21 deletions(-) diff --git a/src/components/SQLCourseVariant/ReviewCarousel.tsx b/src/components/SQLCourseVariant/ReviewCarousel.tsx index d6296d196..4075c187d 100644 --- a/src/components/SQLCourseVariant/ReviewCarousel.tsx +++ b/src/components/SQLCourseVariant/ReviewCarousel.tsx @@ -4,8 +4,10 @@ import { StarIcon, User2Icon, } from 'lucide-react'; -import { useState } from 'react'; +import { useLayoutEffect, useMemo, useState } from 'react'; import { markdownToHtml } from '../../lib/markdown'; +import { getTailwindScreenDimension } from '../../lib/is-mobile'; +import { cn } from '../../lib/classname'; type Review = { name: string; @@ -107,14 +109,23 @@ export function ReviewCarousel() { }, ]; - const batchSize = 2; + const [batchSize, setBatchSize] = useState(3); const maxBatchNumber = Math.ceil(reviews.length / batchSize); const [currentBatchNumber, setCurrentBatchNumber] = useState(0); - const currentBatch = reviews.slice( - currentBatchNumber * batchSize, - (currentBatchNumber + 1) * batchSize, - ); + const currentBatch = useMemo(() => { + const result = reviews.slice( + currentBatchNumber * batchSize, + (currentBatchNumber + 1) * batchSize, + ); + + if (result.length < batchSize) { + const remaining = batchSize - result.length; + return [...result, ...reviews.slice(0, remaining)]; + } + + return result; + }, [currentBatchNumber, batchSize]); const handleNextBatch = () => { setCurrentBatchNumber((prev) => (prev + 1) % maxBatchNumber); @@ -126,27 +137,52 @@ export function ReviewCarousel() { ); }; + useLayoutEffect(() => { + const size = getTailwindScreenDimension(); + if (size === 'xl' || size === '2xl') { + setBatchSize(3); + } else { + setBatchSize(2); + } + }, []); + return (

What other learners said

-
-
-
+ +
+
+ - - + icon={ + + } + />
-
+
{currentBatch.map((review, index) => (
@@ -195,15 +231,33 @@ export function ReviewCarousel() { ))}
-
- + icon={ + + } + />
); } + +type NavigateButtonProps = { + onClick: () => void; + icon: React.ReactNode; +}; + +function NavigateButton(props: NavigateButtonProps) { + const { onClick, icon } = props; + + return ( + + ); +}