add new routing
This commit is contained in:
@@ -1,71 +1,308 @@
|
||||
// lib/api/menu-api.ts
|
||||
|
||||
import { fetchGraphQL } from './graphql-client.js';
|
||||
|
||||
|
||||
interface MenuItemNode {
|
||||
uri: string;
|
||||
url: string;
|
||||
order: number;
|
||||
label: string;
|
||||
export interface MenuItem {
|
||||
id: string;
|
||||
databaseId: number;
|
||||
uri: string;
|
||||
url: string;
|
||||
order: number;
|
||||
label: string;
|
||||
parentId: string | null;
|
||||
target: string;
|
||||
cssClasses: string[];
|
||||
description: string;
|
||||
childItems?: {
|
||||
nodes: MenuItem[];
|
||||
};
|
||||
}
|
||||
|
||||
interface MenuNode {
|
||||
name: string;
|
||||
menuItems: {
|
||||
nodes: MenuItemNode[];
|
||||
};
|
||||
export interface Menu {
|
||||
id: string;
|
||||
databaseId: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
locations: string[];
|
||||
menuItems: {
|
||||
nodes: MenuItem[];
|
||||
};
|
||||
}
|
||||
|
||||
interface MenusResponse {
|
||||
menus: {
|
||||
nodes: MenuNode[];
|
||||
};
|
||||
export type MenuIdentifier =
|
||||
| { id: number } // По ID меню
|
||||
| { location: string } // По локации
|
||||
| { slug: string } // По слагу
|
||||
| { name: string }; // По имени
|
||||
|
||||
/**
|
||||
* Получить меню по идентификатору
|
||||
*/
|
||||
export async function fetchMenu(identifier: MenuIdentifier): Promise<Menu | null> {
|
||||
try {
|
||||
// Определяем тип запроса на основе переданного идентификатора
|
||||
if ('id' in identifier) {
|
||||
return await fetchMenuById(identifier.id);
|
||||
}
|
||||
if ('location' in identifier) {
|
||||
return await fetchMenuByLocation(identifier.location);
|
||||
}
|
||||
if ('slug' in identifier) {
|
||||
return await fetchMenuBySlug(identifier.slug);
|
||||
}
|
||||
if ('name' in identifier) {
|
||||
return await fetchMenuByName(identifier.name);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Error fetching menu:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get navigation menu from WordPress
|
||||
* Получить меню по ID (самый надежный способ)
|
||||
*/
|
||||
export async function navQuery(): Promise<MenusResponse> {
|
||||
try {
|
||||
const query = `{
|
||||
menus(where: {location: PRIMARY}) {
|
||||
nodes {
|
||||
name
|
||||
menuItems {
|
||||
nodes {
|
||||
uri
|
||||
url
|
||||
order
|
||||
label
|
||||
async function fetchMenuById(id: number): Promise<Menu | null> {
|
||||
const query = `
|
||||
query GetMenuById($id: ID!) {
|
||||
menu(id: $id, idType: DATABASE_ID) {
|
||||
id
|
||||
databaseId
|
||||
name
|
||||
slug
|
||||
locations
|
||||
menuItems(first: 100) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
uri
|
||||
url
|
||||
order
|
||||
label
|
||||
parentId
|
||||
target
|
||||
cssClasses
|
||||
description
|
||||
childItems(first: 50) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
label
|
||||
uri
|
||||
url
|
||||
order
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`;
|
||||
|
||||
return await executeQuery<MenusResponse>(query, {}, "navigation");
|
||||
} catch (error) {
|
||||
log.error("Error fetching nav: " + error);
|
||||
// Return fallback data for development
|
||||
return {
|
||||
menus: {
|
||||
nodes: [
|
||||
{
|
||||
name: "Primary",
|
||||
menuItems: {
|
||||
nodes: [
|
||||
{ uri: "/", url: "/", order: 1, label: "Home" },
|
||||
{ uri: "/about/", url: "/about/", order: 2, label: "About" },
|
||||
{
|
||||
uri: "/contact/",
|
||||
url: "/contact/",
|
||||
order: 3,
|
||||
label: "Contact",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
const variables = { id };
|
||||
const data = await fetchGraphQL(query, variables);
|
||||
|
||||
if (data?.menu) {
|
||||
return {
|
||||
...data.menu,
|
||||
menuItems: data.menu.menuItems || { nodes: [] }
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить меню по локации
|
||||
*/
|
||||
async function fetchMenuByLocation(location: string): Promise<Menu | null> {
|
||||
const query = `
|
||||
query GetMenuByLocation($location: MenuLocationEnum!) {
|
||||
menus(where: { location: $location }, first: 1) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
name
|
||||
slug
|
||||
locations
|
||||
menuItems(first: 100) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
uri
|
||||
url
|
||||
order
|
||||
label
|
||||
parentId
|
||||
target
|
||||
cssClasses
|
||||
description
|
||||
childItems(first: 50) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
label
|
||||
uri
|
||||
url
|
||||
order
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const variables = { location };
|
||||
const data = await fetchGraphQL(query, variables);
|
||||
return data?.menus?.nodes?.[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить меню по слагу
|
||||
*/
|
||||
async function fetchMenuBySlug(slug: string): Promise<Menu | null> {
|
||||
const query = `
|
||||
query GetMenuBySlug($slug: String!) {
|
||||
menus(where: { slug: $slug }, first: 1) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
name
|
||||
slug
|
||||
locations
|
||||
menuItems(first: 100) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
uri
|
||||
url
|
||||
order
|
||||
label
|
||||
parentId
|
||||
target
|
||||
cssClasses
|
||||
description
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const variables = { slug };
|
||||
const data = await fetchGraphQL(query, variables);
|
||||
return data?.menus?.nodes?.[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить меню по имени
|
||||
*/
|
||||
async function fetchMenuByName(name: string): Promise<Menu | null> {
|
||||
const query = `
|
||||
query GetMenuByName($name: String!) {
|
||||
menus(where: { name: $name }, first: 1) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
name
|
||||
slug
|
||||
locations
|
||||
menuItems(first: 100) {
|
||||
nodes {
|
||||
id
|
||||
databaseId
|
||||
uri
|
||||
url
|
||||
order
|
||||
label
|
||||
parentId
|
||||
target
|
||||
cssClasses
|
||||
description
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const variables = { name };
|
||||
const data = await fetchGraphQL(query, variables);
|
||||
return data?.menus?.nodes?.[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразовать плоский список элементов меню в иерархическую структуру
|
||||
*/
|
||||
export function buildMenuHierarchy(menuItems: MenuItem[]): MenuItem[] {
|
||||
const itemsMap = new Map<string, MenuItem>();
|
||||
const rootItems: MenuItem[] = [];
|
||||
|
||||
// Создаем map всех элементов
|
||||
menuItems.forEach(item => {
|
||||
itemsMap.set(item.id, {
|
||||
...item,
|
||||
childItems: { nodes: [] }
|
||||
});
|
||||
});
|
||||
|
||||
// Строим иерархию
|
||||
menuItems.forEach(item => {
|
||||
const menuItem = itemsMap.get(item.id)!;
|
||||
|
||||
if (item.parentId && itemsMap.has(item.parentId)) {
|
||||
const parent = itemsMap.get(item.parentId)!;
|
||||
if (!parent.childItems) {
|
||||
parent.childItems = { nodes: [] };
|
||||
}
|
||||
parent.childItems.nodes.push(menuItem);
|
||||
} else {
|
||||
rootItems.push(menuItem);
|
||||
}
|
||||
});
|
||||
|
||||
// Сортируем элементы по order
|
||||
const sortByOrder = (items: MenuItem[]) =>
|
||||
items.sort((a, b) => a.order - b.order);
|
||||
|
||||
// Рекурсивно сортируем все уровни
|
||||
function sortRecursive(items: MenuItem[]) {
|
||||
sortByOrder(items);
|
||||
items.forEach(item => {
|
||||
if (item.childItems?.nodes.length) {
|
||||
sortRecursive(item.childItems.nodes);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sortRecursive(rootItems);
|
||||
return rootItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить меню в виде иерархической структуры
|
||||
*/
|
||||
export async function getHierarchicalMenu(identifier: MenuIdentifier): Promise<MenuItem[]> {
|
||||
const menu = await fetchMenu(identifier);
|
||||
if (!menu || !menu.menuItems?.nodes?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return buildMenuHierarchy(menu.menuItems.nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить меню в виде плоского списка
|
||||
*/
|
||||
export async function getFlatMenu(identifier: MenuIdentifier): Promise<MenuItem[]> {
|
||||
const menu = await fetchMenu(identifier);
|
||||
if (!menu || !menu.menuItems?.nodes?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return menu.menuItems.nodes.sort((a, b) => a.order - b.order);
|
||||
}
|
||||
Reference in New Issue
Block a user