Skip to content

Commit

Permalink
Implement Courses Page Course Pagination using shadcn and mongoose
Browse files Browse the repository at this point in the history
  • Loading branch information
prominhaj committed Aug 8, 2024
1 parent 3181bc0 commit 77e25b7
Show file tree
Hide file tree
Showing 6 changed files with 2,428 additions and 5,103 deletions.
22 changes: 15 additions & 7 deletions app/(main)/courses/(courses-page)/@courses/page.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
import CourseCard from '@/components/globals/CourseCard/CourseCard';
import { coursesByFilter } from '@/queries/courses';
import CoursePagination from '@/components/globals/Pagination/Pagination';
import { coursesByFilter, getTotalCourse } from '@/queries/courses';

export const dynamic = 'force-dynamic';

const CoursesSectionPage = async ({ searchParams: { s, categories, price, sort } }) => {
const CoursesSectionPage = async ({ searchParams: { s, categories, price, sort, page } }) => {
const totalCourse = await getTotalCourse();
const courses = await coursesByFilter({
search: s,
categories: categories?.split(',') || '',
price,
sort: sort === 'price-asc' ? 'asc' : 'desc'
sort: sort === 'price-asc' ? 'asc' : 'desc',
page: parseInt(page) || 1,
perPage: 6
});
const totalPage = Math.round(totalCourse / 6);

return (
<>
{courses?.length > 0 ? (
<div className='grid gap-4 lg:col-span-3 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3'>
{courses?.map((course) => (
<CourseCard key={course?.id} course={course} />
))}
<div>
<div className='grid gap-4 pb-3 lg:col-span-3 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3'>
{courses?.map((course) => (
<CourseCard key={course?.id} course={course} />
))}
</div>
<CoursePagination currentPage={parseInt(page) || 1} totalPages={totalPage} />
</div>
) : (
<div className='py-10 text-center'>
Expand Down
72 changes: 72 additions & 0 deletions components/globals/Pagination/Pagination.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"use client";
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { useCallback } from 'react';

const CoursePagination = ({ currentPage, totalPages }) => {
const router = useRouter();
const searchParams = useSearchParams();
const pathname = usePathname();

const goToPage = useCallback((page) => {
const params = new URLSearchParams(searchParams);
params.set('page', page);
router.replace(`${pathname}?${params.toString()}`);
}, [searchParams, pathname, router]);

return (
<div className="flex justify-center my-4">
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
onClick={() => goToPage(currentPage - 1)}
disabled={currentPage === 1}
>
Previous
</PaginationPrevious>
</PaginationItem>

{[...Array(totalPages)].map((_, index) => {
const pageNumber = index + 1;
return (
<PaginationItem key={pageNumber}>
<PaginationLink
onClick={() => goToPage(pageNumber)}
isActive={pageNumber === currentPage}
>
{pageNumber}
</PaginationLink>
</PaginationItem>
);
})}

{totalPages > 5 && currentPage < totalPages - 3 && (
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
)}

<PaginationItem>
<PaginationNext
onClick={() => goToPage(currentPage + 1)}
disabled={currentPage === totalPages}
>
Next
</PaginationNext>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
);
};

export default CoursePagination;
2 changes: 1 addition & 1 deletion components/ui/button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils"

const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-opacity-50",
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
Expand Down
104 changes: 104 additions & 0 deletions components/ui/pagination.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import * as React from "react"
import {
ChevronLeftIcon,
ChevronRightIcon,
DotsHorizontalIcon,
} from "@radix-ui/react-icons"

import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button";

const Pagination = ({
className,
...props
}) => (
<nav
role="navigation"
aria-label="pagination"
className={cn("mx-auto flex w-full justify-center", className)}
{...props} />
)
Pagination.displayName = "Pagination"

const PaginationContent = React.forwardRef(({ className, ...props }, ref) => (
<ul
ref={ref}
className={cn("flex flex-row items-center gap-1", className)}
{...props} />
))
PaginationContent.displayName = "PaginationContent"

const PaginationItem = React.forwardRef(({ className, ...props }, ref) => (
<li ref={ref} className={cn("", className)} {...props} />
))
PaginationItem.displayName = "PaginationItem"

const PaginationLink = ({
className,
isActive,
size = "icon",
...props
}) => (
<button
aria-current={isActive ? "page" : undefined}
className={cn(buttonVariants({
variant: isActive ? "outline" : "ghost",
size,
}), className)}
{...props} />
)
PaginationLink.displayName = "PaginationLink"

const PaginationPrevious = ({
className,
...props
}) => (
<PaginationLink
aria-label="Go to previous page"
size="default"
className={cn("gap-1 pl-2.5", className)}
{...props}>
<ChevronLeftIcon className="w-4 h-4" />
<span>Previous</span>
</PaginationLink>
)
PaginationPrevious.displayName = "PaginationPrevious"

const PaginationNext = ({
className,
...props
}) => (
<PaginationLink
aria-label="Go to next page"
size="default"
className={cn("gap-1 pr-2.5 disabled:cursor-not-allowed disabled:opacity-60", className)}
{...props}>
<span>Next</span>
<ChevronRightIcon className="w-4 h-4" />
</PaginationLink>
)
PaginationNext.displayName = "PaginationNext"

const PaginationEllipsis = ({
className,
...props
}) => (
<span
aria-hidden
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}>
<DotsHorizontalIcon className="w-4 h-4" />
<span className="sr-only">More pages</span>
</span>
)
PaginationEllipsis.displayName = "PaginationEllipsis"

export {
Pagination,
PaginationContent,
PaginationLink,
PaginationItem,
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
}
Loading

0 comments on commit 77e25b7

Please sign in to comment.