// --------------------------------------------------------------------------- // Fabri-Ka — Agrégateur de produits fabriqués au Québec // Auteur : Simon-Pierre Boucher — contact@spboucher.ai // fiche/PriceCard.tsx : « Prix et déclinaisons » — KPI (prix, prix barré ou // fourchette, disponibilité), options (tailles, couleurs, formats) en puces, // liste des déclinaisons avec prix et rupture (8 + « Voir les N »), note // moyenne, méthodologie. Toutes les données viennent de la boutique. // --------------------------------------------------------------------------- import { useState } from 'react' import { ProductDetail, ProductOption, formatPrice } from '../api' import { Ico } from '../components/KaIcons' import { rabais, variantsOf } from './synthese' import { Accordion, MoreButton, SectionCard, StatTile, NBSP } from './ui' const optName = (o: ProductOption) => o.name || o.title || '' const optValues = (o: ProductOption) => (o.values || o.selections || []).filter(Boolean) export default function PriceCard({ p }: { p: ProductDetail }) { const [all, setAll] = useState(false) const det = p.details ?? {} const r = rabais(p) const options = (det.options ?? []).filter((o) => optName(o) && optValues(o).length > 0) const variants = variantsOf(p) const LIMIT = 8 const dispo = !p.available ? 'Non disponible' : det.low_stock_remaining ? `Plus que ${det.low_stock_remaining}` : det.is_on_backorder ? 'Précommande' : det.inventory_quantity != null && det.inventory_quantity > 0 ? `${det.inventory_quantity} en stock` : det.availability_text || 'Disponible' const rating = det.average_rating return ( }>
{r ? : p.price_max != null && p.price != null && p.price_max > p.price ? : 1 ? variants.length : 1} label={variants.length > 1 ? 'Déclinaisons' : 'Déclinaison unique'} />}
{rating != null && rating > 0 && (

Note {rating.toFixed(1).replace('.', ',')} / 5{det.review_count ? ` — ${det.review_count} avis publiés sur la boutique` : ' — note publiée par la boutique'}

)} {options.length > 0 && ( <>

Options

{options.map((o) => (
{optName(o)}
{optValues(o).slice(0, 18).map((v) => {v})} {optValues(o).length > 18 && +{optValues(o).length - 18}}
))} )} {variants.length > 1 && ( <>

Déclinaisons · {variants.length}{det.variations && det.variations > variants.length ? ` sur ${det.variations}` : ''}

{variants.length > LIMIT && setAll(!all)} expanded={all}>{all ? 'Réduire' : `Voir les ${variants.length} déclinaisons`}} )}

Prix, prix barré, options, déclinaisons et disponibilité sont ceux publiés par la boutique (Shopify, WooCommerce, Wix, Squarespace…) lors de la dernière synchronisation Fabri-Ka. Un prix barré supérieur à dix fois le prix est ignoré (saisie en cents chez certains marchands). Le prix final, les taxes et la livraison se confirment sur la boutique.

) }