Open In App

Job Board Using React

Last Updated : 23 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Job Board application using React and Rapidapi JSearch allows users to search, filter and view job listings posted on LinkedIn, Indeed, Glassdoor, ZipRecruiter, BeBee and many others in a single job board. Users can search for jobs by keyword, filter jobs by location or category and see detailed job descriptions when they click on a job listing.

Preview of Final Output: Let us have a look at how the final the final project will look like

Frame-2-(2)-(1)

a preview image of the Home page of the final output

Prerequisites and Technologies used for Job Board Project

Approach and Functionalities of Job Board Project

We will use the following approach to implement different functionalities of the project

  1. Fetch job data from Rapidapi JSearch API.
  2. Display a list of job listings.
  3. Implement search functionality to filter jobs based on keywords.
  4. Allow users to filter jobs by location or category.
  5. Display detailed job descriptions when a job listing is clicked.
  6. Apply Tailwind CSS for styling and responsiveness.

Steps to create the project

Step 1: Create a react application by Vite using the following command.

npm create vite@latest

Then Prompt some questions to set up your project.

Project name: yourProjectName
Package name: yourProjectName
Select a framework: › React // select React
Select a variant: › JavaScript // optional TypeScript or javascript anything works

Step 2: After creating your project folder change the directory to your project folder.

cd projectFolderName

Step 3: Install project dependencies.

npm install axios html-react-parser react-icons react-paginate react-router-dom

Step 4: Then install Tailwind CSS.

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Step 5: Configure your template paths. Add the paths to all of your template files in your tailwind.config.js file.

Javascript




/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}


Step 6: Add the Tailwind directives to your CSS. Add the @tailwind directives for each of Tailwind’s layers to your ./src/index.css file.

@import url(‘https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap’);

@tailwind base;

@tailwind components;

@tailwind utilities;

Step 7: Then, create a folder called pages and components in the same src folder and add the files as mentioned in project structure below.

Step 8: Finally, go to Rapid API Hub and create an account if and get the API key Now create a file called .env as able in the project structure and write the following code.

VITE_REACT_APP_API_SECRET_KEY='your-X-RapidAPI-Key'

Project Structure:

Screenshot-2023-09-28-at-74418-PM-(1)

project structure

Example: Write the following code in respective files:

  • App.jsx: This file implements routing and imports all the components
  • JobCard.jsx: This file creates a basic card component for Job
  • JobCards.jsx: This file renders multiple job files components
  • demoApiData.js: This file contains demo data for fetching
  • MainPage.jsx: This component implements searching based on location and queries
  • JobInfoPage.jsx: This component displays information about the job

Javascript




// App.jsx
import MainPage from "./pages/MainPage"
import JobInfoPage from "./pages/JobInfoPage";
import { Route, Routes } from 'react-router-dom';
 
function App() {
  return (
      <Routes>
        <Route exact path="/" Component={MainPage}/>
        <Route path="/job-info" Component={JobInfoPage}/>
      </Routes> 
  )
}
 
export default App


Javascript




// JobCard.jsx
/* eslint-disable react/prop-types */
import { BiWorld, BiTimeFive } from "react-icons/bi";
import { Link } from "react-router-dom";
 
function JobCard(props) {
  const item = props.data;
  let date = item.job_posted_at_datetime_utc;
  date = date != undefined ? date.split("T") : "no date";
  return (
    <Link to={"/job-info"} state={{ page: item, pagination: props.pagination }}>
      <div className="w-full flex items-center h-fit gap-2 rounded-md bg-white mb-6 shadow p-2 sm:gap-4 hover:shadow-lg">
        <img
          src={
            item.employer_logo !== null
              ? item.employer_logo
          }
          alt="company img"
          className="h-28 w-32 border-1 rounded"
        />
        <div className="text-secondary flex flex-col justify-evenly w-full h-28 overflow-hidden">
          <h3 className="text-xs font-bold truncate">
            {item.employer_name ? item.employer_name : "Company name not found"}
          </h3>
          <h1 className="text-base truncate">
            {item.job_title ? item.job_title : "Job title not found"}
          </h1>
          <div className="flex items-center justify-between flex-wrap gap-2 text-xs w-full sm:flex-nowrap ">
            <div className="border-2 rounded px-2 py-1 truncate border-secondary ">
              {item.job_employment_type
                ? item.job_employment_type
                : "Job type not found"}
            </div>
            <div className="flex justify-between gap-1 flex-wrap sm:flex-nowrap sm:gap-4">
              <div className="text-gray-400 truncate flex items-center gap-2">
                <BiWorld className="inline" />
                <span className="">{item.job_country}</span>
              </div>
              <div className="text-gray-400 truncate justify-self-end flex items-center gap-2">
                <BiTimeFive className="inline" />
                <span className="">{date[0]}</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </Link>
  );
}
 
