import { CategoryResponse } from '@/services/api/catalogService'; export type SearchCategoryOption = { category_id: string; slug: string; name: string; label: string; }; export function isActiveCategory(category: CategoryResponse): boolean { return category.is_active !== false; } export function sortCategories(list: CategoryResponse[]): CategoryResponse[] { return [...list].sort((a, b) => { const orderA = parseInt(String(a.sort_order || '0'), 10); const orderB = parseInt(String(b.sort_order || '0'), 10); if (orderA !== orderB) return orderA - orderB; return (a.name || '').localeCompare(b.name || '', undefined, { sensitivity: 'base' }); }); } export function normalizeCategories(list: CategoryResponse[] | null | undefined): CategoryResponse[] { return sortCategories((list || []).filter(isActiveCategory)); } function parentExists(category: CategoryResponse, all: CategoryResponse[]): boolean { if (!category.parent_category_id) return false; return all.some((item) => item.category_id === category.parent_category_id); } export function getTopLevelCategories(list: CategoryResponse[]): CategoryResponse[] { const all = normalizeCategories(list); return all.filter((category) => !parentExists(category, all)); } export function getChildCategories(list: CategoryResponse[], parentId: string): CategoryResponse[] { return normalizeCategories(list).filter((category) => category.parent_category_id === parentId); } export function getDescendantIds(list: CategoryResponse[], categoryId: string): string[] { const ids = [categoryId]; const walk = (parentId: string) => { getChildCategories(list, parentId).forEach((child) => { ids.push(child.category_id); walk(child.category_id); }); }; walk(categoryId); return ids; } export function findCategory( list: CategoryResponse[], slugOrId: string | null | undefined ): CategoryResponse | undefined { if (!slugOrId) return undefined; const needle = String(slugOrId).trim().toLowerCase(); if (!needle) return undefined; return normalizeCategories(list).find( (category) => category.category_id === slugOrId || category.slug.toLowerCase() === needle || category.name.toLowerCase() === needle ); } export type CategoryNavNode = CategoryResponse & { children: CategoryResponse[]; }; export function getCategoryNavTree(list: CategoryResponse[]): CategoryNavNode[] { return getTopLevelCategories(list).map((root) => ({ ...root, children: getChildCategories(list, root.category_id), })); } export function getSearchCategoryOptions(list: CategoryResponse[]): SearchCategoryOption[] { const result: SearchCategoryOption[] = []; const topLevel = getTopLevelCategories(list); topLevel.forEach((parent) => { result.push({ category_id: parent.category_id, slug: parent.slug, name: parent.name, label: parent.name, }); const children = getChildCategories(list, parent.category_id); children.forEach((child) => { result.push({ category_id: child.category_id, slug: child.slug, name: child.name, label: `${parent.name} → ${child.name}`, }); }); }); // Include any orphan active categories as well const includedIds = new Set(result.map((r) => r.category_id)); normalizeCategories(list).forEach((cat) => { if (!includedIds.has(cat.category_id)) { result.push({ category_id: cat.category_id, slug: cat.slug, name: cat.name, label: cat.name, }); } }); return result; }