feat: implement job list

This commit is contained in:
jongomez
2023-10-24 12:49:54 +01:00
parent cef9fe9f61
commit 3da1faef69
6 changed files with 165 additions and 0 deletions
@@ -18,6 +18,7 @@ import {
SectionHeader,
TimelineItem,
ShowcaseCard,
JobList,
} from '../components/mdx'
<Hero size="large">
@@ -352,3 +353,4 @@ import {
Build on Waku
</CallToActionButton>
</Box>
<JobList jobBoard="nomos" />
@@ -0,0 +1,53 @@
import React, { useState } from 'react'
import useFetchJobs, { JobBoard, Job } from './useFetchJobs'
type Props = {
jobBoard: JobBoard
titleFilter?: string
}
export const JobList: React.FC<Props> = ({ jobBoard, titleFilter = '' }) => {
const { data, error, fetchJobs } = useFetchJobs()
const [isLoading, setIsLoading] = useState(false)
const handleFetchJobs = async () => {
setIsLoading(true)
await fetchJobs([jobBoard], titleFilter)
setIsLoading(false)
}
React.useEffect(() => {
handleFetchJobs()
}, [jobBoard, titleFilter])
if (isLoading) {
return <div>Loading...</div>
}
if (error) {
return <div>Error: {error.message}</div>
}
if (!data) {
return <div>No data</div>
}
return (
<div>
<h2>Job List</h2>
<ul>
{data.jobs.map((job: Job, index: number) => (
<li key={index}>
<a
href={job.absolute_url}
target="_blank"
rel="noopener noreferrer"
>
{job.title}
</a>
</li>
))}
</ul>
</div>
)
}
@@ -0,0 +1 @@
export * from './JobList'
@@ -0,0 +1,108 @@
import { useState } from 'react'
// Inspired by:
// https://github.com/acid-info/rnd-dynamic-list/blob/master/react/useFetchJobs.js
const jobBoards = [
'acidtest',
'logos',
'status',
'nimbus',
'codex',
'nomos',
'statusnetwork',
'ift',
'vac',
'waku',
] as const
export type JobBoard = (typeof jobBoards)[number]
const jobBoardMappings: Record<JobBoard, string> = {
acidtest: 'testacidinfo',
logos: 'logos',
status: 'status72',
nimbus: 'nimbus',
codex: 'codex',
nomos: 'nomos',
statusnetwork: 'thestatusnetwork',
ift: 'instituteoffreetechnologies',
vac: 'vac',
waku: 'waku',
}
export type Job = {
absolute_url: string
data_compliance?: {
type: string
requires_consent: boolean
requires_processing_consent: boolean
requires_retention_consent: boolean
retention_period: null | string // Assuming retention_period can be a string or null.
}[]
internal_job_id: number
location?: {
name: string
}
metadata?: any
id: number
updated_at: string
requisition_id: string
title: string
}
type JobData = {
jobs: Job[]
meta: {
total: number
}
} | null
type UseFetchJobs = {
data: JobData
error: any
fetchJobs: (jobBoardsToFetch: JobBoard[], titleFilter: string) => void
}
export const useFetchJobs = (): UseFetchJobs => {
const [data, setData] = useState<JobData>(null)
const [error, setError] = useState<Error | null>(null)
const fetchJobs = async (jobBoardsToFetch: JobBoard[], titleFilter) => {
try {
const resultsPerBoard: Partial<Record<JobBoard, string>> = {}
for (let board of jobBoardsToFetch) {
const response = await fetch(
`https://boards-api.greenhouse.io/v1/boards/${jobBoardMappings[board]}/jobs`,
)
const jobData = await response.json()
resultsPerBoard[board] = jobData.jobs
}
let jobs = Object.values(resultsPerBoard).flat() as unknown as Job[]
if (titleFilter) {
jobs = jobs.filter(
(job) => job.title && job.title.includes(titleFilter),
)
}
setData({ jobs, meta: { total: jobs.length } })
} catch (err) {
if (err instanceof Error) {
setError(err)
} else if (typeof err === 'string') {
setError(new Error(err))
} else {
setError(new Error('Unknown error'))
}
console.error(err)
}
}
return { data, error, fetchJobs }
}
export default useFetchJobs
@@ -24,3 +24,4 @@ export * from './Showcase'
export * from './ShowcaseCard'
export * from './SocialCard'
export * from './TimelineItem'
export * from './JobList'