Skip to content

Commit

Permalink
Make dynamic page fetching data from database
Browse files Browse the repository at this point in the history
  • Loading branch information
Soohyeun committed May 13, 2024
1 parent 41474e3 commit 59a277d
Show file tree
Hide file tree
Showing 13 changed files with 1,060 additions and 4 deletions.
502 changes: 502 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2",
"axios": "^1.6.8",
"babel": "^6.23.0",
"class-variance-authority": "^0.7.0",
Expand Down
1 change: 1 addition & 0 deletions public/placeholder.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions src/app/jobsite2/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Libre_Franklin, Cormorant_Garamond } from 'next/font/google';
import Top2 from '@/components/jobsite2/Top2';
import Footer from '@/components/Footer';

const libre_franklin = Libre_Franklin({
subsets: ['latin'],
display: 'swap',
variable: '--font-libre_franklin',
});
const cormorant_garamond = Cormorant_Garamond({
subsets: ['latin'],
display: 'swap',
variable: '--font-cormorant_garamond',
weight: ['400', '500', '600'],
});

// Todo: Change metadata
export const metadata = {
title: 'Job Site #2',
description: 'Generate Job listings',
};

export default function RootLayout({ children }) {
return (
<html lang="en">
<body
suppressHydrationWarning
className={libre_franklin.variable + ' ' + cormorant_garamond.variable}>
<Top2 />
{children}
<Footer />
</body>
</html>
);
}
24 changes: 24 additions & 0 deletions src/app/jobsite2/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use client';

import JobDetail from '@/components/jobsite2/jobdetail';
import SearchBar from '@/components/jobsite2/searchBar';
import JobLists from '@/components/jobsite2/joblists';
import { useState } from 'react';

