/* ─────────────────────────────────────────────────
Furnishfy — Home page (English, LTR)
Sections:
1. Hero Banner
2. Categories Slider (circular, named)
3. Best Sellers slider
4. Per-Category product rows
───────────────────────────────────────────────── */
/* ── ProductCardSlide ── */
function ProductCardSlide({ p, go }) {
const hasImg = p.thumbnail && !p.thumbnail.includes('no-product');
return (
go('product', p.id)}
style={{ cursor: 'pointer', flexShrink: 0, width: 220 }}
>
{hasImg
?

:
}
{p.badge &&
{p.badge.en}}
{p.en}
{money(p.price)}
{p.old && (
{money(p.old)}
)}
);
}
/* ── CategorySlider ── */
function CategorySlider({ categories, go, lang }) {
const trackRef = useRef(null);
const [canPrev, setCanPrev] = useState(false);
const [canNext, setCanNext] = useState(true);
const ITEM_W = 130; // approx width of each item + gap
const scroll = (dir) => {
if (!trackRef.current) return;
trackRef.current.scrollBy({ left: dir * ITEM_W * 2, behavior: 'smooth' });
};
useEffect(() => {
const el = trackRef.current;
if (!el) return;
const update = () => {
setCanPrev(el.scrollLeft > 4);
setCanNext(el.scrollLeft + el.clientWidth < el.scrollWidth - 4);
};
el.addEventListener('scroll', update, { passive: true });
update();
return () => el.removeEventListener('scroll', update);
}, []);
const hues = [28, 95, 55, 75, 18, 40, 65, 85, 50, 30, 60, 20];
return (
{canPrev && (
)}
{canNext && (
)}
{/* scrollable track */}
{categories.map((c, i) => (
go('shop', null, c.id)}
className="cat-item"
>
{/* circle */}
{c.image
?
)
:
}
{/* name — always visible below the circle */}
{lang === "ar" ? c.ar : c.en}
))}
);
}
/* ── CategoryProductRow ── */
function CategoryProductRow({ section, go, lang }) {
const CARD_W = 220;
const GAP = 20;
const VIS = 4;
const [offset, setOffset] = useState(0);
const maxOff = Math.max(0, section.products.length - VIS);
return (
{/* row header */}
{lang === "ar" ? section.ar : section.en}
{/* slider */}
{section.products.map((p) => (
))}
);
}
/* ══════════════════════════════════════════════════
Main Home Component
══════════════════════════════════════════════════ */
function Home({ go, lang }) {
useReveal();
const {
PRODUCTS, CATEGORIES, BANNERS,
BEST_SELLERS, PRODUCTS_BY_CATEGORY,
} = window.FURN;
/* Best sellers fallback */
const bestSellers = (BEST_SELLERS && BEST_SELLERS.length > 0)
? BEST_SELLERS
: PRODUCTS.slice(0, 8);
/* Per-category fallback */
const productsByCategory = (PRODUCTS_BY_CATEGORY && PRODUCTS_BY_CATEGORY.length > 0)
? PRODUCTS_BY_CATEGORY
: CATEGORIES.filter(c => !c.parent).map(c => ({
id: c.id, en: c.en, ar: c.ar,
products: PRODUCTS.filter(p => p.cat === c.id || CATEGORIES.find(sub => sub.id === p.cat)?.parent === c.id),
})).filter(g => g.products.length > 0);
/* ── Hero banner ── */
const bannersToUse = (BANNERS && BANNERS.length > 0) ? BANNERS : [
{
title_en: 'The 2026 Collection',
subtitle_en: 'Furniture that outlives the trend.',
image: '', link: '#',
},
];
const [slide, setSlide] = useState(0);
useEffect(() => {
if (bannersToUse.length <= 1) return;
const t = setInterval(() => setSlide(s => (s + 1) % bannersToUse.length), 5000);
return () => clearInterval(t);
}, [bannersToUse.length]);
const activeBanner = bannersToUse[slide];
/* ── Best sellers slider offset ── */
const BS_W = 220;
const BS_GAP = 20;
const BS_VIS = 4;
const [bsOff, setBsOff] = useState(0);
const bsMax = Math.max(0, bestSellers.length - BS_VIS);
return (
{/* ══ 1. HERO BANNER ══ */}
{bannersToUse.map((banner, i) => (
{(!banner.image || banner.image.endsWith('null')) && (
)}
))}
{/* gradient overlay */}
{/* copy */}
The 2026 Collection — Limited Release
{activeBanner.title_en}
{activeBanner.subtitle_en}
{/* dots */}
{bannersToUse.length > 1 && (
{bannersToUse.map((_, i) => (
)}
Scroll
{/* ══ 2. CATEGORIES SLIDER ══ */}
Shop by category
Featured Categories
!c.parent).filter(c => {
const childIds = CATEGORIES.filter(sub => sub.parent === c.id).map(sub => sub.id);
const count = PRODUCTS.filter(p => p.cat === c.id || childIds.includes(p.cat)).length;
return count > 0;
})} go={go} lang={lang} />
{/* ══ 3. BEST SELLERS ══ */}
{bsOff > 0 && (
)}
{bsOff < bsMax && (
)}
{bestSellers.map((p) => (
))}
{/* ══ 4. PRODUCTS BY CATEGORY ══ */}
Browse the collection
Shop by Category
{productsByCategory.map((section) => (
))}
{/* ══ STYLES ══ */}
);
}
Object.assign(window, { Home });