SPB Git

spb/lou-ka Public

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

HTML 99.7%
3.8 KB · 103 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// pages/Passerelle.tsx : page de transition vers l'annonce originale5//   (« passerelle » à la Centris). Ouverte dans un nouvel onglet par les CTA6//   de la fiche : affiche Lou-Ka → gestionnaire avec une barre de progression,7//   puis redirige vers l'annonce chez le gestionnaire après ~2,2 s.8//   Sécurité : on reçoit un uid (jamais une URL brute) — l'URL de destination9//   vient de notre API, pas du paramètre. Aucune redirection ouverte possible.10// -----------------------------------------------------------------------------11import { useEffect, useRef, useState } from "react";12import { Link, useParams } from "react-router-dom";13import { fetchListing, fetchSources, registerSourceNames, sourceName } from "../api";1415const DELAI_MS = 2200;1617export default function PasserellePage() {18  const { uid } = useParams<{ uid: string }>();19  const [dest, setDest] = useState<{ url: string; source: string } | null>(null);20  const [error, setError] = useState(false);21  const timer = useRef<number | null>(null);2223  useEffect(() => {24    if (!uid) return;25    let cancelled = false;26    Promise.all([fetchSources(), fetchListing(uid)])27      .then(([src, l]) => {28        if (cancelled) return;29        registerSourceNames(src.sources);30        if (!l.url || !/^https?:\/\//.test(l.url)) { setError(true); return; }31        setDest({ url: l.url, source: l.source });32        timer.current = window.setTimeout(() => {33          window.location.replace(l.url);34        }, DELAI_MS);35      })36      .catch(() => !cancelled && setError(true));37    return () => {38      cancelled = true;39      if (timer.current) window.clearTimeout(timer.current);40    };41  }, [uid]);4243  if (error)44    return (45      <div className="notice container">46        <div className="big">⚠️</div>47        <h2>Annonce introuvable</h2>48        <p>Impossible de retrouver l'annonce originale.</p>49        <Link className="btn btn-primary" to="/">Retour aux logements</Link>50      </div>51    );5253  const nom = dest ? sourceName(dest.source) : "…";5455  return (56    <div className="passerelle" role="status" aria-live="polite">57      <div className="pass-card">58        <div className="pass-brands">59          <span className="pass-brand">60            Lou<span className="ka">Ka</span>61          </span>62          <span className="pass-trajet" aria-hidden="true">63            <span className="pass-dot" /><span className="pass-dot" /><span className="pass-dot" />64            <span className="pass-fleche">➔</span>65          </span>66          <span className="pass-gestionnaire">67            <span className="pass-gest-ico" aria-hidden="true">🏢</span>68            {nom}69          </span>70        </div>7172        <h1>Passerelle vers l'annonce originale</h1>73        <p className="pass-texte">74          {dest75            ? <>Nous vous amenons chez <b>{nom}</b> — les prix, visites et76                signatures se passent directement chez le gestionnaire.</>77            : "Préparation de la redirection…"}78        </p>7980        <div className="pass-progress" aria-hidden="true">81          <span className={`pass-progress-fill ${dest ? "go" : ""}`} />82        </div>8384        <div className="pass-actions">85          {dest && (86            <a className="btn btn-primary" href={dest.url} rel="noopener noreferrer">87              Y aller maintenant ↗88            </a>89          )}90          <button className="btn btn-ghost" onClick={() => window.close()}>91            Rester sur Lou-Ka92          </button>93        </div>9495        <div className="fine">96          Lou-Ka est un agrégateur indépendant : chaque fiche renvoie à97          l'annonce publiée par le gestionnaire immobilier.98        </div>99      </div>100    </div>101  );102}103