// --------------------------------------------------------------------------- // Fabri-Ka — Agrégateur de produits fabriqués au Québec // Auteur : Simon-Pierre Boucher — contact@spboucher.ai // fiche/Closing.tsx : « En bref », CTA sticky mobile, aside desktop et // « Demander à Ka » (widget KA Agent partagé) de la fiche produit. // --------------------------------------------------------------------------- import { useEffect, useState } from 'react' import { ProductDetail, formatPrice } from '../api' import { Ico, IcoHeart } from '../components/KaIcons' import OriginBadge from '../components/OriginBadge' import BottomSheet from './BottomSheet' import { Constat, rabais } from './synthese' import { SectionCard, SkeletonLines } from './ui' export function BriefList({ items, compact = false }: { items: Constat[]; compact?: boolean }) { const glyph = (t: Constat['tone']) => (t === 'good' ? '✓' : t === 'bad' ? '✕' : t === 'warn' ? '!' : '○') return ( ) } export function Summary({ items }: { items: Constat[] }) { return ( {items.length > 0 ? : } ) } export function usePastElement(watch: React.RefObject): boolean { const [past, setPast] = useState(false) useEffect(() => { const check = () => { const el = watch.current; if (el) setPast(el.getBoundingClientRect().bottom < 0) } check() window.addEventListener('scroll', check, { passive: true }) window.addEventListener('resize', check) return () => { window.removeEventListener('scroll', check); window.removeEventListener('resize', check) } }, [watch]) return past } const prixTxt = (p: ProductDetail) => (p.price != null ? formatPrice(p.price, p.currency) : p.price_on_request ? 'Sur devis' : 'Prix en boutique') export function StickyCTA({ p, show }: { p: ProductDetail; show: boolean }) { const r = rabais(p) return (
{prixTxt(p)}
{r ? `Solde −${r.pct} %` : p.store_name}
Voir chez {p.store_name}
) } export function DesktopAside({ p, brief, fav, onFav, onShare }: { p: ProductDetail; brief: Constat[]; fav: boolean; onFav: () => void; onShare: () => void }) { const r = rabais(p) return ( ) } const SUGGESTIONS = ['Ce produit est-il fabriqué au Québec ?', 'Trouve des produits semblables d\'ici', 'Explique la classe d\'origine', 'Compare le prix à d\'autres boutiques', 'Idée cadeau dans la même catégorie'] function envoyerAKa(question: string): boolean { const btn = document.querySelector('.kaa-btn') const ta = document.querySelector('.kaa-panel textarea') const send = document.querySelector('.kaa-in button') if (!btn || !ta || !send) return false btn.click(); ta.value = question; setTimeout(() => send.click(), 60) return true } export function KaAssistant({ p, hidden }: { p: ProductDetail; hidden?: boolean }) { const [open, setOpen] = useState(false) const [q, setQ] = useState('') const [err, setErr] = useState(false) useEffect(() => { const on = () => setOpen(true); window.addEventListener('fb:askka', on); return () => window.removeEventListener('fb:askka', on) }, []) const contexte = () => `(Produit consulté sur Fabri-Ka : ${p.title} chez ${p.store_name}${p.price != null ? ` — ${formatPrice(p.price, p.currency)}` : ''} — https://www.fabri-ka.com/produits/${encodeURIComponent(p.uid)})` const poser = (question: string) => { const ok = envoyerAKa(`${question}\n\n${contexte()}`); if (ok) { setOpen(false); setQ(''); setErr(false) } else setErr(true) } return ( <> setOpen(false)} title="Demander à Ka" sub="Assistant Groupe KA · connaît cette fiche" footer={
{ e.preventDefault(); if (q.trim()) poser(q.trim()) }}> setQ(e.target.value)} placeholder="Posez votre question sur ce produit…" aria-label="Votre question" />
}>

Je peux expliquer l'origine du produit, trouver des alternatives fabriquées au Québec et comparer les boutiques d'ici.

{p.images?.[0] && }{p.title}{[p.store_name, p.price != null ? formatPrice(p.price, p.currency) : null].filter(Boolean).join(' · ')}
{SUGGESTIONS.map((s) => )}
{err &&

L'assistant n'est pas encore chargé — réessayez dans un instant.

}
) }