SPB Git

spb/lou-ka Public

Lou·Ka — tous les logements à louer du Québec, un seul endroit.

HTML 99.7%
4.1 KB · 104 lines tsx
Raw Blame History
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