export default JobCard;


Javascript




// JobCards.jsx
/* eslint-disable react/prop-types */
import { BiChevronRight, BiChevronLeft } from "react-icons/bi";
import { useState } from "react";
import ReactPaginate from "react-paginate";
import JobCard from "./JobCard";
 
function JobCards(props) {
  const items = props.apiData;
  const itemsPerPage = 4;
 
  const [itemOffset, setItemOffset] = useState(props.pagination);
  const endOffset = itemOffset + itemsPerPage;
 
  const currentItems = items.slice(itemOffset, endOffset);
  const pageCount = Math.ceil(items.length / itemsPerPage);
 
  const handlePageClick = (event) => {
    const newOffset = (event.selected * itemsPerPage) % items.length;
    setItemOffset(newOffset);
  };
 
  return (
    <>
      <>
        {currentItems.map((item, i) => {
          return <JobCard key={i} data={item} pagination={itemOffset} />;
        })}
      </>
      <ReactPaginate
        breakLabel={
          <span className="w-10 h-10 mr-4 flex items-center justify-center bg-lightGray rounded-md active:bg-primary active:text-white hover:border-2 hover:border-primary hover:text-primary border border-solid border-lightGray">
            ...
          </span>
        }
        nextLabel={
          <span className="w-10 h-10 mr-4 flex items-center justify-center bg-lightGray rounded-md active:bg-primary active:text-white hover:border-2 hover:border-primary hover:text-primary border border-solid border-lightGray">
            <BiChevronRight />
          </span>
        }
        onPageChange={handlePageClick}
        pageRangeDisplayed={3}
        pageCount={pageCount}
        previousLabel={
          <span className="w-10 h-10  mr-4 flex items-center justify-center bg-lightGray rounded-md active:bg-primary active:text-white hover:border-2 hover:border-primary hover:text-primary border border-solid border-lightGray">
            <BiChevronLeft />
          </span>
        }
        renderOnZeroPageCount={null}
        activeClassName="bg-primary text-white"
        containerClassName="flex items-center justify-end flex-wrap gap-2 mt-8 mb-4 "
        pageClassName="block border border-solid w-10 h-10 flex items-center justify-center rounded-md mr-4 hover:border-2 hover:border-primary "
      />
    </>
  );
}
 
export default JobCards;


Javascript




