'use client';
import React, { useEffect, useMemo, useState } from 'react';
import Link from 'next/link';
import { Star, PackageX } from 'lucide-react';
import {
catalogService,
CategoryResponse,
ProductCardResponse,
} from '@/services/api/catalogService';
import { formatCurrency, getImageUrl, parseMoney } from '@/lib/utils';
import {
CmsMegaMenuPanel,
hasCmsMegaGroups,
} from '@/components/CmsMegaMenuPanel';
import type { MegaMenuData } from '@/services/api/storefrontService';
import { storefrontService } from '@/services/api/storefrontService';
type DynamicTab = {
id: string;
label: string;
slug?: string;
};
type MegaProduct = {
id: string;
name: string;
slug: string;
image: string;
price: number;
oldPrice?: number;
discount?: number;
rating: number;
categoryId?: string;
};
function mapCard(p: ProductCardResponse): MegaProduct {
const price = parseMoney(p.price);
const old =
p.compare_price != null && parseMoney(p.compare_price) > price
? parseMoney(p.compare_price)
: undefined;
const discount =
parseMoney(p.discount_percent) ||
(old ? Math.round(((old - price) / old) * 100) : undefined);
return {
id: p.product_id,
name: p.name,
slug: p.slug,
image: getImageUrl(p.thumbnail_url) || '',
price,
oldPrice: old,
discount: discount || undefined,
rating: Number(p.rating) || 4,
categoryId: p.category_id,
};
}
function MegaProductCard({ product }: { product: MegaProduct }) {
const rating = Math.round(product.rating || 4);
const [imgFailed, setImgFailed] = useState(false);
const showImage = Boolean(product.image) && !imgFailed;
return (
{product.discount ? (
-{product.discount}%
) : null}
{showImage ? (
// eslint-disable-next-line @next/next/no-img-element

setImgFailed(true)}
className="max-h-full max-w-[85%] object-contain group-hover/card:scale-[1.03] transition-transform duration-300"
/>
) : (
)}
{product.name}
{Array.from({ length: 5 }).map((_, i) => (
))}
{product.oldPrice != null && product.oldPrice > product.price ? (
{formatCurrency(product.oldPrice)}
) : null}
{formatCurrency(product.price)}
);
}
export const ProductsMegaMenu: React.FC<{ cms?: MegaMenuData | null }> = ({
cms,
}) => {
const [activeTabId, setActiveTabId] = useState('all');
const [allProducts, setAllProducts] = useState([]);
const [categories, setCategories] = useState([]);
const [loading, setLoading] = useState(true);
const [remote, setRemote] = useState(cms ?? null);
useEffect(() => {
if (hasCmsMegaGroups(cms)) {
setRemote(cms ?? null);
return;
}
let cancelled = false;
storefrontService.getMegaMenu().then((menus) => {
if (cancelled) return;
setRemote(menus.products || null);
});
return () => {
cancelled = true;
};
}, [cms]);
useEffect(() => {
if (hasCmsMegaGroups(remote) || hasCmsMegaGroups(cms)) return;
let cancelled = false;
const load = async () => {
setLoading(true);
try {
const [cats, productRes] = await Promise.all([
catalogService.getCategories(),
catalogService.getProductsPaginated({ limit: 48 }),
]);
if (cancelled) return;
const catList = cats || [];
setCategories(catList);
setAllProducts((productRes.products || []).map((p) => mapCard(p)));
const rootCats = catList.filter((c) => !c.parent_category_id);
if (rootCats.length > 0) {
setActiveTabId(rootCats[0].category_id);
} else if (catList.length > 0) {
setActiveTabId(catList[0].category_id);
}
} finally {
if (!cancelled) setLoading(false);
}
};
void load();
return () => {
cancelled = true;
};
}, [cms, remote]);
const tabs: DynamicTab[] = useMemo(() => {
const rootCats = categories.filter((c) => !c.parent_category_id);
const topCats = rootCats.length > 0 ? rootCats : categories;
const dynamic = topCats.slice(0, 6).map((c) => ({
id: c.category_id,
label: c.name,
slug: c.slug,
}));
return dynamic.length > 0
? dynamic
: [{ id: 'all', label: 'All Products' }];
}, [categories]);
const filteredProducts = useMemo(() => {
if (activeTabId === 'all') {
return allProducts.slice(0, 5);
}
const childIds = new Set(
categories
.filter((c) => c.parent_category_id === activeTabId)
.map((c) => c.category_id)
);
childIds.add(activeTabId);
const matches = allProducts.filter(
(p) => p.categoryId && childIds.has(p.categoryId)
);
return (matches.length > 0 ? matches : allProducts).slice(0, 5);
}, [allProducts, categories, activeTabId]);
if (hasCmsMegaGroups(remote)) {
return ;
}
const activeTabLabel =
tabs.find((t) => t.id === activeTabId)?.label || 'Products';
return (
{/* Centered tabs — dynamic from database categories */}
{tabs.map((tab, idx) => (
{idx > 0 && (
|
)}
))}
{loading ? (
{Array.from({ length: 5 }).map((_, i) => (
))}
) : filteredProducts.length === 0 ? (
No products in {activeTabLabel}
View all products
) : (
{Array.from({ length: 5 }).map((_, i) => {
const product = filteredProducts[i];
if (!product) {
return
;
}
return (
);
})}
)}
);
};
export function isProductsNavLabel(label: string): boolean {
const n = label.toLowerCase().trim();
if (n === 'products' || n === 'product') return true;
if (n.includes('featured product')) return true;
return n === 'hot products' || n === 'new products';
}