SPB Git

spb/food-ka Public

Food-Ka — agrégateur de produits d'épicerie du Québec — www.food-ka.com

Python 57.7% TypeScript 24.9% CSS 16.7% HTML 0.6%
3.1 KB · 84 lines tsx
Raw Blame History
1// -----------------------------------------------------------------------------2// Food-Ka — Agrégateur de produits d'épicerie (province de Québec)3// Auteur : Simon-Pierre Boucher — contact@spboucher.ai4// pages/Sources.tsx : registre des bannières d'épicerie agrégées5// -----------------------------------------------------------------------------6import { useEffect, useState } from "react";7import { Source, fetchSources } from "../api";8import SourceLogo from "../components/SourceLogo";910export default function SourcesPage() {11  const [sources, setSources] = useState<Source[] | null>(null);12  const [error, setError] = useState<string | null>(null);1314  useEffect(() => {15    fetchSources()16      .then((r) => setSources(r.sources))17      .catch((e) => setError(String(e)));18  }, []);1920  return (21    <div className="container sources">22      <span className="kicker">Registre — bannières d'épicerie</span>23      <h1>Sources agrégées</h1>24      <p className="sub">25        Bannières d'épicerie du Québec recensées par Food·Ka. Chaque source «26        active » est synchronisée périodiquement par un connecteur dédié; les27        autres sont en attente de connecteur.28      </p>2930      {error && <div className="notice">⚠️ {error}</div>}31      {!sources && !error && <div className="notice">Chargement…</div>}3233      {sources && (34        <div className="src-wrap">35        <table className="src-table">36          <thead>37            <tr>38              <th>Bannière</th>39              <th>Région</th>40              <th>Statut</th>41              <th style={{ textAlign: "right" }}>Produits actifs</th>42              <th>Dernière synchro</th>43            </tr>44          </thead>45          <tbody>46            {sources.map((s) => (47              <tr key={s.id}>48                <td>49                  <div className="src-cell">50                    <SourceLogo source={s.id} size={32} fallback="hide" />51                    <div>52                      <a href={s.url} target="_blank" rel="noopener noreferrer">{s.name}</a>53                      {s.notes && (54                        <div style={{ color: "var(--ink-3)", fontSize: 12, marginTop: 2 }}>{s.notes}</div>55                      )}56                    </div>57                  </div>58                </td>59                <td style={{ color: "var(--ink-2)", maxWidth: 380 }}>{s.region}</td>60                <td>61                  {s.connector ? (62                    <span className="pill ok">connecté</span>63                  ) : (64                    <span className="pill todo">{s.status}</span>65                  )}66                </td>67                <td style={{ textAlign: "right" }}>68                  <span className="count-pill">{s.active_products || "—"}</span>69                </td>70                <td style={{ color: "var(--ink-3)" }}>71                  {s.last_sync72                    ? new Date(s.last_sync * 1000).toLocaleString("fr-CA")73                    : "—"}74                </td>75              </tr>76            ))}77          </tbody>78        </table>79        </div>80      )}81    </div>82  );83}84