//demoApiData.js
export const demo = {
  "status": "OK",
  "request_id": "3368b446-971b-474b-ae82-5332240dcd1f",
  "parameters": {
    "query": "python developer in texas, usa",
    "page": 1,
    "num_pages": 15
  },
  "data": [
    {
      "employer_name": "Mphasis USA",
      "employer_logo": null,
      "employer_website": "http://mphasis.com",
      "employer_company_type": null,
      "job_publisher": "LinkedIn",
      "job_id": "FJjhCKEFMzsAAAAAAAAAAA==",
      "job_employment_type": "FULLTIME",
      "job_title": "Full Time Python Developer Position",
      "job_apply_is_direct": false,
      "job_apply_quality_score": 0.5644,
      "job_description":
"Title: Python Developer\n\nLocation: Houston, TX\n\nFull Time Position\n\nHybrid Role ( 3 days onsite in a week)\n\nSkills: Python Java\n\nExperience: 8+ Years\n\nJob Description:\n\nMigrate existing jobs from Python/Bob/Athena to Java/Autosys Support strategic projects (datacenter migration, etc.) as needed.\n• Extensive Experience with at least one the Python frameworks (e.g. Django, Flask, Bottle)
      "job_posted_at_timestamp": 1683670969,
      "job_posted_at_datetime_utc": "2023-05-09T22:22:49.000Z",
      "job_city": "Houston",
      "job_state": "TX",
      "job_country": "US",
      "job_latitude": 29.760427,
      "job_longitude": -95.369804,
      "job_benefits": null,
      "job_google_link":
"https://www.google.com/search?gl=us&hl=en&rciv=jb&q=python+developer+in+texas,+usa&start=0&ibp=htl;jobs#fpstate=tldetail&htivrt=jobs&htiq=python+developer+in+texas,+usa&htidocid=FJjhCKEFMzsAAAAAAAAAAA%3D%3D",
      "job_offer_expiration_datetime_utc": "2023-06-08T22:22:49.000Z",
      "job_offer_expiration_timestamp": 1686262969,
      "job_required_experience": {
        "no_experience_required": false,
        "required_experience_in_months": 72,
        "experience_mentioned": true,
        "experience_preferred": false
      },
      "job_required_skills": [
        "Python (Programming Language)",
        "Software Development",
        "Java",
        "Scripting"
      ],
      "job_required_education": {
        "postgraduate_degree": false,
        "professional_certification": false,
        "high_school": false,
        "associates_degree": false,
        "bachelors_degree": true,
        "degree_mentioned": true,
        "degree_preferred": true,
        "professional_certification_mentioned": false
      },
      "job_experience_in_place_of_education": false,
      "job_min_salary": null,
      "job_max_salary": null,
      "job_salary_currency": null,
      "job_salary_period": null,
      "job_highlights": {
        "Qualifications": [
          "Experience: 8+ Years",
          "Extensive Experience with at least one the Python frameworks (e.g. Django, Flask, Bottle)",
          "Bachelor’s/Master’s degree in Engineering, Computer Science (or equivalent experience)",
          "At least 6+ years of relevant experience as a software developer",
          "Skilled with Python, and JAVA",
          "Prior experience working with Python scripting and integration"
        ],
        "Responsibilities": [
          "Hybrid Role ( 3 days onsite in a week)",
          "Migrate existing jobs from Python/Bob/Athena to Java/Autosys Support strategic projects (datacenter migration, etc.)"
        ]
      },
      "job_job_title": null,
      "job_posting_language": "en",
      "job_onet_soc": "15113200",
      "job_onet_job_zone": "4"
    },
    {
      "employer_name": "Global IT Con LLC.",
      "employer_logo": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQqlJQHEPiDdaJfVEJl5oIpQX4z4BL9yiDrW_LL&s=0",
      "employer_website": null,
      "employer_company_type": null,
      "job_publisher": "LinkedIn",
      "job_id": "5ny6eYx9aNIAAAAAAAAAAA==",
      "job_employment_type": "FULLTIME",
      "job_title": "Python Developer",
      "job_apply_link": "https://www.linkedin.com/jobs/view/python-developer-at-global-it-con-llc-3600137822",
      "job_apply_is_direct": false,
      "job_apply_quality_score": 0.5772,
      "job_description": "Job Role :: Python Developer\n\nLocations :: Dallas, TX\n\nJob type :: Fulltime\n\nJob Description:\n,
      "job_is_remote": false,
      "job_posted_at_timestamp": 1683640785,
      "job_posted_at_datetime_utc": "2023-05-09T13:59:45.000Z",
      "job_city": "Houston",
      "job_state": "TX",
      "job_country": "US",
      "job_latitude": 29.760427,
      "job_longitude": -95.369804,
      "job_benefits": null,
      "job_google_link":
"https://www.google.com/search?gl=us&hl=en&rciv=jb&q=python+developer+in+texas,+usa&start=0&ibp=htl;jobs#fpstate=tldetail&htivrt=jobs&htiq=python+developer+in+texas,+usa&htidocid=5ny6eYx9aNIAAAAAAAAAAA%3D%3D",
      "job_offer_expiration_datetime_utc": "2023-06-08T13:59:45.000Z",
      "job_offer_expiration_timestamp": 1686232785,
      "job_required_experience": {
        "no_experience_required": false,
        "required_experience_in_months": 36,
        "experience_mentioned": true,
        "experience_preferred": false
      },
      "job_required_skills": [
        "PyMongo",
        "pytest",
        "Beautiful Soup",
        "Python (Programming Language)",
        "Azure SQL",
        "Data Engineering",
        "AWS Command Line Interface (CLI)",
        "PySpark",
        "Azure Data Factory",
        "Azure CLI"
      ],
      "job_required_education": {
        "postgraduate_degree": false,
        "professional_certification": false,
        "high_school": false,
        "associates_degree": false,
        "bachelors_degree": true,
        "degree_mentioned": false,
        "degree_preferred": false,
        "professional_certification_mentioned": false
      },
      "job_experience_in_place_of_education": false,
      "job_min_salary": null,
      "job_max_salary": null,
      "job_salary_currency": null,
      "job_salary_period": null,
      "job_highlights": {
        "Qualifications": [
          "Pandas - data manipulation, merges, and data-analytics",
          "xlwings - library to manipulate Excel files thru IPC",
          "Ability to integrate Azure APIs thru Python Azure SDK and Azure CLI",
          "3-5 years of relevant work experience working with SOAP and REST APIs /design",
          "Advanced Excel Development Skills",
          "Hands on experience in designing and implementing data engineering pipelines",
          "Pivot tables",
          "Proficiency with formulas and micros",
          "Design and maintenance of data tables sourced from external csv files",
          "Experience in using Microsoft Azure SQL database, Azure Data Factory, Functions and PowerBI",
          "Proficiency with dimensional modelling, data migration, data cleansing, data profiling, and ETL processes features"
        ],
        "Responsibilities": [
          "Python Development (used as the backend to retrieve Azure data and generate Excel files)"
        ]
      },
      "job_job_title": null,
      "job_posting_language": "en",
      "job_onet_soc": "15113200",
      "job_onet_job_zone": "4"
    } "job_onet_job_zone": "4"
    ]


Javascript




// MainPage.jsx
/* eslint-disable no-unused-vars */
import { useState, useEffect } from "react";
import { useLocation } from "react-router-dom";
 
import axios from "axios";
 
import JobCards from "../components/JobCards";
 
import { MdWorkOutline } from "react-icons/md";
import { BiWorld } from "react-icons/bi";
import { demo } from "../demoApiData";
 
function MainPage() {
  let { state } = useLocation();
 
  let currPage = state == null ? 0 : state.pagination;
  const [query, setQuery] = useState("");
  const [fullTime, setFullTime] = useState(false);
  const [location, setLocation] = useState("");
  const [pagination, setPagination] = useState(currPage);
 
  const [actualQuery, setActualQuery] = useState("");
  const [actualLocation, setActualLocation] = useState("");
 
  let que = actualQuery == "" ? "Full Stack Developer" : actualQuery;
  let loc = actualLocation == "" ? "India" : actualLocation;
 
  const [apiData, setApiData] = useState();
 
  const [error, setError] = useState(null);
  const HandleSubmit = (event) => {
    event.preventDefault();
    setActualQuery(query);
    setActualLocation(location);
    const options = {
      method: "GET",
      params: {
        query: que + " in " + loc,
        page: "1",
        num_pages: "15",
        employment_types: fullTime ? "FULLTIME" : "PARTTIME",
      },
      headers: {
        "X-RapidAPI-Key": "71b69fb31bmsh7d13a809fa7e7ecp16c1fcjsn21afd2c7dd25",
        "X-RapidAPI-Host": "jsearch.p.rapidapi.com",
      },
    };
    axios.request(options).then((res) => {
      console.log(res);
      setApiData(res.data.data);
    });
    //setApiData(apiData)
  };
  const handleFullTime = () => {
    setFullTime((prev) => !prev);
  };
  const handleLocation = (e) => {
    setLocation("" + e.target.value);
  };
 
  useEffect(() => {
    const options = {
      method: "GET",
      params: {
        query: que + " in " + loc,
        page: "1",
        num_pages: "15",
        employment_types: fullTime ? "FULLTIME" : "PARTTIME",
      },
      headers: {
        "X-RapidAPI-Key": import.meta.env.VITE_REACT_APP_API_SECRET_KEY,
        "X-RapidAPI-Host": "jsearch.p.rapidapi.com",
      },
    };
    axios
      .request(options)
      .then((res) => setApiData(res.data.data))
      .catch((err) => setError(err));
    //console.log(apiData)
  }, []);
 
  //console.log(error)
  return (
    <div className="bg-background min-h-screen">
      <div className=" font-Poppins max-w-full p-4 text-xl md:p-8 cursor-pointer ">
        <b>Jobs</b> Portal
      </div>
      {error != null && (
        <div className="bg-primary text-sm rounded
                        text-white font-Poppins max-w-full
                        p-4 mx-4 mb-4 md:p-8 md:mx-8 md:mb-8">
          {
            <div>
              <div className="text-black">{error.code}</div>
              <br />
              {error.response.data.message}
              <br />
              <br />
              Note :{" "}
              <i>
                {" "}
                Due to exceeded of MONTHLY quota for Requests. You can not do
                more requests for the end of the month.{" "}
              </i>
              <b>
                <u>Currently it shows demo api data.</u>
              </b>
            </div>
          }
        </div>
      )}
      <header className="font-Roboto max-w-full
                           mx-4 h-32 rounded-lg
                         bg-jobs-background bg-left-bottom
                         flex items-center justify-center
                         md:mx-8 md:bg-cover ">
        <form
          onSubmit={(e) => HandleSubmit(e)}
          className="bg-white flex items-center
                       justify-around gap-0
                     rounded-lg m-10 md:w-2/3
                     md:gap-8 sm:gap-4 "
        >
          <MdWorkOutline className="flex-none text-sm m-2
                                      sm:m-4 text-gray-400 sm:text-xl" />
          <input
            type="text"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="Title, companies, expertise or benefits"
            className="outline-0 text-sm grow font-Roboto w-full"
          />
          <input
            type="submit"
            className="bg-primary text-white px-4
                       py-2 text-sm rounded-md
                       flex-none m-1 sm:px-6
                       sm:py-3 sm:text-lg"
          />
        </form>
      </header>
      <main className="flex flex-col w-full md:flex-row">
        <form className="p-4 py-8 font-Roboto text-secondary
                         text-sm font-normal w-full
                         md:pl-8 md:pr-0 md:w-1/3 sm:text-lg">
          <input
            type="checkbox"
            checked={fullTime}
            className="w-4 h-4 mx-3 mb-4"
            onChange={handleFullTime}
          />{" "}
          Full Time
          <br />
          <label className="font-bold text-gray-400">Location</label>
          <div className="flex items-center bg-white
                            shadow rounded p-4 my-4 gap-2 w-full ">
            <BiWorld />
            <input
              type="text"
              className="text-sm outline-none grow w-full"
              placeholder="City, state, zip code or country"
              onChange={(e) => handleLocation(e)}
            />
          </div>
          <label>
            <input
              type="radio"
              name="radio-location"
              className="w-4 h-4 mx-3 mb-4"
              value="India"
              onClick={(e) => handleLocation(e)}
            />
            India
          </label>
          <br />
          <label>
            <input
              type="radio"
              name="radio-location"
              className="w-4 h-4 mx-3 mb-4"
              value="London"
              onClick={(e) => handleLocation(e)}
            />
            London
          </label>
          <br />
          <label>
            <input
              type="radio"
              name="radio-location"
              className="w-4 h-4 mx-3 mb-4"
              value="New York"
              onClick={(e) => handleLocation(e)}
            />
            New York
          </label>
          <br />
          <label>
            <input
              type="radio"
              name="radio-location"
              className="w-4 h-4 mx-3 mb-4"
              value="Berlin"
              onClick={(e) => handleLocation(e)}
            />
            Berlin
          </label>
          <br />
        </form>
        <section className="p-4 w-full md:w-2/3 md:p-8 ">
          {/* {demo.jobs_results.map((item,i) => <JobCard key={i} data={item}/>)} */}
          {apiData == null ? (
            <div className="flex flex-col justify-center items-center h-full">
              <svg
                aria-hidden="true"
                className="w-12 h-12 mr-2 text-white
                           animate-spin dark:text-gray-300
                           fill-blue-600 mb-4 "
                viewBox="0 0 100 101"
                fill="none"
                xmlns="http://www.w3.org/2000/svg"
              >
                <path
                  d=
"M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
                  fill="currentColor"
                />
                <path
                  d=
"M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
                  fill="currentFill"
                />
              </svg>
              <h3>Loading jobs...</h3>
            </div>
          ) : (
            apiData && <JobCards apiData={apiData} pagination={pagination} />
          )}
        </section>
      </main>
    </div>
  );
}
export default MainPage;


Javascript




// JobInfoPage.jsx
import { Link, useLocation } from "react-router-dom";
import parse from "html-react-parser";
 
import { HiOutlineArrowNarrowLeft } from "react-icons/hi";
import { BiWorld, BiTimeFive } from "react-icons/bi";
 
function JobInfoPage() {
  let { state } = useLocation();
  //console.log(state);
  var dateTimeExp = new Date(state.page.job_offer_expiration_timestamp * 1000);
  var dateTimePosted = new Date(state.page.job_posted_at_timestamp * 1000);
  var des = state.page.job_description;
  des = des.replaceAll("\n\n", "<br/>");
  des = des.replaceAll("•", "-");
  //let vals = Object.values(state.page.job_highlights)
  let keys = Object.keys(state.page.job_highlights);
 
  return (
    <div className="bg-background min-h-screen text-secondary">
      <div className="font-Poppins max-w-full p-4
                        text-2xl md:p-8 cursor-pointer
                      text-black sticky top-0 bg-background ">
        <b>Jobs</b> Portal
      </div>
      <main className="flex flex-wrap md:flex-nowrap">
        <aside className="px-4 mb-4 md:px-8 w-full h-fit md:max-w-xs bg-background ">
          <Link
            to="/"
            state={{ pagination: state.pagination }}
            className="flex items-center gap-4 mb-4"
          >
            <HiOutlineArrowNarrowLeft className="text-primary text-base inline" />
            <span className="text-primary text-base"> Back to search </span>
          </Link>
          <div>
            <h3 className="text-[#B9BDCF] uppercase text-base text-bold mb-4">
              How to Apply
            </h3>
            <div className="mb-1">
              Company website :{" "}
              {state.page.employer_website != null ? (
                <a
                  href={state.page.employer_website}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-primary"
                >
                  {state.page.employer_name}
                </a>
              ) : (
                <a
                  href={state.page.employer_website}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-gray-500 cursor-not-allowed "
                >
                  {state.page.employer_name}
                </a>
              )}
            </div>
            <div className="mb-1">Salary : As per the Industry Standard</div>
            <div className="mb-1">
              Publisher :{" "}
              {state.page.job_publisher ? state.page.job_publisher : "NA"}
            </div>
            <div className="mb-4 ">
              Apply Before :{" "}
              <span className="underline underline-offset-2
                                 decoration-wavy  decoration-violet-500">
                {dateTimeExp.toDateString()}
              </span>
            </div>
            <a
              href={state.page.job_apply_link}
              target="_blank"
              rel="noopener noreferrer"
            >
              <button className="bg-primary mb-4 text-white
                                   px-4 py-2 text-base rounded-md
                                 flex-none sm:px-4 sm:py-2 hover:bg-sky-700">
                {" "}
                Apply Now
              </button>
            </a>
          </div>
        </aside>
        <section className="w-full md:w-3/4 px-4 md:px-8">
          <div className=" flex flex-col justify-start
                             items-start gap-2 sm:flex-row
                           sm:items-center sm:gap-4 mb-2">
            <h1 className="text-2xl  font-bold ">{state.page.job_title}</h1>
            <div className="border-2 text-xs rounded px-2
                            py-1  truncate border-secondary max-w-fit ">
              {state.page.job_employment_type}
            </div>
          </div>
          <div className="text-gray-400 truncate text-xs
                            justify-self-end  mb-8 gap-2 flex items-center">
            <BiTimeFive className="inline" />
            <span className=""> {dateTimePosted.toDateString()}</span>
          </div>
 
          <div className="flex gap-4 flex-wrap mb-8">
            <img
              src={
                state.page.employer_logo !== null
                  ? state.page.employer_logo
                  :
              }
              alt="company img"
              className="h-16 w-16 border-1 rounded-md"
            />
            <div className="flex flex-col justify-around">
              <h3 className="text-base font-bold truncate">
                {state.page.employer_name}
              </h3>
              <div className="text-gray-400 text-xs truncate flex items-center gap-2">
                <BiWorld className="inline" />
                <span className="">{state.page.job_country}</span>
              </div>
            </div>
          </div>
          <div>
            <div className="mb-8">
              <h3 className="text-base font-bold truncate mb-4">
                ???? Job Info:{" "}
              </h3>
              <hr className="mb-4 border-secondary"></hr>
              <div className="font-Poppins whitespace-break-spaces">
                {parse(des)}
              </div>
            </div>
            {keys.map((item, i) => {
              return (
                <div key={i} className="mb-8">
                  <h3 className="text-base font-bold truncate mb-4">
                    {"????  " + item + ":"}
                  </h3>
                  <hr className="mb-4 border-secondary"></hr>
                  <ul className="list-disc ml-4">
                    {state.page.job_highlights[item].map((pro, j) => (
                      <li key={j} className="mb-2">
                        <span>{pro}</span>
                      </li>
                    ))}
                  </ul>
                </div>
              );
            })}
          </div>
        </section>
      </main>
    </div>
  );
}
export default JobInfoPage;


Steps to Run the Application:

To run the application, type the following command:

npm run dev

Open your browser and go to the following linke:

http://localhost:5173/

Output:

ezgifcom-video-to-gif

the output of the Job Portal



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads