SPB Git forge

spb/resto-ka

Public

Resto·Ka — tous les restaurants du Québec, menus complets et prix réels (famille ·Ka)

52commits 1branches 0releases
11.6 MBsize
maindefault branch
20 days agolast push
Python 69.3% TypeScript 16.7% CSS 7.9% JavaScript 4.7% HTML 1.4%
3.0 KB · 77 lines tsx
Raw Blame History
1// ==============================================================================2// Author: Simon-Pierre Boucher <contact@spboucher.ai>3// File:   pages/Sources.tsx4// Desc:   Registre public des sources connectées (même patron que la page5//         Sources de Lou·Ka) : plateforme, contexte de prix produit, volumes,6//         dernière synchronisation.7// ==============================================================================8import { useEffect, useState } from "react";9import { CONTEXT_SHORT, Source, fetchSources, fmtTs } from "../api";1011export default function SourcesPage() {12  const [sources, setSources] = useState<Source[]>([]);13  const [error, setError] = useState(false);1415  useEffect(() => {16    fetchSources().then((r) => setSources(r.sources)).catch(() => setError(true));17  }, []);1819  return (20    <div className="container sources">21      <span className="kicker">Transparence</span>22      <h1>Les sources de Resto-Ka</h1>23      <p className="sub">24        Chaque menu est capté à sa source et étiqueté selon son contexte de25        prix. Les plateformes de commande des restos eux-mêmes (prix réels,26        non majorés) passent toujours avant les plateformes de livraison.27      </p>28      {error && <div className="notice"><h2>Impossible de charger les sources</h2></div>}29      <div className="src-wrap">30        <table className="src-table">31          <thead>32            <tr>33              <th>Source</th>34              <th>Contexte de prix</th>35              <th>Cadence</th>36              <th>Restos actifs</th>37              <th>Plats</th>38              <th>Dernière synchro</th>39              <th>Statut</th>40            </tr>41          </thead>42          <tbody>43            {sources.map((s) => (44              <tr key={s.id}>45                <td>46                  <a href={s.url} target="_blank" rel="noopener noreferrer">{s.name}</a>47                  {s.integrations && (48                    <div className="src-integrations">49                      {s.integrations.filter((i) => i.status !== "inactif").length} intégrations :{" "}50                      {s.integrations.filter((i) => i.status !== "inactif")51                        .map((i) => i.label).join(" · ")}52                    </div>53                  )}54                </td>55                <td>56                  <span className={`pill ctx-pill ctx-${s.price_context}`}>57                    {CONTEXT_SHORT[s.price_context ?? ""] ?? s.price_context}58                  </span>59                </td>60                <td>{s.cadence ?? "—"}</td>61                <td><span className="count-pill">{s.active_restaurants}</span></td>62                <td><span className="count-pill">{s.menu_items ?? 0}</span></td>63                <td>{fmtTs(s.last_sync)}</td>64                <td>65                  <span className={`pill ${s.status === "actif" ? "ok" : "todo"}`}>66                    {s.status}67                  </span>68                </td>69              </tr>70            ))}71          </tbody>72        </table>73      </div>74    </div>75  );76}77