SPB Git

spb/resto-ka

Public

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

3.1 KB · 80 lines tsx
1// ==============================================================================2// Author: Simon-Pierre Boucher <contact@spboucher.ai>3// File:   components/RestoCard.tsx4// Desc:   Carte de restaurant (grille de résultats) — même patron que la5//         ListingCard de Lou·Ka : prix en tête, badge de contexte de prix6//         TOUJOURS affiché (CLAUDE.md §6.2), source en pied de carte.7// ==============================================================================8import { Link } from "react-router-dom";9import { useAccount } from "../account";10import {11  CONTEXT_SHORT, Restaurant, cuisineLabel, fmtPrice, sourceName, typeLabel,12} from "../api";13import { IcoPlate } from "./Icons";1415export default function RestoCard({ r }: { r: Restaurant }) {16  const ms = r.menu_summary;17  const img = ms?.image || (r.images ?? [])[1] || null;   // photo de plat d'abord18  const logo = (r.images ?? [])[0] || null;19  const { me, favs, toggleFav } = useAccount();20  const fav = favs.has(r.uid);21  return (22    <Link to={`/resto/${encodeURIComponent(r.uid)}`} className="card">23      <div className="card-img">24        {img ? (25          <img src={img} alt={r.name} loading="lazy" />26        ) : logo ? (27          <div className="noimg"><img className="card-logo" src={logo} alt={r.name} loading="lazy" /></div>28        ) : (29          <div className="noimg"><IcoPlate size={38} strokeWidth={1.6} /></div>30        )}31        {r.price_range && <span className="badge type">{r.price_range}</span>}32        {ms && (33          <span className={`badge right ctx ctx-${ms.price_context}`}>34            {CONTEXT_SHORT[ms.price_context] ?? ms.price_context}35          </span>36        )}37        {me && (38          <button39            className={`fav-btn ${fav ? "on" : ""}`}40            aria-label={fav ? "Retirer des favoris" : "Ajouter aux favoris"}41            aria-pressed={fav}42            onClick={(e) => { e.preventDefault(); e.stopPropagation(); toggleFav(r.uid); }}43          >44            {fav ? "♥" : "♡"}45          </button>46        )}47      </div>48      <div className="card-body">49        <div className="card-price">50          {ms?.price_median != null ? (51            <>52              {fmtPrice(ms.price_median)} <small>plat médian</small>53            </>54          ) : (55            <span className="no-menu">Menu à venir</span>56          )}57        </div>58        <div className="card-title">{r.name}</div>59        <div className="card-meta">60          <span>{typeLabel(r.establishment_type)}</span>61          {r.cuisines.slice(0, 2).map((c) => (62            <span key={c}>63              <span className="sep" /> {cuisineLabel(c)}64            </span>65          ))}66        </div>67        <div className="card-meta">68          {r.city && <span>{r.city}</span>}69          {r.city && r.region && <span className="sep" />}70          {r.region && <span>{r.region}</span>}71        </div>72        <div className="card-foot">73          <span className="source-tag">{sourceName(r.source)}</span>74          {ms && <span className="avail">{ms.item_count} plats au menu</span>}75        </div>76      </div>77    </Link>78  );79}80
Files · c9f9e0970a11c1ae39fed1d26753cd00e6448cef
Menu

Theme