-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make dynamic page fetching data from database
- Loading branch information
Showing
13 changed files
with
1,060 additions
and
4 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} |
Oops, something went wrong.