Skip to content

Commit

Permalink
skeleton loading added to job description
Browse files Browse the repository at this point in the history
  • Loading branch information
sudhanshuGt committed Jul 25, 2024
1 parent 7eb7348 commit 7df21e8
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 72 deletions.
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"next-themes": "^0.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-loading-skeleton": "^3.4.0",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.1",
"react-scripts": "^5.0.1",
Expand Down
61 changes: 27 additions & 34 deletions src/components/JobDescription.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,25 @@ import Navbar from './shared/Navbar';
import Footer from './shared/Footer';
import { MapPin } from 'lucide-react';
import { BuildOutlined, NoLuggageOutlined } from '@mui/icons-material';
import Skeleton from 'react-loading-skeleton';
import 'react-loading-skeleton/dist/skeleton.css';

const JobDescription = () => {
const { singleJobById } = useSelector(store => store.job);
const { authUser } = useSelector(store => store.auth);

const isInitiallyApplied = singleJobById?.applications?.some(application => application.applicant === authUser?._id) || false;
const [isApplied, setIsApplied] = useState(isInitiallyApplied);
const [loading, setLoading] = useState(true);

const dispatch = useDispatch();
const params = useParams();

const applyJobHandler = async () => {

window.open(singleJobById?.link, '_blank');

// feature to saved applied job in profile section..can be implemeted later

// if( authUser?.id == NoLuggageOutlined){
// window.open(singleJobById?.link, '_blank');
// }else{
// try {
// axios.defaults.withCredentials = true;
// const res = await axios.get(`http://localhost:8000/api/v1/application/apply/${params.id}`);
// if (res.data.success) {
// setIsApplied(true); // Update the local state
// const updatedJob = { ...singleJobById, applications: [...singleJobById.applications, { applicant: authUser._id }] };
// dispatch(setSingleJobById(updatedJob));
// toast.success(res.data.message);
// window.open(singleJobById?.link, '_blank');
// }
// } catch (error) {
// console.log(error);
// toast.error(error.response.data.message);
// }
// }
};

useEffect(() => {

const fetchSingleJob = async () => {
try {
axios.defaults.withCredentials = true;
Expand All @@ -59,6 +39,8 @@ const JobDescription = () => {
}
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
};
fetchSingleJob();
Expand All @@ -84,41 +66,52 @@ const JobDescription = () => {
<div className='max-w-7xl mx-auto my-10 p-4 sm:px-6 lg:px-8'>
<div className='flex flex-col sm:flex-row items-start sm:items-center justify-between'>
<div>
<h1 className='font-bold text-2xl mb-2'>{singleJobById?.title} ({singleJobById?.experienceLevel} Year Exp.)</h1>
<h1 className='font-bold text-2xl mb-2'>
{loading ? <Skeleton width={300} /> : `${singleJobById?.title} (${singleJobById?.experienceLevel} Year Exp.)`}
</h1>
<div className='flex items-center gap-2 my-2'>
<MapPin className='text-red-500' />
<span className='text-gray-800'>{singleJobById?.location}</span>
<span className='text-gray-800'>{loading ? <Skeleton width={150} /> : singleJobById?.location}</span>
</div>


<div className='flex items-center gap-2'>
<Badge className='text-blue-700 font-bold' variant='ghost'>{singleJobById?.position} Positions</Badge>
<Badge className='text-[#F83002] font-bold' variant='ghost'>{singleJobById?.jobType}</Badge>
<Badge className='text-[#7209b7] font-bold' variant='ghost'>{singleJobById?.salary} LPA</Badge>
{loading ? (
<>
<Skeleton width={100} height={24} />
<Skeleton width={100} height={24} />
<Skeleton width={100} height={24} />
</>
) : (
<>
<Badge className='text-blue-700 font-bold' variant='ghost'>{singleJobById?.position} Positions</Badge>
<Badge className='text-[#F83002] font-bold' variant='ghost'>{singleJobById?.jobType}</Badge>
<Badge className='text-[#7209b7] font-bold' variant='ghost'>{singleJobById?.salary} LPA</Badge>
</>
)}
</div>
</div>
<Button
onClick={applyJobHandler}
className={`rounded-lg mt-4 sm:mt-0 ${isApplied ? "bg-gray-600 cursor-not-allowed" : "bg-[#7209b7] hover:bg-[#5f32ad]"}`}
disabled={loading || isApplied}
>
{isApplied ? "Already Applied" : "Apply Now"}
{loading ? <Skeleton width={100} /> : isApplied ? "Already Applied" : "Apply Now"}
</Button>
</div>
<div className='my-4'>
<h1 className='border-b-2 pb-1 border-b-gray-300 font-medium text-lg'>Job Description</h1>
</div>
<div className='text-gray-800'>
{singleJobById?.description}
{loading ? <Skeleton count={5} /> : singleJobById?.description}
</div>
{singleJobById?.responsibility && (
{singleJobById?.responsibility && !loading && (
<div className='my-4'>
<h1 className='border-b-2 pb-1 border-b-gray-300 font-medium text-lg'>Responsibility</h1>
<ul className='text-gray-800'>
{renderList(singleJobById.responsibility)}
</ul>
</div>
)}
{singleJobById?.qualification && (
{singleJobById?.qualification && !loading && (
<div className='my-4'>
<h1 className='border-b-2 pb-1 border-b-gray-300 font-medium text-lg'>Qualification</h1>
<ul className='text-gray-800'>
Expand Down
85 changes: 47 additions & 38 deletions src/components/Jobs.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import React, { useEffect, useState } from 'react'
import Navbar from './shared/Navbar'
import FilterCard from './FilterCard'
import Job from './Job'
import Footer from './shared/Footer'
import { useSelector } from 'react-redux'
import { useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import Jobnotfound from './Jobnotfound'
import React, { useEffect, useState } from 'react';
import Navbar from './shared/Navbar';
import FilterCard from './FilterCard';
import Job from './Job';
import Footer from './shared/Footer';
import { useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { motion } from 'framer-motion';
import Jobnotfound from './Jobnotfound';
import Skeleton from 'react-loading-skeleton';
import 'react-loading-skeleton/dist/skeleton.css';

const Jobs = () => {
const { authUser } = useSelector((store) => store.auth);
const { allJobs, searchText } = useSelector((store) => store.job);
const [filterJobs, setFilterJobs] = useState(allJobs);
const [loading, setLoading] = useState(true);
const navigate = useNavigate();

useEffect(() => {
Expand All @@ -20,19 +23,24 @@ const Jobs = () => {
return job.title.toLowerCase().includes(searchText.toLowerCase()) ||
job.description.toLowerCase().includes(searchText.toLowerCase()) ||
job?.location?.toLowerCase().includes(searchText.toLowerCase())
})
});
setFilterJobs(filteredJobs);
} else {
setFilterJobs(allJobs);
}
}, [allJobs, searchText]);

// Introducing a 1-second manual delay
setTimeout(() => {
setLoading(false);
}, 1000);
}, [allJobs, searchText]);

useEffect(() => {
if (authUser?.role === 'recruiter') {
navigate("/admin/jobs");
}
})
}, [authUser, navigate]);

return (
<div className='bg-gray-100 h-screen'>
<Navbar />
Expand All @@ -41,34 +49,35 @@ const Jobs = () => {
<div className='w-[20%]'>
<FilterCard />
</div>
{
filterJobs.length <= 0 ? <Jobnotfound /> : (
<div className='flex-1 h-[88vh] overflow-y-auto no-scrollbar pb-5'>
<div className='grid grid-cols-3 gap-4'>
{
filterJobs && filterJobs.map((job) => (
<motion.div
key={job._id}
initial={{ opacity: 0, x: 100 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -100 }}
transition={{ duration: 0.3 }}
>
<Job job={job} />
</motion.div>
))
}

</div>
<div className='flex-1 h-[88vh] overflow-y-auto no-scrollbar pb-5'>
{loading ? (
<div className='grid grid-cols-3 gap-4'>
{Array(9).fill().map((_, index) => (
<Skeleton key={index} height={200} />
))}
</div>
)
}

</div>
) : filterJobs.length <= 0 ? (
<Jobnotfound />
) : (
<div className='grid grid-cols-3 gap-4'>
{filterJobs.map((job) => (
<motion.div
key={job._id}
initial={{ opacity: 0, x: 100 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -100 }}
transition={{ duration: 0.3 }}
>
<Job job={job} />
</motion.div>
))}
</div>
)}
</div>
</div>
</div>
</div>

)
);
}

export default Jobs
export default Jobs;

0 comments on commit 7df21e8

Please sign in to comment.