Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/hng 93 implement pagination for career page #356

Closed
wants to merge 5 commits into from
Closed

Feat/hng 93 implement pagination for career page #356

wants to merge 5 commits into from

Conversation

Jomagene
Copy link
Contributor

implement pagination for career page:

(This PR introduces a pagination feature to the HNG-boiler-plate-Remix application due to the issue [FEAT] External Dynamic Pages > Career Page > Implement Pagination #93. CLOSED BY MISTAKE MERGING AN EMPTY PR)

Add Pagination Component and Job Listing Feature for Career Page

PR Description:

This PR introduces a pagination component and integrates it with the job listing feature on the career page. The new pagination system allows users to navigate through multiple pages of job listings seamlessly. Below are the key features and implementation details:

Features:

  1. Pagination Component:

    • Pagination: Container for the pagination navigation.
    • PaginationContent: Holds the pagination items.
    • PaginationItem: Represents an individual page item.
    • PaginationLink: Link for each page, styled according to its state (active/inactive).
    • PaginationPrevious and PaginationNext: Navigation links to move to the previous or next page.
    • PaginationEllipsis: Ellipsis for indicating skipped pages.
  2. Job Listing Integration:

    • CareerPage: A page that displays job listings with pagination controls.
    • Dynamically generates page numbers based on the current page and total pages.
    • Adjusts the number of visible page links based on the window width.

How to Use:

To use the pagination component and fetch a job list, follow these steps:

  1. Loader Function:

    • The loader function fetches job listings based on the current page from the URL query parameters.
    • If the page number is invalid, it returns a 404 response.
    export const loader: LoaderFunction = async ({ request }) => {
      const url = new URL(request.url);
      const page = parseInt(url.searchParams.get("page") || "1", 10);
      const jobListings = dummyJobListings(page);
    
      if (isNaN(page) || page < 1 || page > jobListings.totalPages) {
        throw new Response("Page not found", { status: 404 });
      }
    
      return json({ jobListings });
    };
  2. CareerPage Component:

    • The CareerPage component uses the useLoaderData hook to fetch job listings data.
    • It dynamically generates the pagination links based on the current page and total pages.
    • Adjusts the number of visible pages based on the window width.
    const CareerPage: React.FC = () => {
      const { jobListings } = useLoaderData<LoaderData>();
      const [searchParams] = useSearchParams();
      const currentPage = parseInt(searchParams.get("page") || "1", 10);
      const totalPages = jobListings.totalPages;
    
      const [maxPagesToShow, setMaxPagesToShow] = useState(3);
    
      useEffect(() => {
        const handleResize = () => {
          const width = window.innerWidth;
          if (width <= 400) {
            setMaxPagesToShow(0);
          } else if (width <= 435) {
            setMaxPagesToShow(1);
          } else if (width <= 450) {
            setMaxPagesToShow(2);
          } else if (width <= 470) {
            setMaxPagesToShow(3);
          } else if (width <= 1024) {
            setMaxPagesToShow(5);
          } else {
            setMaxPagesToShow(totalPages);
          }
        };
    
        window.addEventListener("resize", handleResize);
        handleResize();
    
        return () => window.removeEventListener("resize", handleResize);
      }, [totalPages]);
    
      const generatePageNumbers = (): (number | string)[] => {
        const pageNumbers: (number | string)[] = [];
        const half = Math.floor(maxPagesToShow / 2);
    
        let start = Math.max(1, currentPage - half);
        let end = Math.min(totalPages, currentPage + half);
    
        if (currentPage - half <= 0) {
          end = Math.min(totalPages, maxPagesToShow);
        }
    
        if (currentPage + half > totalPages) {
          start = Math.max(1, totalPages - maxPagesToShow + 1);
        }
    
        for (let i = start; i <= end; i++) {
          pageNumbers.push(i);
        }
    
        if (start > 1) {
          if (start > 2) {
            pageNumbers.unshift(1, "ellipsis");
          } else {
            pageNumbers.unshift(1);
          }
        }
    
        if (end < totalPages - 1) {
          pageNumbers.push("ellipsis", totalPages);
        } else if (end === totalPages - 1) {
          pageNumbers.push(totalPages);
        }
    
        return pageNumbers;
      };
    
      return (
        <div className="container mx-auto px-4">
          <h1>Career Page</h1>
          <div>
            {jobListings.items.map((job) => (
              <div key={job.id}>{job.title}</div>
            ))}
          </div>
          {jobListings.totalPages > 1 && (
            <Pagination className="my-4 flex justify-center font-[inter]">
              <PaginationContent className="flex items-center justify-between p-0">
                <PaginationItem className="mx-1">
                  <Link
                    to={`?page=${Math.max(currentPage - 1, 1)}`}
                    className={`flex items-center gap-2 space-x-1 rounded-md py-2 pl-2.5 pr-4 ${
                      currentPage === 1
                        ? "pointer-events-none text-gray-400 opacity-50"
                        : "hover:bg-[#F4F4F5]"
                    }`}
                  >
                    <PaginationPrevious size={250} />
                  </Link>
                </PaginationItem>
                {generatePageNumbers().map((page, index) =>
                  page === "ellipsis" ? (
                    <PaginationItem key={index}>
                      <PaginationEllipsis className="flex items-center" />
                    </PaginationItem>
                  ) : (
                    <PaginationItem key={index} className="mx-1">
                      <Link
                        to={`?page=${page}`}
                        className={`rounded-md px-3 py-2 text-[14px] ${
                          currentPage === page
                            ? "bg-orange-500 text-white"
                            : `hover:bg-[#F4F4F5] ${
                                maxPagesToShow === 0 ? "hidden" : ""
                              }`
                        } `}
                      >
                        <PaginationLink size={20}>{page}</PaginationLink>
                      </Link>
                    </PaginationItem>
                  ),
                )}
                <PaginationItem className="mx-1">
                  <Link
                    to={`?page=${Math.min(currentPage + 1, totalPages)}`}
                    className={`flex items-center gap-2 space-x-1 rounded-md py-2 pl-2.5 pr-4 ${
                      currentPage === totalPages
                        ? "pointer-events-none text-[#CBD5E1]"
                        : "hover:bg-[#F4F4F5]"
                    }`}
                    aria-disabled={currentPage === totalPages}
                  >
                    <PaginationNext size={250} />
                  </Link>
                </PaginationItem>
              </PaginationContent>
            </Pagination>
          )}
        </div>
      );
    };
    
    export default CareerPage;

Additional Notes:

  • The dummyJobListings function is used to simulate job listings data. Replace this with your actual data fetching logic.
  • The pagination component adjusts the number of visible pages based on the window width for responsive design.

@Jomagene Jomagene closed this by deleting the head repository Jul 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant