Horje
Build a Job Board with Next.js

In this article, we will guide you through creating a dynamic job board application using Next.js. A job board application helps job seekers browse, filter, and apply for job openings while enabling employers to post job listings.

Project Preview

job

Build a Job Board with Next.js

Prerequisites:

Approach to Build a Job Board with Next.js:

  • Setup the Project by Creating a new NextJS project Install the necessary libraries.
  • Create Layouts and Components using Bootstrap for responsive design.
  • Create Navbar component for easy navigation across the application.
  • Create AddJob component to add new job listings to board.
  • Create JobListing component which is responsible to display the all listings.
  • Add search feature to look for the specific job.
  • Add filters to allow users to filter job listings by job type (full-time, intern, etc.) and experience level.

Steps to Build a Job Board with Next.js:

Step 1: Create a application of NextJS using the following command.

npx create-next-app job-board

Step 2: Navigate to project directory

cd job-board

Step 3: Install the necessary package in your project using the following command.

npm install bootstrap

Project Structure

Screenshot-(156)

Folder Structure

Dependencies

 "dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"bootstrap": "^5.3.3",
"next": "14.1.3",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.0.1"
}

Example: Create the required files in respective folder and write the following code.

JavaScript
// page.js

import React from 'react'
import JobListing from './components/JobListing'

const page = () => {
    return (
        <div>
            <JobListing />
        </div>
    )
}

export default page;
JavaScript
// Nvabar.js

import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import Link from "next/link";
function Navbar() {
    return (
        <nav className="navbar navbar-expand-lg navbar-light bg-light shadow top-0">
            <div className="container">
                <a className="navbar-brand text-success" href="#">
                    GFG Job Listing
                </a>
                <button
                    className="navbar-toggler"
                    type="button"
                    data-toggle="collapse"
                    data-target="#navbarNav"
                    aria-controls="navbarNav"
                    aria-expanded="false"
                    aria-label="Toggle navigation"
                >
                    <span className="navbar-toggler-icon"></span>
                </button>
                <div className="collapse navbar-collapse" id="navbarNav">
                    <ul className="navbar-nav">
                        <li className="nav-item">
                            <Link className="nav-link" href="/">
                                Home
                            </Link>
                        </li>
                        <li className="nav-item">
                            <Link className="nav-link" href="AddJob">
                                Add New Job Listing
                            </Link>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    );
}

export default Navbar;
JavaScript
// JobListing.js

"use client";
import React, { useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import Navbar from "./Navbar";
import { FaLocationDot } from "react-icons/fa6";

const JobListing = () => {
    const storedListings = localStorage.getItem("listings");
    const allListings = storedListings ? JSON.parse(storedListings) : [];
    const [listings, setListings] = useState(allListings);
    const [filter, setFilter] = useState("all");
    const [searchTerm, setSearchTerm] = useState("");
    const [experienceFilter, setExperienceFilter] = useState("all");

    const handleFilterChange = (e) => {
        const value = e.target.value;
        setFilter(value);
        applyFilters(value, searchTerm, experienceFilter);
    };

    const handleSearchChange = (e) => {
        const value = e.target.value;
        setSearchTerm(value);
        applyFilters(filter, value, experienceFilter);
    };

    const handleExperienceChange = (e) => {
        const value = e.target.value;
        setExperienceFilter(value);
        applyFilters(filter, searchTerm, value);
    };

    const applyFilters = (jobTypeFilter, search, experience) => {
        let filteredListings = allListings;

        if (jobTypeFilter !== "all") {
            filteredListings = filteredListings.filter(
                (listing) => listing.jobType === jobTypeFilter
            );
        }

        if (search) {
            filteredListings = filteredListings.filter((listing) =>
                listing.title.toLowerCase().includes(search.toLowerCase())
            );
        }

        if (experience !== "all") {
            filteredListings = filteredListings.filter((listing) => {
                const [minExp, maxExp] = listing.experience
                    .split("-")
                    .map((exp) => exp.trim());
                const minExpYears = parseInt(minExp);
                const maxExpYears = maxExp
                    ? parseInt(maxExp.replace(" years", ""))
                    : minExpYears;

                if (experience === "0-1 years") {
                    return minExpYears <= 1;
                } else if (experience === "1-3 years") {
                    return minExpYears <= 3 && maxExpYears >= 1;
                } else if (experience === "3-5 years") {
                    return minExpYears <= 5 && maxExpYears >= 3;
                } else if (experience === "5+ years") {
                    return minExpYears >= 5;
                }
                return true;
            });
        }

        setListings(filteredListings);
    };

    return (
        <>
            <Navbar />
            <div className="container mt-5">
                <div className="row">
                    <div className="col-md-3">
                        <div className="mb-3">
                            <p>Type:</p>
                            <label
                                className="form-check-label me-3"
                                style={{ fontSize: "1rem" }}
                            >
                                <input
                                    type="checkbox"
                                    name="filter"
                                    value="all"
                                    checked={filter === "all"}
                                    onChange={handleFilterChange}
                                    style={{ transform: "scale(1.3)" }}
                                />{" "}
                                All
                            </label>
                            <label
                                className="form-check-label me-3"
                                style={{ fontSize: "1rem" }}
                            >
                                <input
                                    type="checkbox"
                                    name="filter"
                                    value="full-time"
                                    checked={filter === "full-time"}
                                    onChange={handleFilterChange}
                                    style={{ transform: "scale(1.3)" }}
                                />{" "}
                                Full Time
                            </label>
                            <label className="form-check-label" style={{ fontSize: "1rem" }}>
                                <input
                                    type="checkbox"
                                    name="filter"
                                    value="intern"
                                    checked={filter === "intern"}
                                    onChange={handleFilterChange}
                                    style={{ transform: "scale(1.3)" }}
                                />{" "}
                                Intern
                            </label>
                        </div>

                        <div className="mb-3">
                            <label htmlFor="experience" className="form-label">
                                Experience
                            </label>
                            <select
                                className="form-select"
                                id="experience"
                                value={experienceFilter}
                                onChange={handleExperienceChange}
                            >
                                <option value="all">All</option>
                                <option value="0-1 years">0-1 years</option>
                                <option value="1-3 years">1-3 years</option>
                                <option value="3-5 years">3-5 years</option>
                                <option value="5+ years">5+ years</option>
                            </select>
                        </div>
                    </div>
                    <div className="col-md-9">
                        <div className="mb-3">
                            <label htmlFor="search" className="form-label">
                                Search
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="search"
                                value={searchTerm}
                                placeholder="Python Developer..."
                                onChange={handleSearchChange}
                            />
                        </div>
                        <div className="row">
                            {listings.map((listing) => (
                                <div key={listing.id} className="col-md-6 mb-4">
                                    <div className="card h-100 w-100">
                                        <div className="row g-0">
                                            <div className="col-md-8 d-flex flex-column">
                                                <div className="card-body d-flex flex-column">
                                                    <div className="d-flex align-items-center">
                                                        <img
                                                            src={listing.logoData}
                                                            className="rounded-circle 
                                                            img-thumbnail"
                                                            alt={listing.title}
                                                            style={{
                                                                width: "70px",
                                                                height: "70px",
                                                                objectFit: "cover",
                                                                marginRight: "15px",
                                                            }}
                                                        />
                                                        <div>
                                                            <h4 className="card-title mb-0">
                                                                {listing.title}
                                                            </h4>
                                                        </div>
                                                    </div>
                                                    <h5 className="card-title">
                                                    {listing.companyName}</h5>
                                                    <p className="card-text">
                                                        <FaLocationDot className="text-success" />
                                                        {listing.location}
                                                    </p>
                                                    <p className="card-text">
                                                        Experience Required:
                                                        {listing.experience}+ Yrs
                                                    </p>
                                                    <div className="d-flex
                                                    justify-content-between">
                                                        <p className="card-text">
                                                            {listing.jobType === "full-time"
                                                                ? "Salary"
                                                                : "Stipend"}
                                                        </p>
                                                        {listing.jobType === "intern" ? (
                                                            <p className="card-text">
                                                                {listing.stipend}/Month
                                                            </p>
                                                        ) : (
                                                            <p className="card-text">
                                                                {listing.salary} LPA/Annum
                                                            </p>
                                                        )}
                                                    </div>
                                                    <button className=
                                                    "btn btn-outline-success w-50">
                                                        Apply
                                                    </button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            ))}
                        </div>
                    </div>
                </div>
            </div>
        </>
    );
};

export default JobListing;
JavaScript
// pages/AddJob.js

import React, { useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import Navbar from "@/app/components/Navbar";

const AddJob = () => {
    const [title, setTitle] = useState("");
    const [description, setDescription] = useState("");
    const [salary, setSalary] = useState("");
    const [stipend, setStipend] = useState("");
    const [location, setLocation] = useState("");
    const [logo, setLogo] = useState("");
    const [logoData, setLogoData] = useState("");
    const [jobType, setJobType] = useState("full-time");
    const [companyName, setCompanyName] = useState("");
    const [experience, setExperience] = useState("");

    const handleSubmit = (e) => {
        e.preventDefault();
        console.log({
            title,
            description,
            salary,
            stipend,
            location,
            logo,
            logoData,
            jobType,
            companyName,
            experience,
        });

        // Save the form data and image data to local storage
        const jobListings = {
            title,
            description,
            salary,
            stipend,
            location,
            logo,
            logoData,
            jobType,
            companyName,
            experience,
        };
        const listings = JSON.parse(localStorage.getItem("listings")) || [];
        listings.push(jobListings);
        localStorage.setItem("listings", JSON.stringify(listings));

        // Reset form fields after submission
        setTitle("");
        setDescription("");
        setSalary("");
        setStipend("");
        setLocation("");
        setLogo("");
        setLogoData("");
        setJobType("full-time");
        setCompanyName("");
        setExperience("");
    };

    const handleImageChange = (e) => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.onloadend = () => {
            setLogoData(reader.result);
        };
        if (file) {
            reader.readAsDataURL(file);
            setLogo(file.name);
        }
    };

    return (
        <>
            <Navbar />
            <div className="container" style={{ width: "70%" }}>
                <h2 className="mt-3 mb-4">Add New Job Listing</h2>
                <form onSubmit={handleSubmit}>
                    <div className="row mb-3">
                        <div className="col-md-6">
                            <label htmlFor="companyName" className="form-label">
                                Company Name
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="companyName"
                                value={companyName}
                                onChange={(e) => setCompanyName(e.target.value)}
                                required
                            />
                        </div>

                        <div className="col-md-6">
                            <label htmlFor="title" className="form-label">
                                Title
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="title"
                                value={title}
                                onChange={(e) => setTitle(e.target.value)}
                                required
                            />
                        </div>
                    </div>

                    <div className="row mb-3">
                        <div className="col-md-6">
                            <label htmlFor="jobloc" className="form-label">
                                Job Location
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="jobloc"
                                value={location}
                                onChange={(e) => setLocation(e.target.value)}
                                required
                            />
                        </div>

                        <div className="col-md-6">
                            <label htmlFor="exp" className="form-label">
                                Experience Required
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="exp"
                                value={experience}
                                onChange={(e) => setExperience(e.target.value)}
                                required
                            />
                        </div>
                    </div>
                    <div className="mb-3">
                        <label htmlFor="description" className="form-label">
                            Description
                        </label>
                        <textarea
                            className="form-control"
                            id="description"
                            value={description}
                            onChange={(e) => setDescription(e.target.value)}
                            required
                        ></textarea>
                    </div>
                    <div className="mb-3">
                        <label htmlFor="jobtype" className="form-label">
                            Select Job Type
                        </label>
                        <select
                            className="form-control"
                            id="jobtype"
                            value={jobType}
                            onChange={(e) => setJobType(e.target.value)}
                            required
                        >
                            <option value="full-time">Full Time</option>
                            <option value="intern">Internship</option>
                        </select>
                    </div>
                    {jobType === "full-time" && (
                        <div className="mb-3">
                            <label htmlFor="salary" className="form-label">
                                Salary
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="salary"
                                value={salary}
                                onChange={(e) => setSalary(e.target.value)}
                                required
                            />
                        </div>
                    )}
                    {jobType === "intern" && (
                        <div className="mb-3">
                            <label htmlFor="stipend" className="form-label">
                                Stipend per Month
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="stipend"
                                value={stipend}
                                onChange={(e) => setStipend(e.target.value)}
                                required
                            />
                        </div>
                    )}
                    <div className="mb-3">
                        <label htmlFor="logo" className="form-label">
                            Logo
                        </label>
                        <input
                            type="file"
                            className="form-control"
                            id="logo"
                            accept="image/*"
                            onChange={handleImageChange}
                            required
                        />
                    </div>
                    {logoData && (
                        <img
                            src={logoData}
                            alt="Selected"
                            className="img-fluid mb-3"
                            style={{ maxWidth: "200px" }}
                        />
                    )}
                    <button type="submit" className="btn btn-primary">
                        Add Job to Portal
                    </button>
                </form>
            </div>
        </>
    );
};

export default AddJob;

Start your application using the following command:

npm run dev

Output

jg

Job Board





Reffered: https://www.geeksforgeeks.org


Web Technologies

Related
Next.js Bundle Analyzer Next.js Bundle Analyzer
Creating a Gatsby Blog from Scratch Creating a Gatsby Blog from Scratch
Middleware in NestJS: Implementing Custom Middleware for Request Processing. Middleware in NestJS: Implementing Custom Middleware for Request Processing.
Controllers in NestJS Controllers in NestJS
E-commerce Websites : User Account Section: E-commerce Websites : User Account Section:

Type:
Geek
Category:
Coding
Sub Category:
Tutorial
Uploaded by:
Admin
Views:
15