/**
* =============================================================================
* Job·Ka — Groupe KA
* Auteur : Simon-Pierre Boucher
* Contact : contact@spboucher.ai
* Fichier : frontend/src/pages/Job.tsx
* Rôle : Fiche d'une offre — refonte premium 2026-09-07 (même socle que
* les fiches Lou-Ka v3 / Immo-Ka v3). Ordre DOM = ordre visuel,
* identique mobile ET desktop (aucun `order`) : héro (employeur ·
* salaire · capsules · titre · actions) → En bref → navigation
* sticky → Salaire et marché → Le poste (+ avantages, description) →
* Où travailler → Dossier → Sources. Desktop ≥ 1024 px : colonne
* principale + aside sticky. Aucun scrollIntoView à l'ouverture.
* Créé : 2026-08-17 Modifié : 2026-09-07
* =============================================================================
*/
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { Job, displayTitle, fetchJob, formatSalary } from "../api";
import { Ico } from "../components/Icons";
import { jobFavItem, useFav } from "../favorites";
import "../fiche/fiche.css";
import { setCurrentListing } from "../fiche/current";
import { comparaisonSalaire, enBref } from "../fiche/synthese";
import JobHero from "../fiche/JobHero";
import SectionNav, { NavItem } from "../fiche/SectionNav";
import SalaryCard from "../fiche/SalaryCard";
import JobFacts from "../fiche/JobFacts";
import { DesktopAside, Dossier, KaAssistant, LocationCard, Sources, StickyCTA, Summary, usePastElement } from "../fiche/Closing";
import { Skeleton, useToast } from "../fiche/ui";
function FicheSkeleton() {
return (
);
}
export default function JobPage() {
const { uid = "" } = useParams();
const [job, setJob] = useState(null);
const [error, setError] = useState("");
const { ids, toggle, connected } = useFav();
const [toast, showToast] = useToast();
const actionsRef = useRef(null);
const pastHero = usePastElement(actionsRef);
useEffect(() => {
setJob(null); setError(""); setCurrentListing(null);
fetchJob(uid).then((j) => { setJob(j); setCurrentListing(j); }).catch((e) => setError(String(e)));
window.scrollTo(0, 0);
return () => setCurrentListing(null);
}, [uid]);
useEffect(() => { document.body.classList.add("jk-fiche-page"); return () => document.body.classList.remove("jk-fiche-page"); }, []);
useEffect(() => { if (job) document.title = `${displayTitle(job)} — ${job.employer}${formatSalary(job) ? ` · ${formatSalary(job)}` : ""} | Job·Ka`; }, [job]);
const fav = !!(job && ids.has(job.uid));
const onFav = useCallback(() => {
if (!job) return;
toggle(jobFavItem(job));
if (connected) showToast(fav ? "Retiré des favoris" : "Ajouté à vos favoris");
}, [job, toggle, connected, fav, showToast]);
const onShare = useCallback(async () => {
if (!job) return;
const url = `https://www.job-ka.com/emploi/${encodeURIComponent(job.uid)}`;
try {
if (navigator.share) { await navigator.share({ title: `${displayTitle(job)} — ${job.employer} | Job·Ka`, url }); return; }
await navigator.clipboard.writeText(url); showToast("Lien copié");
} catch { /* annulé */ }
}, [job, showToast]);
const cmp = useMemo(() => (job ? comparaisonSalaire(job) : null), [job]);
const brief = useMemo(() => (job ? enBref(job) : []), [job]);
if (error)
return (
Offre introuvable
Cette offre n'existe pas ou a été retirée par l'employeur.
Retour aux offres
);
if (!job) return ;
const geo = job.lat != null && job.lng != null;
const nav: NavItem[] = [
{ id: "resume", label: "Résumé" },
...(formatSalary(job) || job.salary_context ? [{ id: "salaire", label: "Salaire" }] : []),
{ id: "poste", label: "Poste" },
...(job.benefits?.length ? [{ id: "avantages", label: "Avantages" }] : []),
{ id: "description", label: "Description" },
...(geo ? [{ id: "carte", label: "Carte" }] : []),
{ id: "dossier", label: "Dossier" }, { id: "sources", label: "Sources" },
];
return (
{toast}
);
}