157 lines
4.0 KiB
TypeScript
157 lines
4.0 KiB
TypeScript
import type { MegaTab } from "@/data/home";
|
|
import type { MeshkeeCategory } from "@/lib/meshkee-categories";
|
|
|
|
type TreeNode = MeshkeeCategory & { children: TreeNode[] };
|
|
|
|
const FEATURED_BY_SLUG: Record<
|
|
string,
|
|
{ title: string; image: string; imageClass?: string }
|
|
> = {
|
|
industry: {
|
|
title: "Iranian industry",
|
|
image: "/images/categories/industry.png",
|
|
imageClass: "drum",
|
|
},
|
|
industries: {
|
|
title: "Iranian industry",
|
|
image: "/images/categories/industry.png",
|
|
imageClass: "drum",
|
|
},
|
|
stores: {
|
|
title: "Persian unique style",
|
|
image: "/images/categories/clothes.png",
|
|
imageClass: "dress",
|
|
},
|
|
wholesellers: {
|
|
title: "Wholesale market",
|
|
image: "/images/categories/shoes.png",
|
|
imageClass: "shoes",
|
|
},
|
|
"whole-sellers": {
|
|
title: "Wholesale market",
|
|
image: "/images/categories/shoes.png",
|
|
imageClass: "shoes",
|
|
},
|
|
services: {
|
|
title: "Professional services",
|
|
image: "/images/categories/services.png",
|
|
imageClass: "notebook",
|
|
},
|
|
};
|
|
|
|
const ICON_BY_SLUG: Record<string, string> = {
|
|
industry: "/images/icons/gear.svg",
|
|
industries: "/images/icons/gear.svg",
|
|
stores: "/images/icons/cart.svg",
|
|
wholesellers: "/images/icons/gear.svg",
|
|
"whole-sellers": "/images/icons/gear.svg",
|
|
services: "/images/icons/home-outline.svg",
|
|
};
|
|
|
|
const DEFAULT_FEATURED = {
|
|
title: "Explore IranBay",
|
|
image: "/images/categories/clothes.png",
|
|
imageClass: "dress",
|
|
};
|
|
|
|
function sortNodes(nodes: TreeNode[]) {
|
|
nodes.sort(
|
|
(a, b) =>
|
|
a.sortOrder - b.sortOrder ||
|
|
a.name.localeCompare(b.name, undefined, { sensitivity: "base" }),
|
|
);
|
|
for (const node of nodes) sortNodes(node.children);
|
|
}
|
|
|
|
function buildTree(categories: MeshkeeCategory[]): TreeNode[] {
|
|
const byId = new Map<string, TreeNode>();
|
|
for (const category of categories) {
|
|
byId.set(category.id, { ...category, children: [] });
|
|
}
|
|
|
|
const roots: TreeNode[] = [];
|
|
for (const node of byId.values()) {
|
|
if (node.parentId && byId.has(node.parentId)) {
|
|
byId.get(node.parentId)!.children.push(node);
|
|
} else {
|
|
roots.push(node);
|
|
}
|
|
}
|
|
|
|
sortNodes(roots);
|
|
return roots;
|
|
}
|
|
|
|
function categoryHref(category: MeshkeeCategory) {
|
|
const slug = category.slug?.trim();
|
|
if (slug) return `/businesses?category=${encodeURIComponent(slug)}`;
|
|
return `/businesses?categoryId=${encodeURIComponent(category.id)}`;
|
|
}
|
|
|
|
function resolveIcon(category: MeshkeeCategory) {
|
|
const icon = category.icon?.trim();
|
|
if (icon) {
|
|
if (
|
|
icon.startsWith("/") ||
|
|
icon.startsWith("http://") ||
|
|
icon.startsWith("https://")
|
|
) {
|
|
return icon;
|
|
}
|
|
}
|
|
return ICON_BY_SLUG[category.slug] ?? "/images/icons/category.svg";
|
|
}
|
|
|
|
function resolveFeatured(category: MeshkeeCategory) {
|
|
const mapped = FEATURED_BY_SLUG[category.slug];
|
|
if (mapped) return mapped;
|
|
return {
|
|
...DEFAULT_FEATURED,
|
|
title: category.name ? `Explore ${category.name}` : DEFAULT_FEATURED.title,
|
|
};
|
|
}
|
|
|
|
/** Roots → groups (L2) → links (L3) for the website mega menu. */
|
|
export function buildMegaMenuTabs(categories: MeshkeeCategory[]): MegaTab[] {
|
|
const roots = buildTree(categories).filter(
|
|
(root) => root.slug !== "other" && root.name.trim(),
|
|
);
|
|
|
|
return roots.map((root) => {
|
|
const groups = root.children.map((group) => {
|
|
const links = group.children.length
|
|
? group.children.map((child) => ({
|
|
label: child.name,
|
|
href: categoryHref(child),
|
|
}))
|
|
: [
|
|
{
|
|
label: group.name,
|
|
href: categoryHref(group),
|
|
},
|
|
];
|
|
|
|
return {
|
|
title: group.name,
|
|
links,
|
|
};
|
|
});
|
|
|
|
return {
|
|
id: root.slug || root.id,
|
|
label: root.name,
|
|
icon: resolveIcon(root),
|
|
groups:
|
|
groups.length > 0
|
|
? groups
|
|
: [
|
|
{
|
|
title: root.name,
|
|
links: [{ label: "Browse", href: categoryHref(root) }],
|
|
},
|
|
],
|
|
featured: resolveFeatured(root),
|
|
};
|
|
});
|
|
}
|