Skip to content

Commit 48b1e64

Browse files
committed
JSON server and fetch listings
1 parent 1b43800 commit 48b1e64

14 files changed

+694
-130
lines changed

package-lock.json

Lines changed: 480 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
"dev": "vite",
88
"build": "vite build",
99
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10-
"preview": "vite preview"
10+
"preview": "vite preview",
11+
"server": "json-server --watch src/jobs.json --port 8000"
1112
},
1213
"dependencies": {
1314
"react": "^18.2.0",
1415
"react-dom": "^18.2.0",
1516
"react-icons": "^5.0.1",
16-
"react-router-dom": "^6.22.3"
17+
"react-router-dom": "^6.22.3",
18+
"react-spinners": "^0.13.8"
1719
},
1820
"devDependencies": {
1921
"@types/react": "^18.2.64",
@@ -24,6 +26,7 @@
2426
"eslint-plugin-react": "^7.34.0",
2527
"eslint-plugin-react-hooks": "^4.6.0",
2628
"eslint-plugin-react-refresh": "^0.4.5",
29+
"json-server": "^1.0.0-alpha.23",
2730
"postcss": "^8.4.35",
2831
"tailwindcss": "^3.4.1",
2932
"vite": "^5.1.6"

src/App.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@ import {
66
} from 'react-router-dom';
77
import MainLayout from './layouts/MainLayout';
88
import HomePage from './pages/HomePage';
9+
import JobsPage from './pages/JobsPage';
10+
import NotFoundPage from './pages/NotFoundPage';
911

1012
const router = createBrowserRouter(
1113
createRoutesFromElements(
1214
<Route path='/' element={<MainLayout />}>
1315
<Route index element={<HomePage />} />
16+
<Route path='/jobs' element={<JobsPage />} />
17+
<Route path='*' element={<NotFoundPage />} />
1418
</Route>
1519
)
1620
);

src/components/HomeCards.jsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Link } from 'react-router-dom';
12
import Card from './Card';
23

