SPB Git forge

spb/lou-ka

Public

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

232commits 1branches 0releases
172.9 MBsize
maindefault branch
2 days agolast push
HTML 98.9% Python 0.6%
3.4 KB · 58 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// fiche/DesktopAside.tsx : colonne droite sticky (≥ 1024 px) — prix, capsule5//   marché, adresse, CTA, PDF, Lou-Ka Score en miniature, constats clés,6//   favoris / partage. Masquée sur mobile (display:none, pas de réordonnancement).7// -----------------------------------------------------------------------------8import { Listing, fmtPrice, sourceName } from "../api";9import { IcoDoc, IcoExternal, IcoHeart, IcoShare, IcoSparkles } from "../components/Icons";10import { ScoreRing } from "./LouKaScore";11import { PriceCapsule } from "./PropertyHero";12import { BriefList } from "./PropertySummary";13import { ComparaisonPrix, Constat, LouKaScore } from "./synthese";14import { NBSP, relTime } from "./ui";1516export default function DesktopAside({ l, cmp, score, brief, fav, onFav, onShare }: {17  l: Listing; cmp: ComparaisonPrix | null; score: LouKaScore; brief: Constat[];18  fav: boolean; onFav: () => void; onShare: () => void;19}) {20  const maj = relTime(l.updated_at);21  return (22    <aside className="lk-aside" aria-label="Résumé et actions">23      <div className="lk-card lk-aside-card">24        <div>25          <div className="lk-price">{fmtPrice(l.price, l.price_label)}{l.price != null && <small>/{NBSP}mois</small>}</div>26          <div className="lk-price-row" style={{ marginTop: 8 }}><PriceCapsule cmp={cmp} /></div>27        </div>28        <div className="lk-aside-addr">{l.address || l.title}{l.city ? <><br />{[l.sector, l.city].filter(Boolean).join(", ")}</> : null}</div>29        <a className="lk-btn lk-btn-primary" href={`/passerelle/${encodeURIComponent(l.uid)}`} target="_blank" rel="noopener noreferrer">30          Voir l'annonce chez {sourceName(l.source)} <IcoExternal size={16} />31        </a>32        <div className="lk-actions">33          <button type="button" className={`lk-btn lk-btn-ghost ${fav ? "on" : ""}`} style={{ flex: 1 }} aria-pressed={fav} onClick={onFav}>34            <IcoHeart size={17} filled={fav} /> {fav ? "Favori" : "Favoris"}35          </button>36          <button type="button" className="lk-btn lk-btn-ghost" style={{ flex: 1 }} onClick={onShare}><IcoShare size={16} /> Partager</button>37          <a className="lk-btn lk-btn-ghost lk-btn-icon" aria-label="Fiche PDF" title="Fiche PDF" href={`/api/listings/${encodeURIComponent(l.uid)}/pdf`} download><IcoDoc size={17} /></a>38        </div>39        <button type="button" className="lk-btn lk-btn-ghost lk-ka-inline" onClick={() => window.dispatchEvent(new Event("lk:askka"))}>40          <IcoSparkles size={16} /> Demander à Ka41        </button>42        {(score.value != null || brief.length > 0) && <hr className="lk-aside-sep" />}43        {score.value != null && (44          <div className="lk-aside-score">45            <ScoreRing value={score.value} partial={score.partial} size={56} />46            <div className="lk-aside-score-txt">47              <b>Lou-Ka Score · {score.label}</b>48              {score.partial ? "Score partiel" : `Emplacement ${score.emplacement} · Prix ${score.prix}`}49            </div>50          </div>51        )}52        {brief.length > 0 && <BriefList items={brief.slice(0, 4)} compact />}53        {maj && <div className="lk-aside-meta">Synchronisé {maj} · {sourceName(l.source)}</div>}54      </div>55    </aside>56  );57}58