diff --git a/client/src/components/JobCard.jsx b/client/src/components/JobCard.jsx index 3e3b105..bccbdf4 100644 --- a/client/src/components/JobCard.jsx +++ b/client/src/components/JobCard.jsx @@ -1,72 +1,65 @@ -import React from 'react' -import { Link } from 'react-router-dom' -import useIsMobile from '../hooks/useIsMobile'; - +import React from "react"; +import { Link } from "react-router-dom"; +import useIsMobile from "../hooks/useIsMobile"; export const JobCard = ({ job }) => { - - - - const convertDateFormat = (inputDate) => { - const parts = inputDate.split('-'); - if (parts.length !== 3) { - return "Invalid date format"; - } - - const day = parts[2]; - const month = parts[1]; - const year = parts[0]; - - return `${day}-${month}-${year}`; + const convertDateFormat = (inputDate) => { + const parts = inputDate.split("-"); + if (parts.length !== 3) { + return "Invalid date format"; } - - const isMobile = useIsMobile() - - - - return ( - <> - - - -
-
- -
-
- -
-

{job.title}

-
-
-
-

{job.companyName}

-

{job.exp}

- {!isMobile &&

{job.description.slice(0, 64)}...

} -

{job.description.slice(0, 39)}...

-
-
- -
- - -
- -
- - -
- -
- {convertDateFormat(job.createdAt.substr(0, 10))} - {job.employmentType} - {job.location} -
- - - - - - ) -} + const day = parts[2]; + const month = parts[1]; + const year = parts[0]; + + return `${day}-${month}-${year}`; + }; + + const isMobile = useIsMobile(); + + return ( + <> + +
+
+ +
+
+
+

{job.title}

+
+
+
+

{job.companyName}

+

{job.exp}

+ {!isMobile && ( +

+ {job.description.slice(0, 64)}... +

+ )} +

+ {job.description.slice(0, 39)}... +

+
+
+ +
+
+
+
+ +
+ {convertDateFormat(job.createdAt.substr(0, 10))} + {job.employmentType} + {job.location} +
+ + + ); +}; diff --git a/client/src/components/Navbar.jsx b/client/src/components/Navbar.jsx index 97cf8ab..214deb6 100644 --- a/client/src/components/Navbar.jsx +++ b/client/src/components/Navbar.jsx @@ -1,125 +1,177 @@ -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import { Avatar } from '@mantine/core'; -import { FaBars } from 'react-icons/fa'; -import { RxCross1 } from 'react-icons/rx'; -import { MdOutlineBusinessCenter, MdOutlineDashboard } from 'react-icons/md'; -import { Menu } from '@mantine/core'; -import { FaUserCircle, FaSave } from 'react-icons/fa'; -import { MdDoneAll } from 'react-icons/md'; -import { RiLogoutBoxFill } from 'react-icons/ri'; -import { toast } from 'react-toastify'; -import { useSelector, useDispatch } from 'react-redux'; -import { logOrNot } from '../actions/UserActions'; -import { useNavigate } from 'react-router-dom'; -import { logoutClearState } from '../slices/UserSlice'; -import { motion } from "framer-motion"; -import useIsMobile from '../hooks/useIsMobile'; +import React, { useState, useEffect } from "react"; +import { Link, useLocation } from "react-router-dom"; +import { Avatar, Menu } from "@mantine/core"; +import { FaBars } from "react-icons/fa"; +import { RxCross1 } from "react-icons/rx"; +import { + MdOutlineBusinessCenter, + MdOutlineDashboard, + MdDoneAll, +} from "react-icons/md"; +import { FaUserCircle, FaSave } from "react-icons/fa"; +import { RiLogoutBoxFill } from "react-icons/ri"; +import { toast } from "react-toastify"; +import { useSelector, useDispatch } from "react-redux"; +import { logOrNot } from "../actions/UserActions"; +import { useNavigate } from "react-router-dom"; +import { logoutClearState } from "../slices/UserSlice"; +import useIsMobile from "../hooks/useIsMobile"; -export const Navbar = () => { - const { isLogin, me } = useSelector(state => state.user); - const [toggle, setToggle] = useState(false); - const dispatch = useDispatch(); - const navigate = useNavigate(); - - - const isMobile = useIsMobile() - - const LogOut = () => { - localStorage.removeItem('userToken'); - localStorage.removeItem('role'); - dispatch(logOrNot()); - navigate('/'); - toast.success("Logout Successful !"); - dispatch(logoutClearState()); - } +const NavLinks = ({ onClick }) => ( + <> + + Home + + + Jobs + + + Contact + + + About + + +); - return ( - <> -
- {!isMobile && } + // Prevent scroll when menu is open + useEffect(() => { + if (isMenuOpen) { + document.body.style.overflow = "hidden"; + } else { + document.body.style.overflow = "unset"; + } + return () => { + document.body.style.overflow = "unset"; + }; + }, [isMenuOpen]); -
- - JOBLANE - -
-
- {isLogin ? ( - - - - + const LogOut = () => { + localStorage.removeItem("userToken"); + localStorage.removeItem("role"); + dispatch(logOrNot()); + dispatch(logoutClearState()); + navigate("/"); + toast.success("Logout Successful!"); + }; - - }>My Profile - {me.role === "admin" && }>Dashboard} - }>Applied Jobs - }>Saved Jobs - - }>Logout - - - ) : ( - - Login - Register - - )} -
+ const toggleMenu = () => setIsMenuOpen(!isMenuOpen); -
- {toggle ? ( - setToggle(!toggle)} /> - ) : ( - setToggle(!toggle)} /> - )} -
-
-
+ const AuthButtons = () => ( +
+ + Login + + + Register + +
+ ); -
+ return ( + + ); +}; diff --git a/client/src/pages/Home.jsx b/client/src/pages/Home.jsx index 4e524fc..4743c78 100644 --- a/client/src/pages/Home.jsx +++ b/client/src/pages/Home.jsx @@ -1,250 +1,262 @@ -import React, { useEffect, useState } from 'react' -import { Link } from 'react-router-dom' -import { MetaData } from '../components/MetaData' -import { useSelector, useDispatch } from 'react-redux'; -import { JobCard } from '../components/JobCard'; -import { getAllJobs } from '../actions/JobActions'; -import Testimonials from '../components/Testimonials/Testimonials.jsx'; - - +import React, { useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { MetaData } from "../components/MetaData"; +import { useSelector, useDispatch } from "react-redux"; +import { JobCard } from "../components/JobCard"; +import { getAllJobs } from "../actions/JobActions"; +import Testimonials from "../components/Testimonials/Testimonials.jsx"; export const Home = () => { - - const [num, setNum] = useState(2); - const dispatch = useDispatch() - const { loading, allJobs } = useSelector(state => state.job) - const [jobs, setJobs] = useState([]) - - - const data = [ - { - link: "/images/JobData/1.jpg" - }, - { - link: "/images/JobData/2.jpg" - }, - { - link: "/images/JobData/3.jpg" - }, - { - link: "/images/JobData/4.jpg" - }, - { - link: "/images/JobData/5.jpg" - }, - { - link: "/images/JobData/6.jpg" - }, - { - link: "/images/JobData/7.jpg" - }, - { - link: "/images/JobData/8.jpg" - }, - { - link: "/images/JobData/9.jpg" - }, - { - link: "/images/JobData/10.jpg" - }, - { - link: "/images/JobData/11.jpg" - }, - { - link: "/images/JobData/12.jpg" - }, - { - link: "/images/JobData/13.jpg" - }, - { - link: "/images/JobData/14.jpg" - }, - { - link: "/images/JobData/15.jpg" - }, - { - link: "/images/JobData/16.jpg" - }, - { - link: "/images/JobData/17.jpg" - }, - { - link: "/images/JobData/18.jpg" - }, - { - link: "/images/JobData/19.jpg" - }, - { - link: "/images/JobData/20.jpg" - } - ] - - - useEffect(() => { - dispatch(getAllJobs()) - - }, []) - - - - const convertDateFormat = (inputDate) => { - const parts = inputDate.split('-'); - if (parts.length !== 3) { - return "Invalid date format"; - } - - const day = parts[2]; - const month = parts[1]; - const year = parts[0]; - - return `${day}-${month}-${year}`; + const [num, setNum] = useState(2); + const dispatch = useDispatch(); + const { loading, allJobs } = useSelector((state) => state.job); + const [jobs, setJobs] = useState([]); + + const data = [ + { + link: "/images/JobData/1.jpg", + }, + { + link: "/images/JobData/2.jpg", + }, + { + link: "/images/JobData/3.jpg", + }, + { + link: "/images/JobData/4.jpg", + }, + { + link: "/images/JobData/5.jpg", + }, + { + link: "/images/JobData/6.jpg", + }, + { + link: "/images/JobData/7.jpg", + }, + { + link: "/images/JobData/8.jpg", + }, + { + link: "/images/JobData/9.jpg", + }, + { + link: "/images/JobData/10.jpg", + }, + { + link: "/images/JobData/11.jpg", + }, + { + link: "/images/JobData/12.jpg", + }, + { + link: "/images/JobData/13.jpg", + }, + { + link: "/images/JobData/14.jpg", + }, + { + link: "/images/JobData/15.jpg", + }, + { + link: "/images/JobData/16.jpg", + }, + { + link: "/images/JobData/17.jpg", + }, + { + link: "/images/JobData/18.jpg", + }, + { + link: "/images/JobData/19.jpg", + }, + { + link: "/images/JobData/20.jpg", + }, + ]; + + useEffect(() => { + dispatch(getAllJobs()); + }, []); + + const convertDateFormat = (inputDate) => { + const parts = inputDate.split("-"); + if (parts.length !== 3) { + return "Invalid date format"; } - return ( - - - <> - -
-
- -
-
JOBLANE
-
- Browse Jobs -
-
-
-

Your gateway to job opportunities.

- -
- - -
-
-

Featured Jobs

-
-
- { - loading ? -
- - - -
: -
-
- - {allJobs && allJobs.length >= 4 ? ( - <> - -
-
- {allJobs[3].title} -
-
-

{allJobs[3].title}

-

{allJobs[3].companyName}

-

{allJobs[3].description.slice(0, 30) + "..."}

-
-
-
- {convertDateFormat(allJobs[3].createdAt.slice(0,10))} - - {allJobs[3].employmentType} - - - {allJobs[3].location} - -
- - - -
-
- {allJobs[5].title} -
-
-

{allJobs[5].title}

-

{allJobs[5].companyName}

-

{allJobs[5].description.slice(0, 30) + "..."}

-
-
-
- {convertDateFormat(allJobs[3].createdAt.slice(0,10))} - - {allJobs[5].employmentType} - - - {allJobs[5].location} - -
- - - -
-
- {allJobs[2].title} -
-
-

{allJobs[2].title}

-

{allJobs[2].companyName}

-

{allJobs[2].description.slice(0, 30) + "..."}

-
-
-
- {convertDateFormat(allJobs[2].createdAt.slice(0,10))} - - {allJobs[2].employmentType} - - - {allJobs[2].location} - -
- - - - - ) : null} - - -
- -
- } -
- -
- - -
-
- Companies on our site -
-
- { - data.map((e, i) => ( -
- -
- )) - } -
-
- - - - -
-

Discover the Power of Possibility with JobLane: Where Your Professional Journey Takes Flight, Guided by a Network of Diverse Opportunities!

-
- - + const day = parts[2]; + const month = parts[1]; + const year = parts[0]; + + return `${day}-${month}-${year}`; + }; + + return ( + <> + +
+
+
+
JOBLANE
+
+ + Browse Jobs + +
+
+
+

+ Your gateway to job + opportunities. +

+
+ +
+
+

Featured Jobs

+
+
+ {loading ? ( +
+
- + ) : ( +
+
+ {allJobs && allJobs.length >= 4 ? ( + <> + +
+
+ {allJobs[3].title} +
+
+

{allJobs[3].title}

+ + {allJobs[3].companyName} + +

+ {allJobs[3].description.slice(0, 30) + "..."} +

+
+
+
+ + {convertDateFormat( + allJobs[3].createdAt.slice(0, 10) + )} + + {allJobs[3].employmentType} + {allJobs[3].location} +
+ + + +
+
+ {allJobs[5].title} +
+
+

{allJobs[5].title}

+

+ {allJobs[5].companyName} +

+

+ {allJobs[5].description.slice(0, 30) + "..."} +

+
+
+
+ + {convertDateFormat( + allJobs[5].createdAt.slice(0, 10) + )} + + {allJobs[5].employmentType} + {allJobs[5].location} +
+ + + +
+
+ {allJobs[2].title} +
+
+

{allJobs[2].title}

+

+ {allJobs[2].companyName} +

+

+ {allJobs[2].description.slice(0, 30) + "..."} +

+
+
+
+ + {convertDateFormat( + allJobs[2].createdAt.slice(0, 10) + )} + + {allJobs[2].employmentType} + {allJobs[2].location} +
+ + + ) : null} +
+
+ )}
- - - - ) -} +
+ +
+
Companies on our site
+
+ {data.map((e, i) => ( +
+ +
+ ))} +
+
+ + + +
+

+ Discover the Power of Possibility with JobLane: Where Your + Professional Journey Takes Flight, Guided by a Network of Diverse + Opportunities! +

+
+
+
+ + ); +}; diff --git a/client/src/pages/Jobs.jsx b/client/src/pages/Jobs.jsx index 81162fb..8e3b41c 100644 --- a/client/src/pages/Jobs.jsx +++ b/client/src/pages/Jobs.jsx @@ -1,20 +1,18 @@ -import React, { useEffect, useState } from 'react' -import { MetaData } from '../components/MetaData' -import { FiSearch } from 'react-icons/fi' -import { Loader } from '../components/Loader' -import { JobCard } from '../components/JobCard' -import { useDispatch, useSelector } from 'react-redux' -import { getAllJobs, getSingleJob } from '../actions/JobActions' -import { Slider } from '@mantine/core'; -import { RxCross2 } from 'react-icons/rx' -import { Pagination } from '@mantine/core'; -import useIsMobile from '../hooks/useIsMobile' - +import React, { useEffect, useState } from "react"; +import { MetaData } from "../components/MetaData"; +import { FiSearch } from "react-icons/fi"; +import { Loader } from "../components/Loader"; +import { JobCard } from "../components/JobCard"; +import { useDispatch, useSelector } from "react-redux"; +import { getAllJobs, getSingleJob } from "../actions/JobActions"; +import { Slider } from "@mantine/core"; +import { RxCross2 } from "react-icons/rx"; +import { Pagination } from "@mantine/core"; +import useIsMobile from "../hooks/useIsMobile"; export const Jobs = () => { - - const dispatch = useDispatch() - const { allJobs, loading } = useSelector(state => state.job) + const dispatch = useDispatch(); + const { allJobs, loading } = useSelector((state) => state.job); const [baseJobs, setBaseJobs] = useState([]); // New state for base jobs const [jobs, setJobs] = useState([]); @@ -26,11 +24,9 @@ export const Jobs = () => { const [currentPage, setCurrentPage] = useState(1); + const isMobile = useIsMobile(); - const isMobile = useIsMobile() - - - const data = ["Technology", "Marketing", "Finance", "Sales", "Legal"] + const data = ["Technology", "Marketing", "Finance", "Sales", "Legal"]; const companyData = [ "Google", @@ -38,112 +34,94 @@ export const Jobs = () => { "Paypal", "Samsung", "Amazon", - "Oracle" - ] + "Oracle", + ]; - console.log(allJobs.length) + console.log(allJobs.length); useEffect(() => { dispatch(getAllJobs()); - }, []) + }, []); useEffect(() => { setJobs(allJobs); setBaseJobs(allJobs); // Set base jobs when allJobs changes - }, [allJobs]) + }, [allJobs]); useEffect(() => { - const searchArr = baseJobs.filter((e) => ( + const searchArr = baseJobs.filter((e) => e.title.toLowerCase().includes(search.toLowerCase().trim()) - )) + ); if (search === "") { - - setJobs(baseJobs) + setJobs(baseJobs); } else { - - setJobs(searchArr) + setJobs(searchArr); } - - }, [search, baseJobs]) - - - - - + }, [search, baseJobs]); const searchHandler = () => { - console.log(search); - const searchArr = baseJobs.filter((e) => ( + const searchArr = baseJobs.filter((e) => e.title.toLowerCase().includes(search.toLowerCase()) - )) - - + ); if (search !== "") { - setJobs(searchArr) - } - else if (searchArr.length === 0) { - setJobs(baseJobs) + setJobs(searchArr); + } else if (searchArr.length === 0) { + setJobs(baseJobs); } - - } + }; const leftFilter = (jobsList) => { if (category == "" && salary == 0) { - setJobs(allJobs) - return + setJobs(allJobs); + return; } - const leftFilArr = jobsList.filter((item) => ( - item.category.toLowerCase() === category.toLowerCase() && parseInt(item.salary) >= salary - )) - setJobs(leftFilArr) - } - + const leftFilArr = jobsList.filter( + (item) => + item.category.toLowerCase() === category.toLowerCase() && + parseInt(item.salary) >= salary + ); + setJobs(leftFilArr); + }; const removeLeftFilter = () => { - setCategory("") - setSalary(0) - rightFilter(allJobs) - setCurrentPage(1) - } + setCategory(""); + setSalary(0); + rightFilter(allJobs); + setCurrentPage(1); + }; const rightFilter = (jobsList) => { if (company == "") { - setJobs(allJobs) - return + setJobs(allJobs); + return; } - const rightFilArr = jobsList.filter((item) => ( - item.companyName.toLowerCase() === company.toLowerCase() - )) - setJobs(rightFilArr) - - } + const rightFilArr = jobsList.filter( + (item) => item.companyName.toLowerCase() === company.toLowerCase() + ); + setJobs(rightFilArr); + }; const removeRightFilter = () => { - setCompany("") - leftFilter(allJobs) - setCurrentPage(1) - } - - - - - + setCompany(""); + leftFilter(allJobs); + setCurrentPage(1); + }; - // Pagination + // Pagination const itemsPerPage = 5; const totalPageCount = Math.ceil(jobs.length / itemsPerPage); const handleNextPage = () => { - setCurrentPage(prevPage => Math.min(prevPage + 1, totalPageCount)); + setCurrentPage((prevPage) => Math.min(prevPage + 1, totalPageCount)); }; const handlePrevPage = () => { - setCurrentPage(prevPage => Math.max(prevPage - 1, 1)); + setCurrentPage((prevPage) => Math.max(prevPage - 1, 1)); }; const handlePageChange = (page) => { @@ -166,122 +144,151 @@ export const Jobs = () => { ); } - // Pagination - - + // Pagination return ( <> -
- - - {loading ? : +
+ {loading ? ( + + ) : ( <> -
-
+
+

Find your dream job now

-
- -
-
-
- setSearch(e.target.value)} type="text" className='outline-none bold-placeholder text-black px-2 pl-3 sm:h-10 w-full h-8 py-1 text-sm' /> -
setSearch("")} size={19} className={`cursor-pointer +
+
+
+
+ {" "} + {" "} +
+ setSearch(e.target.value)} + type="text" + className="outline-none bold-placeholder text-black px-2 pl-3 sm:h-10 w-full h-8 py-1 text-sm" + /> +
+ setSearch("")} + size={19} + className={`cursor-pointer ${search.length !== 0 ? "flex" : "hidden"} - `} />
- + `} + /> +
+
- -
+
+ {!isMobile && ( +
+
+

+ Categories +

+
    + {data.map((e, i) => ( +
  • setCategory(e)} + className={`hover:text-yellow-600 cursor-pointer ${ + category === e ? "text-yellow-600" : "" + } `} + > + {e} +
  • + ))} +
+
+

+ Salary +

+ + +
-
- - {!isMobile &&
-
-

Categories

-
    - - { - data.map((e, i) => ( -
  • setCategory(e)} className={`hover:text-yellow-600 cursor-pointer ${category === e ? "text-yellow-600" : ""} `}>{e}
  • - )) - } - -
-
-

Salary

- - -
- - -
- - +
+ + +
-
+ )} -
} - - - -
- -
- +
+
{ // jobs && jobs - jobs && displayedData - .filter(job => job._id) - .sort((a, b) => { - const dateA = new Date(a.createdAt); - const dateB = new Date(b.createdAt); - return dateB - dateA; - }).map((job, i) => ( - { - dispatch(getSingleJob(job._id)) - }} - key={i} - job={job} /> - - )) - + jobs && + displayedData + .filter((job) => job._id) + .sort((a, b) => { + const dateA = new Date(a.createdAt); + const dateB = new Date(b.createdAt); + return dateB - dateA; + }) + .map((job, i) => ( + { + dispatch(getSingleJob(job._id)); + }} + key={i} + job={job} + /> + )) } - - -
+
No Jobs available according to your preferences
-
- -
-
- - +
{/* Pagination */}
- {pageButtons} -
- {/* Mobile Filters */} -
- -
-
-

Categories

-
    - - { - data.map((e, i) => ( -
  • setCategory(e)} className={`hover:text-yellow-600 cursor-pointer ${category === e ? "text-yellow-600" : ""} `}>{e}
  • - )) - } - +
    +
    +
    +

    + Categories +

    +
      + {data.map((e, i) => ( +
    • setCategory(e)} + className={`hover:text-yellow-600 cursor-pointer ${ + category === e ? "text-yellow-600" : "" + } `} + > + {e} +
    • + ))}
    -
    -

    Salary

    +
    +

    + Salary +

    { />
    - -
    - - +
    + +
    -
    -
    -
    -
    -

    Companies

    - -
    - { - companyData.map(e => ( -
    setCompany(e)} className={`${company === e ? "text-yellow-600" : ""} cursor-pointer text-sm hover:text-yellow-600`} >{e}
    - )) - } +
    +
    +

    + Companies +

    + +
    + {companyData.map((e) => ( +
    setCompany(e)} + className={`${ + company === e ? "text-yellow-600" : "" + } cursor-pointer text-sm hover:text-yellow-600`} + > + {e} +
    + ))}
    -
    - - +
    + +
    -
    - - - - -
    -
    - - - {!isMobile &&
    -
    -

    Companies

    - -
    - { - companyData.map(e => ( -
    setCompany(e)} className={`${company === e ? "text-yellow-600" : ""} cursor-pointer hover:text-yellow-600`} >{e}
    - )) - } -
    -
    - - + {!isMobile && ( +
    +
    +

    + Companies +

    + +
    + {companyData.map((e) => ( +
    setCompany(e)} + className={`${ + company === e ? "text-yellow-600" : "" + } cursor-pointer hover:text-yellow-600`} + > + {e} +
    + ))} +
    +
    + + +
    - -
    } - - - - - - - - - - + )}
    -
    - } - - + )}
    - - ) -} + ); +};