34
const HomeCards = () => {
@@ -10,24 +11,24 @@ const HomeCards = () => {
1011
<p className='mt-2 mb-4'>
1112
Browse our React jobs and start your career today
1213
</p>
13-
<a
14-
href='/jobs.html'
14+
<Link
15+
to='/jobs'
1516
className='inline-block bg-black text-white rounded-lg px-4 py-2 hover:bg-gray-700'
1617
>
1718
Browse Jobs
18-
</a>
19+
</Link>
1920
</Card>
2021
<Card bg='bg-indigo-100'>
2122
<h2 className='text-2xl font-bold'>For Employers</h2>
2223
<p className='mt-2 mb-4'>
2324
List your job to find the perfect developer for the role
2425
</p>
25-
<a
26-
href='/add-job.html'
26+
<Link
27+
to='/add-job'
2728
className='inline-block bg-indigo-500 text-white rounded-lg px-4 py-2 hover:bg-indigo-600'
2829
>
2930
Add Job
30-
</a>
31+
</Link>
3132
</Card>
3233
</div>
3334
</div>

src/components/JobListing.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useState } from 'react';
22
import { FaMapMarker } from 'react-icons/fa';
3+
import { Link } from 'react-router-dom';
34

45
const JobListing = ({ job }) => {
56
const [showFullDescription, setShowFullDescription] = useState(false);
@@ -36,12 +37,12 @@ const JobListing = ({ job }) => {
3637
<FaMapMarker className='inline text-lg mb-1 mr-1' />
3738
{job.location}
3839
</div>
39-
<a
40-
href={`/job/${job.id}`}
40+
<Link
41+
to={`/job/${job.id}`}
4142
className='h-[36px] bg-indigo-500 hover:bg-indigo-600 text-white px-4 py-2 rounded-lg text-center text-sm'
4243
>
4344
Read More
44-
</a>
45+
</Link>
4546
</div>
4647
</div>
4748
</div>

src/components/JobListings.jsx

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
1+
import { useState, useEffect } from 'react';
12
import JobListing from './JobListing';
2-
import jobs from '../jobs.json';
3+
import Spinner from './Spinner';
34

4-
const JobListings = () => {
5-
const recentJobs = jobs.slice(0, 3);
5+
const JobListings = ({ isHome = false }) => {
6+
const [jobs, setJobs] = useState([]);
7+
const [loading, setLoading] = useState(true);
8+
9+
useEffect(() => {
10+
const fetchJobs = async () => {
11+
const apiUrl = isHome ? '/api/jobs?_limit=3' : '/api/jobs';
12+
try {
13+
const res = await fetch(apiUrl);
14+
const data = await res.json();
15+
setJobs(data);
16+
} catch (error) {
17+
console.log('Error fetching data', error);
18+
} finally {
19+
setLoading(false);
20+
}
21+
};
22+
23+
fetchJobs();
24+
}, []);
625

726
return (
827
<section className='bg-blue-50 px-4 py-10'>
928
<div className='container-xl lg:container m-auto'>
1029
<h2 className='text-3xl font-bold text-indigo-500 mb-6 text-center'>
11-
Browse Jobs
30+
{isHome ? 'Recent Jobs' : 'Browse Jobs'}
1231
</h2>
13-
<div className='grid grid-cols-1 md:grid-cols-3 gap-6'>
14-
{recentJobs.map((job) => (
15-
<JobListing key={job.id} job={job} />
16-
))}
17-
</div>
32+
33+
{loading ? (
34+
<Spinner loading={loading} />
35+
) : (
36+
<div className='grid grid-cols-1 md:grid-cols-3 gap-6'>
37+
{jobs.map((job) => (
38+
<JobListing key={job.id} job={job} />
39+
))}
40+
</div>
41+
)}
1842
</div>
1943
</section>
2044
);

src/components/Navbar.jsx

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,34 @@
1+
import { NavLink } from 'react-router-dom';
12
import logo from '../assets/images/logo.png';
23

34
const Navbar = () => {
5+
const linkClass = ({ isActive }) =>
6+
isActive
7+
? 'bg-black text-white hover:bg-gray-900 hover:text-white rounded-md px-3 py-2'
8+
: 'text-white hover:bg-gray-900 hover:text-white rounded-md px-3 py-2';
9+
410
return (
511
<nav className='bg-indigo-700 border-b border-indigo-500'>
612
<div className='mx-auto max-w-7xl px-2 sm:px-6 lg:px-8'>
713
<div className='flex h-20 items-center justify-between'>
814
<div className='flex flex-1 items-center justify-center md:items-stretch md:justify-start'>
9-
<a
10-
className='flex flex-shrink-0 items-center mr-4'
11-
href='/index.html'
12-
>
15+
<NavLink className='flex flex-shrink-0 items-center mr-4' to='/'>
1316
<img className='h-10 w-auto' src={logo} alt='React Jobs' />
1417
<span className='hidden md:block text-white text-2xl font-bold ml-2'>
1518
React Jobs
1619
</span>
17-
</a>
20+
</NavLink>
1821
<div className='md:ml-auto'>
1922
<div className='flex space-x-2'>
20-
<a
21-
href='/index.html'
22-
className='text-white bg-black hover:bg-gray-900 hover:text-white rounded-md px-3 py-2'
23-
>
23+
<NavLink to='/' className={linkClass}>
2424
Home
25-
</a>
26-
<a
27-
href='/jobs.html'
28-
className='text-white hover:bg-gray-900 hover:text-white rounded-md px-3 py-2'
29-
>
25+
</NavLink>
26+
<NavLink to='/jobs' className={linkClass}>
3027
Jobs
31-
</a>
32-
<a
33-
href='/add-job.html'
34-
className='text-white hover:bg-gray-900 hover:text-white rounded-md px-3 py-2'
35-
>
28+
</NavLink>
29+
<NavLink to='/add-job' className={linkClass}>
3630
Add Job
37-
</a>
31+
</NavLink>
3832
</div>
3933
</div>
4034
</div>

src/components/Spinner.jsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import ClipLoader from 'react-spinners/ClipLoader';
2+
3+
const override = {
4+
display: 'block',
5+
margin: '100px auto',
6+
};
7+
8+
const Spinner = ({ loading }) => {
9+
return (
10+
<ClipLoader
11+
color='#4338ca'
12+
loading={loading}
13+
cssOverride={override}
14+
size={150}
15+
/>
16+
);
17+
};
18+
export default Spinner;

src/components/ViewAllJobs.jsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
import { Link } from 'react-router-dom';
2+
13
const ViewAllJobs = () => {
24
return (
35
<section className='m-auto max-w-lg my-10 px-6'>
4-
<a
5-
href='/jobs'
6+
<Link
7+
to='/jobs'
68
className='block bg-black text-white text-center py-4 px-6 rounded-xl hover:bg-gray-700'
79
>
810
View All Jobs
9-
</a>
11+
</Link>
1012
</section>
1113
);
1214
};

0 commit comments

Comments
 (0)