Adding Job Type Filtering
Tags: nextjs, tailwindcss, markdown, react
Published: 2021-11-24 15:50:42

# ExamPro Markdown Lab Part 3

This is part of the [ExamPro](https://www.exampro.co/) 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`

![](https://exampro-support.s3.amazonaws.com/Nextjs/job_listing_with_filtering.png)

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

2. Import the following

```javascript
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';
```

3. Create the getStaticPaths() function

```javascript
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,
  };
}
```

4. Create the getStaticProps() function

```javascript
// 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,
    },
  };
}
```

5. Create `JobTypePostings()` function

```javascript
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

```javascript
import JobsHeader from '@/components/jobs/JobsHeader';
```

2. Replace the following lines

```javascript
<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

```javascript
<JobsHeader />
```