import {create} from 'zustand'; import * as burst_api from '../utils/api'; import getAnchor from '../utils/getAnchor'; const fetchMenu = () => { return burst_settings.menu; }; // Parses menu items and nested items in single array const menuItemParser = ( parsedMenuItems, menuItems ) => { menuItems.forEach( ( menuItem ) => { if ( menuItem.visible ) { parsedMenuItems.push( menuItem.id ); if ( menuItem.hasOwnProperty( 'menu_items' ) ) { menuItemParser( parsedMenuItems, menuItem.menu_items ); } } }); return parsedMenuItems; }; const getPreviousAndNextMenuItems = ( menu, selectedSubMenuItem ) => { let previousMenuItem; let nextMenuItem; const parsedMenuItems = []; menuItemParser( parsedMenuItems, menu ); // Finds current menu item index const currentMenuItemIndex = parsedMenuItems.findIndex( ( menuItem ) => menuItem === selectedSubMenuItem ); if ( -1 !== currentMenuItemIndex ) { previousMenuItem = parsedMenuItems[ 0 === currentMenuItemIndex ? '' : currentMenuItemIndex - 1]; nextMenuItem = parsedMenuItems[ currentMenuItemIndex === parsedMenuItems.length - 1 ? '' : currentMenuItemIndex + 1]; previousMenuItem = previousMenuItem ? previousMenuItem : parsedMenuItems[0], nextMenuItem = nextMenuItem ? nextMenuItem : parsedMenuItems[parsedMenuItems.length - 1]; } return { nextMenuItem, previousMenuItem }; }; const dropEmptyMenuItems = ( menuItems, fields, selectedSubMenuItem ) => { const newMenuItems = menuItems; for ( const [ index, menuItem ] of menuItems.entries() ) { const menuItemFields = fields.filter( ( field ) => { return ( field.menu_id === menuItem.id && field.visible && ! field.conditionallyDisabled ); }); if ( 0 === menuItemFields.length && ! menuItem.hasOwnProperty( 'menu_items' ) ) { newMenuItems[index].visible = false; } else { newMenuItems[index].visible = true; if ( menuItem.hasOwnProperty( 'menu_items' ) ) { newMenuItems[index].menu_items = dropEmptyMenuItems( menuItem.menu_items, fields, selectedSubMenuItem ); } } } return newMenuItems; }; /* * filter sidebar menu from complete menu structure */ const getSubMenu = ( menu, selectedMainMenuItem ) => { let subMenu = []; for ( const key in menu ) { if ( menu.hasOwnProperty( key ) && menu[key].id === selectedMainMenuItem ) { subMenu = menu[key]; } } subMenu = addVisibleToMenuItems( subMenu ); return subMenu; }; /** * Get the current selected menu item based on the hash, selecting subitems if the main one is empty. */ const getSelectedSubMenuItem = ( subMenu, fields ) => { let fallBackMenuItem = subMenu && subMenu.menu_items.hasOwnProperty( 0 ) ? subMenu.menu_items[0].id : 'general'; let foundAnchorInMenu; //get flat array of menu items let parsedMenuItems = menuItemParser([], subMenu.menu_items ); let anchor = getAnchor( 'menu' ); //check if this anchor actually exists in our current submenu. If not, clear it foundAnchorInMenu = parsedMenuItems.filter( menu_item => menu_item === anchor ); if ( ! foundAnchorInMenu ) { anchor = false; } let selectedMenuItem = anchor ? anchor : fallBackMenuItem; //check if menu item has fields. If not, try a subitem let fieldsInMenu = fields.filter( field => field.menu_id === selectedMenuItem ); if ( 0 === fieldsInMenu.length ) { //look up the current menu item let menuItem = getMenuItemByName( selectedMenuItem, subMenu.menu_items ); if ( menuItem && menuItem.menu_items && menuItem.menu_items.hasOwnProperty( 0 ) ) { selectedMenuItem = menuItem.menu_items[0].id; } } return selectedMenuItem; }; //Get a menu item by name from the menu array const getMenuItemByName = ( name, menuItems ) => { for ( const key in menuItems ) { let menuItem = menuItems[key]; if ( menuItem.id === name ) { return menuItem; } if ( menuItem.menu_items ) { let found = getMenuItemByName( name, menuItem.menu_items ); if ( found ) { return found; } } } return false; }; export const useMenu = create( ( set, get ) => ({ menuLoaded: false, subMenuLoaded: false, menu: [], previousMenuItem: false, nextMenuItem: false, selectedMainMenuItem: false, selectedSubMenuItem: false, hasProItems: false, subMenu: [], setSelectedSidebarMenuItem: ( selectedSubMenuItem ) => set( state => ({ selectedSubMenuItem }) ), setSelectedMainMenuItem: ( selectedMainMenuItem ) => set( state => ({ selectedMainMenuItem }) ), //we need to get the main menu item directly from the anchor, otherwise we have to wait for the menu to load in page.js fetchSelectedMainMenuItem: () => { let selectedMainMenuItem = getAnchor( 'main' ) || 'dashboard'; set( ( state ) => ({selectedMainMenuItem: selectedMainMenuItem}) ); }, fetchSelectedSubMenuItem: async() => { let selectedSubMenuItem = getAnchor( 'menu' ) || 'general'; set( ( state ) => ({selectedSubMenuItem: selectedSubMenuItem}) ); }, fetchMainMenuData: async() => { let menu = get().menu; const menuLoaded = get().menuLoaded; //menu doesnt need to reload on next fetch menu = ! menuLoaded ? await fetchMenu() : menu; const selectedMainMenuItem = getAnchor( 'main' ) || 'dashboard'; set( ( state ) => ({menuLoaded: true, menu: menu, selectedMainMenuItem: selectedMainMenuItem}) ); }, fetchSubMenuData: async( fields ) => { let menu = get().menu; const menuLoaded = get().menuLoaded; //menu doesnt need to reload on next fetch menu = ! menuLoaded ? await fetchMenu() : menu; const selectedMainMenuItem = getAnchor( 'main' ) || 'dashboard'; let subMenu = getSubMenu( menu, selectedMainMenuItem ); const selectedSubMenuItem = getSelectedSubMenuItem( subMenu, fields ); const { nextMenuItem, previousMenuItem } = getPreviousAndNextMenuItems( menu, selectedSubMenuItem ); subMenu.menu_items = dropEmptyMenuItems( subMenu.menu_items, fields, selectedSubMenuItem ); const hasProItems = 0 < subMenu.menu_items.filter( ( item ) => { return ( true === item.pro ); }).length; set( ( state ) => ({subMenuLoaded: true, menuLoaded: true, menu: menu, nextMenuItem: nextMenuItem, previousMenuItem: previousMenuItem, selectedMainMenuItem: selectedMainMenuItem, selectedSubMenuItem: selectedSubMenuItem, subMenu: subMenu, hasProItems: hasProItems}) ); } }) ); const addVisibleToMenuItems = ( menu ) => { let newMenuItems = menu.menu_items; for ( let [ index, menuItem ] of menu.menu_items.entries() ) { menuItem.visible = true; if ( menuItem.hasOwnProperty( 'menu_items' ) ) { menuItem = addVisibleToMenuItems( menuItem ); } newMenuItems[index] = menuItem; } menu.menu_items = newMenuItems; menu.visible = true; return menu; };