import HeroSlider, { type Slide } from "@/components/HeroSlider"; import CategoryCarousel from "@/components/CategoryCarousel"; import HotDeals from "@/components/HotDeals"; import ProductCarousel from "@/components/ProductCarousel"; import { OneBanner, ThreeBanners, TwoBanners } from "@/components/PromoBanners"; import BlogCarousel, { type BlogCardData } from "@/components/BlogCarousel"; import { findSlot, getBlogs, getCategories, getProducts, getSliders, getStaticImageSlots, getStoreSpecials, safe, } from "@/lib/api"; import { buildCategoryTree, findNode, subtreeIds } from "@/lib/categoryTree"; import { productToCard, specialToCards } from "@/lib/cards"; import { blogHref, categoryHref } from "@/lib/slug"; import { HOME_CAROUSELS } from "@/data/site"; import { FALLBACK_BLOGS } from "@/data/fallbackBlogs"; // The slider slot is empty on this tenant, so the homepage falls back to the // campaign banners already running on moalem.shop (same art, same targets). const FALLBACK_SLIDES: Slide[] = [ { id: "laptop", image: "/images/banners/9WYorEOTwn.jpg", mobileImage: "/images/banners/WRbs72TDPR.jpg", href: categoryHref("1254", "لپ تاپ"), alt: "لپ تاپ", }, { id: "console", image: "/images/banners/OiNl9v5gTf.jpg", mobileImage: "/images/banners/ieYGotL2qd.jpg", href: categoryHref("1256", "کنسول بازی"), alt: "کنسول بازی", }, { id: "iphone-17", image: "/images/banners/06SQinO4sG.jpg", mobileImage: "/images/banners/lAGRh3ks32.jpg", href: categoryHref("1251", "موبایل"), alt: "آیفون ۱۷ پرو مکس", }, ]; const EMPTY_PAGE = { items: [], total: 0, page: 1, pageSize: 12 }; export default async function HomePage() { const [categories, sliders, specials, blogs, imageSlots] = await Promise.all([ safe(getCategories().then(buildCategoryTree), []), safe(getSliders(), []), safe(getStoreSpecials(), []), safe(getBlogs({ pageSize: 10 }), { items: [], total: 0, page: 1, pageSize: 10 }), safe(getStaticImageSlots("home"), []), ]); // Empty or failing slots fall through to each section's own placeholder — // findSlot() already returns undefined for an empty/missing key. const sliderSlot = findSlot(imageSlots, "slider"); const categoriesSlot = findSlot(imageSlots, "categories"); const oneBannerSlot = findSlot(imageSlots, "one-banner-bg"); const twoBannerSlot = findSlot(imageSlots, "two-banner-bg"); const threeBannerSlot = findSlot(imageSlots, "three-banner-bg"); const slides: Slide[] = sliders.length > 0 ? sliders .filter((s) => s.imageUrl) .map((s, i) => ({ id: s.id ?? `slide-${i}`, image: s.imageUrl!, mobileImage: s.mobileImageUrl ?? undefined, href: s.linkUrl ?? "/products", alt: s.title ?? "بنر فروشگاه موبایل معلم", })) : FALLBACK_SLIDES; // "تخفیف‌های داغ" prefers the curated special-discount group; until it is // filled in the dashboard it falls back to the newest catalog products. const discountGroup = specials.find((s) => s.key === "special-discount" && s.isActive) ?? specials[0]; const dealsFromCms = discountGroup ? specialToCards(discountGroup) : []; const fallbackDeals = dealsFromCms.length ? [] : (await safe(getProducts({ pageSize: 12 }), EMPTY_PAGE)).items.map(productToCard); const deals = dealsFromCms.length ? dealsFromCms : fallbackDeals; const carousels = await Promise.all( HOME_CAROUSELS.map(async (section) => { const cat = findNode(categories, section.categoryId); const ids = cat ? subtreeIds(cat) : [section.categoryId]; const pages = await Promise.all( ids.map((categoryId) => safe(getProducts({ categoryId, pageSize: 12 }), EMPTY_PAGE)) ); const seen = new Set(); const products = pages .flatMap((page) => page.items) .filter((product) => !seen.has(product.id) && seen.add(product.id)) .slice(0, 12) .map(productToCard); return { ...section, href: categoryHref(section.categoryId, cat?.nameFa ?? section.title, cat?.name), products, }; }) ); const posts: BlogCardData[] = blogs.items.length > 0 ? blogs.items.map((b) => ({ id: b.id, href: blogHref(b.id, b.title ?? b.nameFa), title: b.title ?? b.nameFa ?? "", image: b.thumbnailUrl ?? b.image ?? null, category: b.categoryNameFa ?? b.categoryName ?? undefined, })) : FALLBACK_BLOGS.map((b) => ({ id: b.id, href: "/blog", title: b.title, image: b.image, category: b.category, })); // The deals countdown runs to the end of the current day, recomputed on each // server render so the timer never shows a stale target. const endOfDay = new Date(); endOfDay.setHours(23, 59, 59, 999); const [mobileCarousel, accessoriesCarousel, laptopCarousel, consoleCarousel] = carousels; return ( <>

فروشگاه موبایل معلم | خرید موبایل، لپ‌تاپ و لوازم جانبی

{mobileCarousel && ( )} {accessoriesCarousel && ( )} {laptopCarousel && ( )} {consoleCarousel && ( )} ); }