spb/lou-ka Public
Lou·Ka — tous les logements à louer du Québec, un seul endroit.
HTML 99.7%
1// -----------------------------------------------------------------------------2// Lou-Ka — Agrégateur de logements à louer (province de Québec)3// Auteur : Simon-Pierre Boucher — contact@spboucher.ai4// components/CookieConsent.tsx : bandeau de consentement (témoins/stockage)5// Honnête par design : Lou-Ka n'utilise AUCUN témoin tiers ni traceur.6// Le sélecteur couvre le stockage local (préférences) et une éventuelle7// mesure d'audience anonyme future. Choix mémorisé en localStorage,8// ré-ouvrable via l'événement « louka:openConsent » (lien du pied de page).9// -----------------------------------------------------------------------------10import { useEffect, useState } from "react";11import { Link } from "react-router-dom";1213const KEY = "louka-consent-v1";1415export interface Consent {16 essential: true; // toujours actif (fonctionnement du site)17 preferences: boolean; // mémoriser filtres et vue liste/carte18 statistics: boolean; // mesure d'audience anonyme (si activée un jour)19 ts: number;20}2122export function getConsent(): Consent | null {23 try {24 const raw = localStorage.getItem(KEY);25 return raw ? (JSON.parse(raw) as Consent) : null;26 } catch {27 return null;28 }29}3031function save(preferences: boolean, statistics: boolean): Consent {32 const c: Consent = { essential: true, preferences, statistics, ts: Date.now() };33 try { localStorage.setItem(KEY, JSON.stringify(c)); } catch { /* stockage bloqué */ }34 return c;35}3637export default function CookieConsent() {38 const [visible, setVisible] = useState(false);39 const [custom, setCustom] = useState(false);40 const [prefs, setPrefs] = useState(true);41 const [stats, setStats] = useState(false);4243 useEffect(() => {44 if (getConsent() === null) setVisible(true);45 const open = () => { setVisible(true); setCustom(true); };46 window.addEventListener("louka:openConsent", open);47 return () => window.removeEventListener("louka:openConsent", open);48 }, []);4950 if (!visible) return null;5152 const close = (p: boolean, s: boolean) => { save(p, s); setVisible(false); setCustom(false); };5354 return (55 <div className="cookie-banner" role="dialog" aria-modal="false" aria-label="Gestion des témoins">56 <div className="cookie-inner">57 <div className="cookie-text">58 <b>🍪 Vos témoins, vos choix.</b>{" "}59 Lou-Ka n'utilise aucun traceur publicitaire ni témoin tiers. Le site60 mémorise localement vos préférences (filtres, vue carte) et votre choix61 de consentement. <Link to="/confidentialite">Politique de confidentialité</Link>62 </div>6364 {custom && (65 <div className="cookie-options">66 <label className="cookie-opt">67 <input type="checkbox" checked disabled />68 <span><b>Essentiels</b> — fonctionnement du site (toujours actifs)</span>69 </label>70 <label className="cookie-opt">71 <input type="checkbox" checked={prefs} onChange={(e) => setPrefs(e.target.checked)} />72 <span><b>Préférences</b> — retenir vos filtres et votre vue liste/carte</span>73 </label>74 <label className="cookie-opt">75 <input type="checkbox" checked={stats} onChange={(e) => setStats(e.target.checked)} />76 <span><b>Statistiques</b> — mesure d'audience anonyme, sans profilage</span>77 </label>78 </div>79 )}8081 <div className="cookie-actions">82 {!custom && (83 <button className="btn btn-ghost" onClick={() => setCustom(true)}>84 Personnaliser85 </button>86 )}87 <button className="btn btn-ghost" onClick={() => close(false, false)}>88 Essentiels seulement89 </button>90 {custom ? (91 <button className="btn btn-primary" onClick={() => close(prefs, stats)}>92 Enregistrer mes choix93 </button>94 ) : (95 <button className="btn btn-primary" onClick={() => close(true, true)}>96 Tout accepter97 </button>98 )}99 </div>100 </div>101 </div>102 );103}104