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.1 KB · 67 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/LouKaScore.tsx : carte « Lou-Ka Score » — anneau 0-100 animé, libellé,5//   composantes (emplacement / prix) et méthodologie en accordéon. Quand une6//   composante manque, le score est présenté comme partiel ; quand aucune7//   n'est fiable, la carte affiche la synthèse sans chiffre (jamais inventé).8// -----------------------------------------------------------------------------9import { useEffect, useState } from "react";10import { Link } from "react-router-dom";11import { IcoSparkles } from "../components/Icons";12import { LouKaScore as Score } from "./synthese";13import { Accordion, SectionCard } from "./ui";1415export function ScoreRing({ value, partial, size = 88 }: { value: number | null; partial?: boolean; size?: number }) {16  const [v, setV] = useState(0);17  useEffect(() => {18    const t = requestAnimationFrame(() => setV(value ?? 0));19    return () => cancelAnimationFrame(t);20  }, [value]);21  const r = 40, c = 2 * Math.PI * r;22  return (23    <div className="lk-score-ring" style={{ width: size, height: size }} role="img"24         aria-label={value != null ? `Lou-Ka Score ${value} sur 100${partial ? ", partiel" : ""}` : "Score non calculable"}>25      <svg viewBox="0 0 100 100" style={{ width: size, height: size }} aria-hidden="true">26        <circle className="bg" cx="50" cy="50" r={r} />27        <circle className={`arc ${partial ? "partial" : ""}`} cx="50" cy="50" r={r}28                strokeDasharray={`${(c * Math.max(0, Math.min(100, v))) / 100} ${c}`} />29      </svg>30      <div className="lk-score-val">31        <div>{value != null ? value : "—"}<small>/ 100</small></div>32      </div>33    </div>34  );35}3637export default function LouKaScore({ s, resume }: { s: Score; resume: string[] }) {38  return (39    <SectionCard id="score" title="Lou-Ka Score" icon={<IcoSparkles size={18} />}40                 sub={s.partial ? "Score partiel — une composante manque" : undefined}>41      <div className="lk-score">42        <ScoreRing value={s.value} partial={s.partial} />43        <div>44          <div className="lk-score-lbl">45            {s.value != null ? s.label : "Pas assez de données pour un score"}46          </div>47          {resume.length > 0 && <div className="lk-score-sub">{resume.join(" · ")}</div>}48          <div className="lk-score-parts">49            <span className={`lk-score-part ${s.emplacement == null ? "na" : ""}`}>50              Emplacement {s.emplacement != null ? <b>{s.emplacement}</b> : "non évalué"}51            </span>52            <span className={`lk-score-part ${s.prix == null ? "na" : ""}`}>53              Prix {s.prix != null ? <b>{s.prix}</b> : "non évalué"}54            </span>55          </div>56        </div>57      </div>58      <Accordion title="Comment est calculé ce score ?" small>59        <p>{s.explication}</p>60        <p>61          <Link to="/ka-scores">Méthodologie des KA Scores</Link> · <Link to="/juste-valeur">Méthodologie de la juste valeur</Link>62        </p>63      </Accordion>64    </SectionCard>65  );66}67