export default function Home() {
const [postingID, setPostingID] = useState(null);

const onClickJobPosting = itemId => {
setPostingID(itemId);
};

return (
<div className="flex flex-col gap-8 p-4 md:p-8 bg-[#f0f9ff] dark:bg-[#0a1929]">
<SearchBar></SearchBar>
<div className="flex flex-row flex-1 space-x-6">
<JobLists onClickJob={onClickJobPosting}></JobLists>
<JobDetail postingID={postingID}></JobDetail>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion src/components/Top.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function Top() {
alt="Logo"
className="h-12 w-12"
height={32}
src="/placeholder-circle.png"
src="/placeholder.svg"
style={{
aspectRatio: '32/32',
objectFit: 'cover',
Expand Down
26 changes: 26 additions & 0 deletions src/components/jobsite2/Top2.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Image from 'next/image';
import Link from 'next/link';

export default function Top2() {
return (
<header className="flex items-center justify-between w-full md:p-5">
<Link
className="flex items-center space-x-2 text-[#0b5394] font-bold"
href="/jobsite2">
<Image
alt="Logo"
className="h-12 w-12"
height={32}
src="/placeholder.svg"
style={{
aspectRatio: '32/32',
objectFit: 'cover',
marginRight: '20px',
}}
width={32}
/>
<span>NewComers Job Site</span>
</Link>
</header>
);
}
146 changes: 146 additions & 0 deletions src/components/jobsite2/jobdetail.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import Axios from 'axios';
import { useEffect, useState } from 'react';
import MapPinIcon from '@/components/icons/mapPinIcon';
import ClockIcon from '@/components/icons/clockIcon';
import BriefcaseIcon from '@/components/icons/briefCaseIcon';
import MoneyIcon from '@/components/icons/moneyIcon';
import CalendarIcon from '@/components/icons/calendarIcon';
import UserIcon from '@/components/icons/userIcon';
import EmailIcon from '@/components/icons/emailIcon';
import Loading from '@/components/ui/Loading';

export default function JobDetail(job) {
const [jobDetail, setJobDetail] = useState({});
const [isLoading, setIsLoading] = useState(true);
const [maxWage, setMaxWage] = useState('');
const [streetAddress, setStreetAddress] = useState('');

const API_URL = '/api/job-posting/by-id?job-posting-id=';

function getDetailData() {
setIsLoading(true);

Axios.get(API_URL + job.postingID)
.then(res => {
console.log(res.data.jobPostings);
setJobDetail(res.data.jobPostings[0]);
res.data.jobPostings[0].maxCompValue
? setMaxWage(`to $${res.data.jobPostings[0].maxCompValue}`)
: '';
res.data.jobPostings[0].streetAddress
? setStreetAddress(`${res.data.jobPostings[0].streetAddress}, `)
: '';
})
.catch(error => {
console.log(error.response);
//todo: handle error
});
setIsLoading(false);
}

useEffect(() => {
if (job.postingID) {
getDetailData();
}
}, [job]);

return (
<div className="bg-white max-h-dvh overflow-y-auto dark:bg-[#0f172a] rounded-lg shadow-lg p-5 md:p-10 flex-1 space-y-4">
{isLoading && <Loading colour="blue"></Loading>}
{Object.keys(jobDetail).length !== 0 && (
<div className="space-y-4">
<div>
<h4 className="text-2xl font-bold text-[#0b5394] titleCase dark:text-white">
{jobDetail.jobTitle}
</h4>
<p className="text-gray-500 dark:text-gray-400">
{jobDetail.hiringOrganization}
</p>
<div className="text-right text-sm text-gray-500 dark:text-gray-400 mt-1 lg:mt-0">
{jobDetail.datePosted}
</div>
</div>
<div className="grid text-sm md:grid-cols-2 gap-6">
<div className="space-y-4">
<div className="flex items-center gap-2">
<BriefcaseIcon className="w-5 h-5 text-gray-500 dark:text-gray-400" />
<span className="text-gray-500 dark:text-gray-400 titleCase">
{jobDetail.employmentSubType}, {jobDetail.employmentType}
</span>
</div>
<div className="flex items-center gap-2">
<MapPinIcon className="w-5 h-5 text-gray-500 dark:text-gray-400" />
<span className="text-gray-500 dark:text-gray-400">
{streetAddress}
{jobDetail.addressLocality}, {jobDetail.addressRegion}
</span>
</div>
<div className="flex items-center gap-2">
<MoneyIcon className="w-5 h-5 text-gray-500 dark:text-gray-400" />
<span className="text-gray-500 dark:text-gray-400">
${jobDetail.minCompValue} {maxWage} hourly
</span>
</div>
</div>
<div className="space-y-4">
<div className="flex items-center gap-2">
<ClockIcon className="w-5 h-5 text-gray-500 dark:text-gray-400" />
<span className="text-gray-500 dark:text-gray-400">
{jobDetail.workHours}
</span>
</div>
<div className="flex items-center gap-2">
<CalendarIcon className="w-5 h-5 text-gray-500 dark:text-gray-400" />
<span className="text-gray-500 dark:text-gray-400">
{jobDetail.startTime}
</span>
</div>
<div className="flex items-center gap-2">
<UserIcon className="w-5 h-5 text-gray-500 dark:text-gray-400" />
<span className="text-gray-500 dark:text-gray-400">
{jobDetail.vacancies} vacancy
</span>
</div>
</div>
</div>
<div>
<h5 className="text-base font-bold text-[#0b5394] dark:text-white">
Job Description
</h5>
<p className="text-gray-500 dark:text-gray-400">## TO BE UPDATED</p>
</div>
<div>
<h5 className="text-base font-bold text-[#0b5394] dark:text-white">
Requirements
</h5>
<ul className="list-disc pl-4 text-gray-500 dark:text-gray-400">
<li>## TO BE UPDATED</li>
</ul>
</div>
<div>
<h5 className="text-base font-bold text-[#0b5394] dark:text-white">
Benefits
</h5>
<ul className="list-disc pl-4 text-gray-500 dark:text-gray-400">
{jobDetail.benefits}
<li>## TO BE UPDATED</li>
</ul>
</div>
<div>
<h5 className="text-base font-bold mb-1 text-[#0b5394] dark:text-white">
Apply by email
</h5>
<div className="flex items-center gap-3 text-sm">
<EmailIcon />
<a
href={`mailto:${jobDetail.email}`}
className="text-blue-900 underline">
{jobDetail.email}
</a>
</div>
</div>
</div>
)}
</div>
);
}
81 changes: 81 additions & 0 deletions src/components/jobsite2/joblists.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
'use client';
import Axios from 'axios';
import { useEffect, useState } from 'react';
import Loading from '../ui/Loading';

export default function JobLists({ onClickJob }) {
const [list, setList] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [page] = useState(1);
const API_URL = '/api/job-posting/newcomers?page_num=';

function getData() {
setIsLoading(true);

Axios.get(API_URL + page)
.then(res => {
console.log(res.data);
if (res.data.jobPostings.length != 0 && list.length == 0) {
onClick(res.data.jobPostings[0]._id);
}
setList(res.data.jobPostings);
})
.catch(error => {
console.log(error.response);
});

setIsLoading(false);
}

useEffect(() => {
getData();
}, []);

const onClick = postingId => {
onClickJob(postingId);
};

return (
<div className="w-4/12 max-h-dvh overflow-y-auto">
{isLoading && <Loading colour="blue" />}
<div className="space-y-8">
{list.map(item => {
const maxWage = item.maxCompValue ? `to $${item.maxCompValue}` : '';
const postedDate = item.datePosted.split(' ').slice(2).join(' ');
return (
<div
key={item._id}
className="bg-white dark:bg-[#0f172a] rounded-lg shadow-lg p-4 space-y-3">
<div onClick={() => onClick(item._id)}>
<h5 className="text-xl font-bold titleCase text-[#0b5394] dark:text-white">
{item.jobTitle}
</h5>
<p className="pl-2 text-gray-500 dark:text-gray-400">
{item.hiringOrganization}
</p>
<div className="pl-2 flex justify-between">
<div className="text-gray-500 dark:text-gray-400">
{item.addressLocality}, {item.addressRegion}
</div>
<div className="text-xs text-gray-400 dark:text-gray-300 mb-4">
{postedDate}
</div>
</div>
<div className="flex justify-between">
<p className="pl-2 text-sm text-gray-500 dark:text-gray-400">
${item.minCompValue} {maxWage} hourly
</p>
<button
className="text-sm p-3 font-bold titleCase text-[#0b5394] dark:text-white"
onClick={() => onClick(item._id)}>
View
</button>
</div>
</div>
</div>
);
})}
</div>
</div>
);
}
Loading

0 comments on commit 59a277d

Please sign in to comment.