@websolutespa/payload-plugin-bowl
Version:
Bowl PayloadCms plugin of the BOM Repository
246 lines (245 loc) • 8.9 kB
JavaScript
import { MenuCategoryStrategy, asCategoryId, isObject, uuidv4 } from '@websolutespa/bom-core';
import { filterRoutes } from '../api/utils';
export const MAX_INT = 1000000000000; // 9007199254740991
function makeCategoryMenuItem_(item, category) {
const id = item.id || uuidv4();
const title = item.customTitle || category.title || '';
const abstract = item.abstract || undefined;
const customClass = item.customClass || undefined;
const media = item.media || category.media;
const items = [];
return category.isHidden ? {
type: 'group',
id,
title,
abstract,
media,
customClass,
items
} : {
type: 'category',
category: category.id,
id,
href: '',
title,
abstract,
media,
customClass,
items
};
}
export function decorateMenuCategory_(item, categories, routes, market, depth = 0) {
const strategy = item.strategy || MenuCategoryStrategy.Default;
const categoryId = asCategoryId(item.category);
// find category
const category = categoryId ? categories.find((x)=>x.id === categoryId) : undefined;
if (category) {
const decoratedItem = makeCategoryMenuItem_(item, category);
if (!category.isHidden) {
const route = routes.find((route)=>route.isDefault && route.resolvedCategory === category.id);
if (route) {
decoratedItem.href = route.id;
if (!decoratedItem.media) {
decoratedItem.media = route.media;
}
}
}
// checking for max depth recursion
let maxDepth = item.maxDepth;
if (typeof maxDepth === 'number') {
if (depth > maxDepth) {
return decoratedItem;
}
maxDepth--;
}
// search child categories
const childCategories = (category.id ? categories.filter((x)=>asCategoryId(x.category) === category.id) : []).filter((x)=>{
switch(strategy){
case MenuCategoryStrategy.ExcludeHidden:
return Boolean(x.isHidden) === false;
case MenuCategoryStrategy.Default:
return true;
}
});
// sort child categories
childCategories.sort((a, b)=>{
return (a.order || MAX_INT) - (b.order || MAX_INT);
});
// define sub strategy (!!! todo)
const subStrategy = strategy;
// decorate child categories
const childCategoryItems = childCategories.map((c)=>decorateMenuCategory_({
id: c.id,
type: 'category',
category: c.id,
maxDepth,
strategy: subStrategy,
items: []
}, categories, routes, market, depth + 1));
// find child routes
const childRoutes = routes.filter((route)=>{
switch(strategy){
case MenuCategoryStrategy.ExcludeHidden:
return route.resolvedCategory === category.id && Boolean(route.isDefault) === false;
case MenuCategoryStrategy.Default:
return route.category === category.id && (category.isHidden || Boolean(route.isDefault) === false);
}
});
// sort child routes
childRoutes.sort((a, b)=>{
return (a.order || MAX_INT) - (b.order || MAX_INT);
});
// decorate child routes
const childRouteItems = childRoutes.map((x)=>decorateMenuRoute_(x));
// filter items
decoratedItem.items = [
...childCategoryItems,
...childRouteItems
].filter((x)=>Boolean(x));
return decoratedItem;
}
// return unresolved category as group
return {
id: item.id || uuidv4(),
type: 'group',
title: item.customTitle || '',
items: []
};
}
export function decorateMenuGroup_(item, categories, routes, market) {
const decoratedItem = {
id: item.id,
type: item.type,
title: item.title,
media: item.media,
abstract: item.abstract,
customClass: item.customClass,
extra: item.extra,
items: (item.items || []).filter((x)=>hasMarket(x, market)).map((x)=>decorateMenuItem_(x, categories, routes, market))
};
return decoratedItem;
}
export function decorateMenuLink_(item, categories, routes, market) {
const decoratedItem = {
id: item.id,
type: item.type,
title: item.title,
href: item.href,
target: item.target,
media: item.media,
abstract: item.abstract,
customClass: item.customClass,
extra: item.extra,
items: (item.items || []).filter((x)=>hasMarket(x, market)).map((x)=>decorateMenuItem_(x, categories, routes, market))
};
return decoratedItem;
}
export function decorateMenuPage_(item, categories, routes, market) {
const page = isObject(item.page.value) ? item.page.value : {
id: item.page.value
};
// console.log('decorateMenuPage_', page);
const route = routes.find((x)=>x.schema === item.page.relationTo && x.page === page.id);
// console.log('decorateMenuPage_', page, route);
const schema = item.schema || item.page.relationTo;
const decoratedItem = {
type: item.type,
schema,
id: item.id,
href: route?.id || '',
page: route ? route.page : page.id,
title: item.customTitle || page.title || route?.title || '',
items: (item.items || []).filter((x)=>hasMarket(x, market)).map((x)=>decorateMenuItem_(x, categories, routes, market))
};
if (item.abstract) {
decoratedItem.abstract = item.abstract;
}
if (item.extra) {
decoratedItem.extra = item.extra;
}
if (item.customClass) {
decoratedItem.customClass = item.customClass;
}
const media = item.media || page.media || route?.media;
if (media) {
decoratedItem.media = media;
}
// items?: IMenuItem[];
return decoratedItem;
}
export function decorateMenuRoute_(item) {
const decoratedItem = {
id: item.page,
type: 'route',
title: item.title,
media: item.media,
href: item.id,
page: item.page,
schema: item.schema,
items: []
};
return decoratedItem;
}
export function decorateMenuItem_(item, categories, routes, market, depth = 0) {
switch(item.type){
case 'category':
return decorateMenuCategory_(item, categories, routes, market, depth);
case 'group':
return decorateMenuGroup_(item, categories, routes, market);
case 'link':
return decorateMenuLink_(item, categories, routes, market);
case 'page':
return decorateMenuPage_(item, categories, routes, market);
default:
// eslint-disable-next-line no-case-declarations
const { blockType, ...rest } = item;
return {
...rest,
type: blockType
};
}
}
export function decorateNavItem_(item, categories, routes, market, depth = 0) {
switch(item.type){
case 'category':
return decorateMenuCategory_(item, categories, routes, market, depth);
case 'page':
if (Array.isArray(item.page.value)) {
return item.page.value.map((x)=>{
return decorateMenuPage_({
...item,
page: {
...item.page,
value: x
}
}, categories, routes, market);
});
}
return decorateMenuPage_(item, categories, routes, market);
}
}
// !!! todo how to handle unknown types?
export function hasMarket(item, market) {
return market === 'all' ? true : Array.isArray(item.markets) && item.markets.length > 0 ? item.markets.includes(market) : true;
}
export async function decorateMenu_(item, context) {
// console.log('decorateMenu_');
const decoratedItem = {
id: item.id,
items: []
};
const { market, locale, markets, locales, routes, categories } = context;
// check if language is enabled
if (!locales.includes(locale) && locale !== 'all') {
return decoratedItem;
}
// check if market is enabled
if (!markets.includes(market) && market !== 'all') {
return decoratedItem;
}
const filteredRoutes = filterRoutes(routes, market, locale);
// check if market is enabled
decoratedItem.items = (item.items || []).filter((x)=>hasMarket(x, market)).map((x)=>decorateMenuItem_(x, categories, filteredRoutes, market));
return decoratedItem;
}
//# sourceMappingURL=menu.js.map