Adding Job Type Filtering

ExamPro Markdown Lab Part 3

This is part of the ExamPro Next.js course. Additional content will be added to this lab, such as pagination and job type filtering.

In this lab, we will be adding the job type filtering feature to the existing application

Filter by Job Type: All, Full-Time, Part-Time Feature

localhost:3000/jobs/type/full-time

  1. Create pages/jobs/type/[type_name].js

  2. Import the following

import { promises as fs } from 'fs';
import path from 'path';
import matter from 'gray-matter';

import Job from '@/components/jobs/Job';
import JobsHeader from '@/components/jobs/JobsHeader';
import Layout from '@/components/Layout';
  1. Create the getStaticPaths() function
export async function getStaticPaths() {
  // Read from the /jobs directory
  const files = await fs.readdir(path.join('jobs'));

  const types = await Promise.all(
    files.map(async (filename) => {
      const markdown = await fs.readFile(path.join('jobs', filename), 'utf-8');

      const { data } = matter(markdown);

      // Return the job types in lowercase. Eg. 'full-time' instead of 'Full-Time'
      return data.type.toLowerCase();
    })
  );

  const paths = types.map((type) => ({
    params: { type_name: type },
  }));

  return {
    paths,
    fallback: false,
  };
}
  1. Create the getStaticProps() function
// This function takes the type_name from getStaticPaths()
export async function getStaticProps({ params: { type_name } }) {
  // Read from /jobs directory
  const files = await fs.readdir(path.join('jobs'));

  // Map through jobs directory
  const jobs = await Promise.all(
    files.map(async (filename) => {
      // Set 'slug' to name of md file
      const slug = filename.replace('.md', '');
      // Read all markdown from file
      const markdown = await fs.readFile(path.join('jobs', filename), 'utf-8');
      // Extract data from markdown
      const { data } = matter(markdown);

      // return slug and data in an array
      return {
        slug,
        data,
      };
    })
  );

  // Maps through all the job types
  const types = jobs.map((job) => job.data.type);
  // Only take the unique job types
  const uniqueTypes = [...new Set(types)];

  const jobTypes = jobs.filter((job) => job.data.type.toLowerCase() === type_name);

  // return jobs, typeName, types
  return {
    props: {
      jobs: jobTypes,
      typeName: type_name,
      types: uniqueTypes,
    },
  };
}
  1. Create JobTypePostings() function
export default function JobTypePostings({ jobs, typeName }) {
  const jobType = typeName.replace(/(^|[\s-])\S/g, function (match) {
    return match.toUpperCase();
  });

  return (
    <Layout title="Jobs | ExamPro">
      <JobsHeader jobType={jobType} />
      <div className="bg-white my-4 shadow overflow-hidden divide-y divide-gray-200 sm:rounded-md">
        <ul role="list" className="divide-y divide-gray-200">
          {/* Maps through each job */}
          {jobs.map((job, index) => (
            <Job key={index} job={job} />
          ))}
        </ul>
      </div>
    </Layout>
  );
}

Update the [page_index].js file

  1. Import the JobsHeader component
import JobsHeader from '@/components/jobs/JobsHeader';
  1. Replace the following lines
<div className="px-4 py-4 sm:px-6 md:flex md:items-center md:justify-between">
  <div className="flex-1 min-w-0">
    <h2 className="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate">
      Job Postings
    </h2>
  </div>
</div>

with

<JobsHeader />

28