SPB Git

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%
1.7 KB · 61 lines tsx
Raw Blame History
1import { useEffect, useState } from 'react'2import { Link } from 'react-router-dom'3import { fetchProducts, Product, ProductQuery } from '../api'4import { IconArrowRight } from './Icons'5import ProductCard from './ProductCard'6import { SkeletonRow } from './Skeleton'78interface RailProps {9  title: string10  query: ProductQuery11  seeAllHref?: string12}1314export default function Rail({ title, query, seeAllHref }: RailProps) {15  const [products, setProducts] = useState<Product[] | null>(null)16  const [error, setError] = useState(false)1718  useEffect(() => {19    const controller = new AbortController()20    setProducts(null)21    setError(false)22    fetchProducts({ per_page: 12, ...query }, controller.signal)23      .then((res) => setProducts(res.items))24      .catch((err: unknown) => {25        if (err instanceof DOMException && err.name === 'AbortError') return26        setError(true)27        setProducts([])28      })29    return () => controller.abort()30    // eslint-disable-next-line react-hooks/exhaustive-deps31  }, [JSON.stringify(query)])3233  if (error || (products !== null && products.length === 0)) {34    return null35  }3637  return (38    <section className="rail">39      <header className="section-header">40        <h2>{title}</h2>41        {seeAllHref && (42          <Link className="section-see-all" to={seeAllHref}>43            Tout voir <IconArrowRight size={15} />44          </Link>45        )}46      </header>47      {products === null ? (48        <SkeletonRow count={6} />49      ) : (50        <div className="rail-track">51          {products.map((p) => (52            <div className="rail-item" key={p.uid}>53              <ProductCard product={p} />54            </div>55          ))}56        </div>57      )}58    </section>59  )60}61