TypeScript 90.1%
JavaScript 3.2%
Python 3.2%
CSS 1.8%
HTML 1.8%
1// UQO Éval — laboratoire pédagogique d'évaluation immobilière2/**3 * /stats — bandeau « LE CHIFFRE » (valeur totale du parc immobilier4 * québécois, comparaisons vulgarisées). Les sections analytiques5 * (KPI, jauges, séries, répartitions, tableaux, records, rapports PDF)6 * sont servies par <StatsDashboard/> — module Stats commun v2.7 */8"use client";9import { CountUp } from "./MetricViz";10import { useLang } from "./LangContext";1112export interface ProvStats {13 generated: string;14 unites: number;15 valeur_totale_2026: number;16 valeur_role_totale: number;17 valeur_mediane_2026: number;18 croissance_2021_2026_pct: number;19 logements: number;20 aire_etages_km2: number;21 terrain_km2: number;22 municipalites: number;23 totaux_annee: { year: number; total: number; n: number }[];24 par_type: { type: string; n: number; total: number; mediane: number | null }[];25 par_ville: { ville: string; n: number; total: number; mediane: number | null }[];26}2728const POP_QC = 9_111_000; // population du Québec (2026, ISQ)29const BUDGET_QC = 165_800_000_000; // dépenses budget QC 2026-2027 (approx.)30const PIB_QC = 640_000_000_000; // PIB nominal QC (approx. 2025)3132const money = (v: number, lang: string, frac = 0) =>33 new Intl.NumberFormat(lang === "fr" ? "fr-CA" : "en-CA", {34 style: "currency",35 currency: "CAD",36 maximumFractionDigits: frac,37 }).format(v);3839const compact = (v: number, lang: string) => {40 const fr = lang === "fr";41 if (v >= 1e12) return `${(v / 1e12).toLocaleString(fr ? "fr-CA" : "en-CA", { maximumFractionDigits: 2 })} ${fr ? "billions $" : "T$"}`;42 if (v >= 1e9) return `${(v / 1e9).toLocaleString(fr ? "fr-CA" : "en-CA", { maximumFractionDigits: 1 })} G$`;43 if (v >= 1e6) return `${(v / 1e6).toLocaleString(fr ? "fr-CA" : "en-CA", { maximumFractionDigits: 1 })} M$`;44 return money(v, lang);45};4647const num = (v: number, lang: string) =>48 v.toLocaleString(lang === "fr" ? "fr-CA" : "en-CA");4950export default function StatsView({ s }: { s: ProvStats }) {51 const { lang } = useLang();52 const fr = lang === "fr";5354 return (55 <div className="pt-10 sm:pt-14">56 {/* ---- LE CHIFFRE ---- */}57 <section>58 <span className="kicker">{fr ? "Juste pour le show" : "Just for the show"}</span>59 <h1 className="vp-display mt-3 text-[clamp(26px,4.6vw,46px)] font-bold uppercase leading-[1.02] tracking-[-0.03em]">60 {fr ? (61 <>62 Tout l'immobilier du Québec vaut,63 <br />64 <span className="hl">au dollar près</span>…65 </>66 ) : (67 <>68 All Québec real estate is worth,69 <br />70 <span className="hl">to the dollar</span>…71 </>72 )}73 </h1>74 <div className="rise mt-6 rounded-[2px] bg-[var(--ink-deep)] p-6 sm:p-10">75 <p className="vp-display break-all text-[clamp(30px,6.2vw,76px)] font-bold leading-none tracking-[-0.03em] text-[var(--accent-bright)]">76 <CountUp77 value={s.valeur_totale_2026}78 duration={2600}79 format={(v) => money(v, lang)}80 />81 </p>82 <p className="vp-mono mt-4 text-[11.5px] uppercase tracking-[0.1em] text-[rgba(255,81,72,0.75)]">83 {fr84 ? `≈ ${compact(s.valeur_totale_2026, lang)} · ${num(s.unites, lang)} propriétés · ${num(s.municipalites, lang)} municipalités · millésime 2026`85 : `≈ ${compact(s.valeur_totale_2026, lang)} · ${num(s.unites, lang)} properties · ${num(s.municipalites, lang)} municipalities · 2026 vintage`}86 </p>87 <div className="mt-6 flex flex-wrap gap-2.5">88 {(89 [90 [fr ? "par Québécois·e" : "per Quebecer", money(s.valeur_totale_2026 / POP_QC, lang)],91 [fr ? "budgets annuels du Québec" : "annual Québec budgets", `× ${(s.valeur_totale_2026 / BUDGET_QC).toFixed(1)}`],92 [fr ? "fois le PIB du Québec" : "× Québec GDP", `× ${(s.valeur_totale_2026 / PIB_QC).toFixed(1)}`],93 [fr ? "depuis 2021 (périmètre constant)" : "since 2021 (constant perimeter)", `+${s.croissance_2021_2026_pct.toLocaleString(fr ? "fr-CA" : "en-CA")} %`],94 ] as [string, string][]95 ).map(([k, v]) => (96 <span key={k} className="stat-chip max-w-full !whitespace-normal !border-[rgba(245,243,238,0.25)] !text-[rgba(245,243,238,0.85)]">97 <b className="!text-[var(--accent-bright)]">{v}</b> {k}98 </span>99 ))}100 </div>101 </div>102 <p className="vp-mono mt-3 text-[10.5px] uppercase tracking-[0.06em] text-ink-3">103 {fr104 ? "Somme des 3 747 008 estimations UQO Éval (modèle hédonique, rôle 2026). Évaluation municipale totale correspondante : "105 : "Sum of 3,747,008 UQO Éval estimates (hedonic model, 2026 roll). Corresponding total municipal assessment: "}106 {compact(s.valeur_role_totale, lang)}.107 </p>108 </section>109 </div>110 );111}112