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
19 days agolast push
Python 69.3% TypeScript 16.7% CSS 7.9% JavaScript 4.7% HTML 1.4%
2.9 KB · 77 lines tsx
Raw Blame History
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 {10  CONTEXT_SHORT, Restaurant, cuisineLabel, fmtPrice, sourceName, typeLabel,11} from "../api";12import { FavButton } from "../favorites";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  return (20    <Link to={`/resto/${encodeURIComponent(r.uid)}`} className="card">21      <div className="card-img">22        {img ? (23          <img src={img} alt={r.name} loading="lazy" />24        ) : logo ? (25          <div className="noimg"><img className="card-logo" src={logo} alt={r.name} loading="lazy" /></div>26        ) : (27          <div className="noimg"><IcoPlate size={38} strokeWidth={1.6} /></div>28        )}29        {r.price_range && <span className="badge type">{r.price_range}</span>}30        {r.ka_reco && (31          <span32            className="badge ka-reco"33            title="Correspond à vos préférences KA ID — gérez-les sur groupe-ka.com/mon-ka"34          >35            Recommandé pour vous36          </span>37        )}38        {ms && (39          <span className={`badge right ctx ctx-${ms.price_context}`}>40            {CONTEXT_SHORT[ms.price_context] ?? ms.price_context}41          </span>42        )}43        <FavButton r={r} />44      </div>45      <div className="card-body">46        <div className="card-price">47          {ms?.price_median != null ? (48            <>49              {fmtPrice(ms.price_median)} <small>plat médian</small>50            </>51          ) : (52            <span className="no-menu">Menu à venir</span>53          )}54        </div>55        <div className="card-title">{r.name}</div>56        <div className="card-meta">57          <span>{typeLabel(r.establishment_type)}</span>58          {r.cuisines.slice(0, 2).map((c) => (59            <span key={c}>60              <span className="sep" /> {cuisineLabel(c)}61            </span>62          ))}63        </div>64        <div className="card-meta">65          {r.city && <span>{r.city}</span>}66          {r.city && r.region && <span className="sep" />}67          {r.region && <span>{r.region}</span>}68        </div>69        <div className="card-foot">70          <span className="source-tag">{sourceName(r.source)}</span>71          {ms && <span className="avail">{ms.item_count} plats au menu</span>}72        </div>73      </div>74    </Link>75  );76}77