Files
nini-naderi/src/components/ProductCarousel.tsx
T
Alireza HassaniandCursor c0a95a826a Connect the storefront to the Meshkee Website API.
Products, blog, search, mega menu, and home carousels now read live tenant data, and login goes to the customer portal.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-18 11:22:31 +03:30

129 lines
3.5 KiB
TypeScript

"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
import type { Product } from "@/lib/catalog";
import { slotImages, type StaticImageSlot } from "@/lib/static-images";
import { Carousel } from "./Carousel";
import { ProductCard } from "./ProductCard";
import { SectionHeading } from "./SectionHeading";
import { SlotImage } from "./SlotImage";
type Props = {
id?: string;
english: string;
title: string;
products: Product[];
countdown?: boolean;
leadBanner?: boolean;
bannerSlot?: StaticImageSlot;
href?: string;
};
export function ProductCarousel({
id,
english,
title,
products,
countdown,
leadBanner,
bannerSlot,
href,
}: Props) {
const saleBanner = slotImages(bannerSlot)[0];
if (!products.length && !leadBanner) return null;
return (
<section id={id} className="container-nn py-8">
<SectionHeading english={english} title={title}>
{countdown ? <SaleTimer /> : null}
{href ? (
<Link href={href} className="text-sm font-bold text-purple-700 hover:text-purple-800">
مشاهده همه
</Link>
) : null}
</SectionHeading>
<Carousel>
{leadBanner ? (
<div
data-card
className="flex w-[280px] min-h-[320px] shrink-0 snap-start self-stretch overflow-hidden rounded-3xl sm:w-[300px]"
aria-label="بنر فروش ویژه"
>
<SlotImage
image={saleBanner}
fallbackSrc="/images/sale-banner.png"
fallbackAlt="فروش ویژه"
aspectRatio={bannerSlot?.aspectRatio}
width={240}
height={400}
rounded="rounded-3xl"
fill
className="h-full w-full"
fallbackHref="/special-sale"
/>
</div>
) : null}
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</Carousel>
</section>
);
}
function SaleTimer() {
const [left, setLeft] = useState({ h: 11, m: 42, s: 18 });
useEffect(() => {
const timer = window.setInterval(() => {
setLeft((current) => {
let { h, m, s } = current;
if (s > 0) s -= 1;
else if (m > 0) {
s = 59;
m -= 1;
} else if (h > 0) {
s = 59;
m = 59;
h -= 1;
} else {
h = 11;
m = 59;
s = 59;
}
return { h, m, s };
});
}, 1000);
return () => window.clearInterval(timer);
}, []);
const cells = [
{ label: "ساعت", value: left.h },
{ label: "دقیقه", value: left.m },
{ label: "ثانیه", value: left.s },
];
return (
<div className="flex items-end gap-1.5">
{cells.map((cell, index) => (
<div key={cell.label} className="flex items-end gap-1.5">
{index > 0 ? (
<span className="font-display mb-5 text-xl leading-none text-rose-400">:</span>
) : null}
<div className="min-w-[3.25rem] rounded-2xl bg-linear-to-b from-rose-100 to-rose-50 px-2.5 py-2 text-center shadow-[inset_0_1px_0_rgb(255_255_255_/_0.8)]">
<p
dir="ltr"
lang="en"
className="font-display text-[1.65rem] font-semibold leading-none tracking-tight text-rose-600"
>
{String(cell.value).padStart(2, "0")}
</p>
<p className="mt-1 text-[10px] font-medium text-rose-400">{cell.label}</p>
</div>
</div>
))}
</div>
);
}