Files
hoomat-store/app/components/product-carousel.tsx
T

130 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import Image from "next/image";
import Link from "next/link";
import { useRef } from "react";
type Product = {
title: string;
enName: string;
price: string;
image: string;
href?: string;
};
type SaleBanner = {
image?: string | null;
linkUrl?: string | null;
ariaLabel?: string;
};
function ProductPrice({ price }: { price: string }) {
const trimmed = price.trim();
const match = trimmed.match(/^([\d٬,.\s]+)\s*(تومان)$/);
if (match) {
return (
<p className="price price-with-amount" dir="ltr">
<span className="price-amount ltr-number" lang="en">
{match[1].trim()}
</span>
<span className="price-unit">تومان</span>
</p>
);
}
return <p className="price price-note">{trimmed}</p>;
}
function ProductCard({ product }: { product: Product }) {
return (
<Link
href={product.href || "/store"}
className="product-card"
aria-label={product.title}
>
<Image src={product.image} alt={product.title} width={560} height={560} />
<div className="product-body">
<p className="product-en-name">{product.enName}</p>
<h3>{product.title}</h3>
<ProductPrice price={product.price} />
</div>
</Link>
);
}
function SaleBannerCard({ banner }: { banner?: SaleBanner | null }) {
const style = banner?.image
? {
backgroundImage: `linear-gradient(90deg, rgba(136, 63, 63, 0.55), rgba(0, 35, 75, 0.5)), url(${banner.image})`,
backgroundSize: "cover",
backgroundPosition: "center",
}
: undefined;
const className = "sale sale-promo-card";
const label = banner?.ariaLabel || "فروش ویژه";
if (banner?.linkUrl) {
return (
<a href={banner.linkUrl} className={className} style={style} aria-label={label} />
);
}
return (
<Link href="/store" className={className} style={style} aria-label={label} />
);
}
export function ProductCarousel({
products,
ariaLabel,
withSaleBanner = false,
saleBanner,
}: {
products: Product[];
ariaLabel: string;
withSaleBanner?: boolean;
saleBanner?: SaleBanner | null;
}) {
const carouselRef = useRef<HTMLDivElement>(null);
const scrollCarousel = (direction: "next" | "previous") => {
const amount = 300;
carouselRef.current?.scrollBy({
left: direction === "next" ? -amount : amount,
behavior: "smooth",
});
};
return (
<div className="product-carousel-shell">
<button
className="carousel-chevron carousel-chevron-left"
type="button"
aria-label="محصولات بعدی"
onClick={() => scrollCarousel("next")}
>
‹
</button>
<div
ref={carouselRef}
className={`carousel ${withSaleBanner ? "sale-carousel" : ""}`}
aria-label={ariaLabel}
>
{withSaleBanner ? <SaleBannerCard banner={saleBanner} /> : null}
{products.map((product) => (
<ProductCard key={`${ariaLabel}-${product.title}`} product={product} />
))}
</div>
<button
className="carousel-chevron carousel-chevron-right"
type="button"
aria-label="محصولات قبلی"
onClick={() => scrollCarousel("previous")}
>
›
</button>
</div>
);
}