ifixkart-storefront/lib/categoryTree.ts

116 lines
3.5 KiB
TypeScript

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;
}