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>
This commit is contained in:
Alireza Hassani
2026-08-18 11:22:31 +03:30
co-authored by Cursor
parent 1a2b62463e
commit c0a95a826a
34 changed files with 2458 additions and 401 deletions
+32 -13
View File
@@ -1,12 +1,13 @@
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
import type { Product } from "@/data/content";
import { toFaDigits } from "@/lib/format";
import type { Product } from "@/lib/catalog";
import { slotImages, type StaticImageSlot } from "@/lib/static-images";
import { Carousel } from "./Carousel";
import { Placeholder } from "./Placeholder";
import { ProductCard } from "./ProductCard";
import { SectionHeading } from "./SectionHeading";
import { SlotImage } from "./SlotImage";
type Props = {
id?: string;
@@ -15,6 +16,8 @@ type Props = {
products: Product[];
countdown?: boolean;
leadBanner?: boolean;
bannerSlot?: StaticImageSlot;
href?: string;
};
export function ProductCarousel({
@@ -24,30 +27,42 @@ export function ProductCarousel({
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 ? (
<a
href="#"
<div
data-card
className="flex w-[220px] min-h-[280px] shrink-0 snap-start self-stretch overflow-hidden rounded-3xl sm:w-[240px]"
className="flex w-[280px] min-h-[320px] shrink-0 snap-start self-stretch overflow-hidden rounded-3xl sm:w-[300px]"
aria-label="بنر فروش ویژه"
>
<Placeholder
src="/images/sale-banner.png"
alt=""
<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"
/>
</a>
</div>
) : null}
{products.map((product) => (
<ProductCard key={product.id} product={product} />
@@ -94,11 +109,15 @@ function SaleTimer() {
{cells.map((cell, index) => (
<div key={cell.label} className="flex items-end gap-1.5">
{index > 0 ? (
<span className="font-count mb-5 text-xl leading-none text-rose-400">:</span>
<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 className="font-count text-[1.65rem] leading-none text-rose-600">
{toFaDigits(String(cell.value).padStart(2, "0"))}
<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>