import { useNavigate, useParams } from "react-router-dom"
import { useEffect, useState } from "react"
import snarkdown from "snarkdown"
import { Link, JobDetailSkeleton } from "@/components"
import styles from './Detail.module.css'
function JobSection({ title, content }) {
const html = snarkdown(content)
return (
<section className={styles.section}>
<h2 className={styles.sectionTitle}>{title}</h2>
<div
className={`${styles.sectionContent} prose`}
dangerouslySetInnerHTML={{ __html: html }}
/>
</section>
)
}
export function JobDetailPage() {
const { jobId } = useParams()
const navigate = useNavigate()
const [job, setJob] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const handleTagClick = (type, value) => {
const params = new URLSearchParams()
const validTechnologies = [
'javascript', 'python', 'react', 'nodejs',
'java', 'csharp', 'c', 'c++', 'ruby', 'php'
]
const validLocations = [
'remoto', 'cdmx', 'guadalajara', 'monterrey', 'barcelona'
]
const validLevels = ['junior', 'mid', 'senior', 'lead']
const lowerValue = value.toLowerCase()
if (type === 'technology') {
if (validTechnologies.includes(lowerValue)) {
params.set('technology', lowerValue)
} else {
params.set('text', value)
}
} else if (type === 'modalidad') {
if (validLocations.includes(lowerValue)) {
params.set('type', lowerValue)
} else {
params.set('text', value)
}
} else if (type === 'nivel') {
if (validLevels.includes(lowerValue)) {
params.set('level', lowerValue)
} else {
params.set('text', value)
}
}
navigate(`/search?${params.toString()}`)
}
useEffect(() => {
window.scrollTo(0, 0)
fetch(`https://jscamp-api.vercel.app/api/jobs/${jobId}`)
.then(res => {
if (!res.ok) throw new Error('Job not found')
return res.json()
})
.then(data => {
setJob(data)
setError(null)
})
.catch(err => {
setError(err.message)
setJob(null)
})
.finally(() => {
setLoading(false)
})
}, [jobId])
if (loading) return <JobDetailSkeleton />
if (error || !job) {
return (
<div style={{ maxWidth: '1280px', margin: '0 auto', padding: '0 1rem' }}>
<div className={styles.error}>
<h2 className={styles.errorTitle}>Oferta no encontrada</h2>
<button
onClick={() => navigate('/')}
className={styles.errorButton}
>
Volver al inicio
</button>
</div>
</div>
)
}
return (
<div style={{ maxWidth: '1280px', margin: '0 auto', padding: '0 1rem' }}>
<div className={styles.container}>
<nav className={styles.breadcrumb}>
<Link href="/search" className={styles.breadcrumbButton}>
Empleos
</Link>
<span className={styles.breadcrumbSeparator}>/</span>
<span className={styles.breadcrumbCurrent}>{job.titulo}</span>
</nav>
</div>
<header className={styles.header}>
<h1 className={styles.title}>{job.titulo}</h1>
<p className={styles.meta}>
{job.empresa} Β· {job.ubicacion}
</p>
</header>
<div className={styles.tags}>
{job.data.technology.map((tech) => (
<span
key={tech}
className={styles.tag}
onClick={() => handleTagClick('technology', tech)}
>
{tech}
</span>
))}
<span
className={`${styles.tag} ${styles.tagModalidad}`}
onClick={() => handleTagClick('modalidad', job.data.modalidad)}
>
{job.data.modalidad}
</span>
<span
className={`${styles.tag} ${styles.tagNivel}`}
onClick={() => handleTagClick('nivel', job.data.nivel)}
>
{job.data.nivel}
</span>
</div>
<button className={styles.applyButton}>
π Aplicar ahora
</button>
<JobSection
title="DescripciΓ³n del puesto"
content={job.content.description}
/>
<JobSection
title="Responsabilidades"
content={job.content.responsibilities}
/>
<JobSection
title="Requisitios"
content={job.content.requirements}
/>
<JobSection
title="Acerca de la empresa"
content={job.content.about}
/>
</div>
)
}
export default JobDetailPage