HTML 82.1%
Python 14.6%
TypeScript 1.9%
CSS 1%
JavaScript 0.5%
1/**2 * =============================================================================3 * Job·Ka — Groupe KA4 * Auteur : Simon-Pierre Boucher5 * Contact : contact@spboucher.ai6 * Fichier : frontend/src/pages/Favoris.tsx7 * Rôle : Mes favoris ♥ « Mon univers Ka » — offres mises en favoris,8 * lues au hub Groupe KA (magasin central, aucun stockage local).9 * Rangées éditoriales alignées sur la liste d'offres (job-row).10 * Créé : 2026-08-23 Modifié : 2026-08-2511 * =============================================================================12 */13import { Link } from "react-router-dom";14import { FavItem, goLogin, useFav } from "../favorites";1516/** /emploi/<uid> local si l'url du favori pointe vers job-ka.com. */17function localPath(f: FavItem): string | null {18 if (!f.url) return `/emploi/${encodeURIComponent(f.item_id)}`;19 try {20 const u = new URL(f.url);21 if (u.hostname.endsWith("job-ka.com")) return u.pathname + u.search;22 } catch { /* url invalide : lien externe ignoré */ }23 return null;24}2526function FavCard({ f }: { f: FavItem }) {27 const { toggle } = useFav();28 const path = localPath(f);29 const inner = (30 <>31 <div className="jr-main">32 <h3 className="jr-title">{f.title}</h3>33 {f.subtitle && <p className="jr-org"><span className="employer">{f.subtitle}</span></p>}34 </div>35 <div className="jr-side">36 {f.price_label37 ? <span className="jr-salary">{f.price_label}</span>38 : <span className="jr-nosalary">Salaire non affiché</span>}39 </div>40 <button41 type="button"42 className="fav-btn on"43 aria-label="Retirer de mes favoris (Mon univers Ka)"44 title="Retirer de mes favoris (Mon univers Ka)"45 onClick={(e) => { e.preventDefault(); e.stopPropagation(); toggle(f); }}46 >47 <svg viewBox="0 0 24 24" aria-hidden="true">48 <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />49 </svg>50 </button>51 </>52 );53 return path54 ? <Link to={path} className="job-row">{inner}</Link>55 : <a href={f.url} className="job-row" target="_blank" rel="noopener noreferrer">{inner}</a>;56}5758export default function FavorisPage() {59 const { ready, connected, items } = useFav();6061 return (62 <main className="container">63 <h1>Mes favoris</h1>64 <p className="muted">65 Vos offres d'emploi mises en favoris ♥ — synchronisées avec votre66 compte <b>Mon univers Ka</b> sur toutes les plateformes du Groupe KA.67 </p>68 {!ready && <div className="empty">Chargement…</div>}69 {ready && !connected && (70 <div className="empty">71 <p>Connectez-vous avec votre KA ID pour retrouver vos favoris.</p>72 <button type="button" className="btn" onClick={goLogin}>73 Se connecter avec KA ID74 </button>75 </div>76 )}77 {ready && connected && items.length === 0 && (78 <div className="empty">79 <p>Aucun favori pour l'instant — touchez le cœur ♥ sur une offre80 pour la retrouver ici.</p>81 <Link className="btn" to="/">Parcourir les offres</Link>82 </div>83 )}84 {ready && connected && items.length > 0 && (85 <div className="job-list">86 {items.map((f) => <FavCard key={f.item_id} f={f} />)}87 </div>88 )}89 {ready && connected && (90 <p className="muted" style={{ marginTop: 24 }}>91 Tous vos favoris Groupe KA (logements, propriétés, produits…) :{" "}92 <a href="https://www.groupe-ka.com/compte" target="_blank" rel="noopener noreferrer">93 Mon univers Ka ↗94 </a>95 </p>96 )}97 </main>98 );99}100