spb/fabri-ka Public
Agrégateur de produits québécois — www.fabri-ka.com
HTML 57%
Python 19.9%
TypeScript 15.3%
CSS 7.7%
1import { useState } from 'react'2import { Link } from 'react-router-dom'3import { formatPrice, Product } from '../api'4import { IconLeaf } from './Icons'5import OriginBadge from './OriginBadge'67export default function ProductCard({ product }: { product: Product }) {8 const [imageFailed, setImageFailed] = useState(false)9 const image = product.images.length > 0 ? product.images[0] : null10 const showImage = image !== null && !imageFailed1112 return (13 <Link14 to={`/produits/${encodeURIComponent(product.uid)}`}15 className="card product-card"16 >17 <div className="product-card-media">18 {showImage ? (19 <img20 src={image}21 alt={product.title}22 loading="lazy"23 decoding="async"24 onError={() => setImageFailed(true)}25 />26 ) : (27 <div className="image-placeholder" aria-hidden="true">28 <IconLeaf size={30} />29 </div>30 )}31 <span className="product-card-badge">32 <OriginBadge origin={product.origin_class} />33 </span>34 </div>35 <div className="product-card-body">36 <h3 className="product-card-title">{product.title}</h3>37 <div className="product-card-price">38 {product.price !== null ? (39 <span className="price-chip">{formatPrice(product.price)}</span>40 ) : (41 <span className="price-chip price-chip-muted">Prix variable</span>42 )}43 {product.compare_at_price !== null &&44 product.price !== null &&45 product.compare_at_price > product.price && (46 <s className="price-compare">47 {formatPrice(product.compare_at_price)}48 </s>49 )}50 </div>51 <p className="product-card-store">52 {product.store_name}53 {product.store_region ? ` · ${product.store_region}` : ''}54 </p>55 </div>56 </Link>57 )58}59