SPB Git

spb/auto-ka Public

Python 81.9% TypeScript 12.4% CSS 5.5%
4.3 KB · 125 lines tsx
Raw Blame History
1// -----------------------------------------------------------------------------2// Auto-Ka — Agrégateur de voitures usagées à vendre (province de Québec)3// Auteur : Simon-Pierre Boucher — contact@spboucher.ai4// App.tsx : layout global (header + ticker en direct + footer encre) et routage5// -----------------------------------------------------------------------------6import { useEffect, useState } from "react";7import { NavLink, Route, Routes } from "react-router-dom";8import { fetchFacets, fetchSources, fetchStats, registerSourceNames } from "./api";9import Home from "./pages/Home";10import VehiclePage from "./pages/Vehicle";11import SourcesPage from "./pages/Sources";12import StatsPage from "./pages/Stats";1314function Ticker() {15  const [items, setItems] = useState<string[]>([]);1617  useEffect(() => {18    Promise.all([fetchStats(), fetchFacets(), fetchSources()])19      .then(([stats, facets, src]) => {20        registerSourceNames(src.sources);21        const parts: string[] = [22          `${stats.total.toLocaleString("fr-CA")} véhicules à vendre`,23          `${stats.sources} concessionnaires connectés`,24        ];25        if (stats.avg_price != null)26          parts.push(`Prix moyen ${Math.round(stats.avg_price).toLocaleString("fr-CA")} $`);27        for (const r of stats.by_region.slice(0, 8))28          parts.push(`${r.region} · ${r.n}`);29        for (const m of facets.makes.slice(0, 8))30          parts.push(`${m.make} · ${m.n}`);31        parts.push("Directement des sites des concessionnaires");32        setItems(parts);33      })34      .catch(() => setItems(["Auto-Ka — voitures usagées à vendre au Québec"]));35  }, []);3637  if (items.length === 0) return null;38  // contenu doublé pour une boucle de défilement continue39  return (40    <div className="ticker" aria-hidden="true">41      <div className="ticker-track">42        {[...items, ...items].map((t, i) => (43          <span key={i}>{t}</span>44        ))}45      </div>46    </div>47  );48}4950function Header() {51  return (52    <>53      <header className="header">54        <div className="container header-inner">55          <NavLink to="/" className="brand" aria-label="Auto-Ka — accueil">56            Auto<span className="ka">Ka</span>57            <span className="brand-tag">Voitures usagées · tout le Québec · toujours à jour</span>58          </NavLink>59          <nav className="nav" aria-label="Navigation principale">60            <NavLink to="/" end className={({ isActive }) => (isActive ? "active" : "")}>61              Véhicules62            </NavLink>63            <NavLink to="/stats" className={({ isActive }) => (isActive ? "active" : "")}>64              Stats65            </NavLink>66            <NavLink to="/sources" className={({ isActive }) => (isActive ? "active" : "")}>67              Sources68            </NavLink>69          </nav>70        </div>71      </header>72      <Ticker />73    </>74  );75}7677function Footer() {78  return (79    <footer className="footer">80      <div className="container">81        <div className="fbrand">82          Auto<span className="ka">Ka</span>83        </div>84        <div className="frow">85          <b>Agrégateur indépendant</b> de voitures usagées à vendre dans la86          province de Québec. Les annonces proviennent directement des sites87          publics des concessionnaires — pas des plateformes d'annonces — et88          sont rafraîchies automatiquement. Chaque fiche renvoie vers l'annonce89          originale du commerçant.90        </div>91        <div className="fmono">92          © {new Date().getFullYear()} Simon-Pierre Boucher — contact@spboucher.ai93        </div>94      </div>95    </footer>96  );97}9899export default function App() {100  return (101    <>102      <Header />103      <main>104        <Routes>105          <Route path="/" element={<Home />} />106          <Route path="/vehicule/:uid" element={<VehiclePage />} />107          <Route path="/stats" element={<StatsPage />} />108          <Route path="/sources" element={<SourcesPage />} />109          <Route110            path="*"111            element={112              <div className="notice container">113                <div className="big">🧭</div>114                <h2>Page introuvable</h2>115                <p>Le lien demandé n'existe pas.</p>116              </div>117            }118          />119        </Routes>120      </main>121      <Footer />122    </>123  );124}125