import {create} from 'zustand';
import getAnchor from "../utils/getAnchor";
const useMenu = create(( set, get ) => ({
menu: [],
subMenuLoaded:false,
previousMenuItem:false,
nextMenuItem:false,
selectedMainMenuItem:false,
selectedSubMenuItem:false,
selectedFilter: false,
activeGroupId: false,
hasPremiumItems:false,
subMenu:{title:' ',menu_items:[]},
setSelectedSubMenuItem: async (selectedSubMenuItem) => {
let selectedMainMenuItem = getMainMenuForSubMenu(selectedSubMenuItem);
set(state => ({ selectedSubMenuItem,selectedMainMenuItem }))
// window.location.href=rsssl_settings.dashboard_url+'#'+selectedMainMenuItem+'/'+selectedSubMenuItem;
window.location.hash = selectedMainMenuItem+'/'+selectedSubMenuItem;
},
setSelectedMainMenuItem: (selectedMainMenuItem) => {
set(state => ({ selectedMainMenuItem }))
// window.location.href=rsssl_settings.dashboard_url+'#'+selectedMainMenuItem;
window.location.hash = 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}));
},
fetchMenuData: (fields) => {
let menu = rsssl_settings.menu;
menu = Object.values(menu);
const selectedMainMenuItem = getAnchor('main') || 'dashboard';
menu = menu.filter( item => !item.default_hidden || selectedMainMenuItem===item.id);
if ( typeof fields !== 'undefined' ) {
let subMenu = getSubMenu(menu, selectedMainMenuItem);
const selectedSubMenuItem = getSelectedSubMenuItem(subMenu, fields);
subMenu.menu_items = dropEmptyMenuItems(subMenu.menu_items, fields, selectedSubMenuItem);
const { nextMenuItem, previousMenuItem } = getPreviousAndNextMenuItems(menu, selectedSubMenuItem, fields);
const hasPremiumItems = subMenu.menu_items.filter((item) => {return (item.premium===true)}).length>0;
set((state) => ({subMenuLoaded:true, menu: menu, nextMenuItem:nextMenuItem, previousMenuItem:previousMenuItem, selectedMainMenuItem: selectedMainMenuItem, selectedSubMenuItem:selectedSubMenuItem, subMenu: subMenu, hasPremiumItems: hasPremiumItems}));
} else {
set((state) => ({menu: menu, selectedMainMenuItem: selectedMainMenuItem}));
}
},
getDefaultSubMenuItem: async (fields) => {
let subMenuLoaded = get().subMenuLoaded;
if (!subMenuLoaded){
await get().fetchMenuData(fields);
}
let subMenu = get().subMenu;
let fallBackMenuItem = subMenuLoaded && subMenu.hasOwnProperty(0) ? subMenu[0].id : 'general';
let anchor = getAnchor('menu');
let foundAnchorInMenu = false;
//check if this anchor actually exists in our current submenu. If not, clear it
for (const key in this.menu.menu_items) {
if ( subMenu.hasOwnProperty(key) && subMenu[key].id === anchor ){
foundAnchorInMenu=true;
}
}
if ( !foundAnchorInMenu ) anchor = false;
return anchor ? anchor : fallBackMenuItem;
}
}));
export default useMenu;
// Parses menu items and nested items in single array
const menuItemParser = (parsedMenuItems, menuItems, fields) => {
menuItems.forEach((menuItem) => {
if( menuItem.visible ) {
parsedMenuItems.push(menuItem.id);
if( menuItem.hasOwnProperty('menu_items') ) {
menuItem.menu_items = dropEmptyMenuItems(menuItem.menu_items, fields );
menuItemParser(parsedMenuItems, menuItem.menu_items, fields);
}
}
});
return parsedMenuItems;
}
const getPreviousAndNextMenuItems = (menu, selectedSubMenuItem, fields) => {
let previousMenuItem;
let nextMenuItem;
const parsedMenuItems = [];
menuItemParser(parsedMenuItems, menu, fields);
// Finds current menu item index
const currentMenuItemIndex = parsedMenuItems.findIndex((menuItem) => menuItem === selectedSubMenuItem);
if( currentMenuItemIndex !== -1 ) {
previousMenuItem = parsedMenuItems[ currentMenuItemIndex === 0 ? '' : currentMenuItemIndex - 1];
//if the previous menu item has a submenu, we should move one more back, because it will select the current sub otherwise.
const previousMenuHasSubMenu = getMenuItemByName(previousMenuItem, menu).hasOwnProperty('menu_items');
if (previousMenuHasSubMenu) {
previousMenuItem = parsedMenuItems[ currentMenuItemIndex === 0 ? '' : currentMenuItemIndex - 2]
}
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) => {
if (!Array.isArray(fields)) {
return menuItems; // return the original menuItems unchanged
}
const newMenuItems = menuItems;
for (const [index, menuItem] of menuItems.entries()) {
let menuItemFields = fields.filter((field) => {
return (field.menu_id === menuItem.id )
});
menuItemFields = menuItemFields.filter((field) => {
return ( field.visible )
});
if ( menuItemFields.length === 0 && !menuItem.hasOwnProperty('menu_items') ) {
if (typeof newMenuItems[index] === 'object' && newMenuItems[index] !== null) {
newMenuItems[index].visible = false;
}
} else {
if (typeof newMenuItems[index] === 'object' && newMenuItems[index] !== null) {
newMenuItems[index].visible = true;
}
if( menuItem.hasOwnProperty('menu_items') ) {
newMenuItems[index].menu_items = dropEmptyMenuItems(menuItem.menu_items, fields);
}
}
}
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 main menu item for a submenu item
*/
const getMainMenuForSubMenu = (findMenuItem) => {
let menu = rsssl_settings.menu;
for (const mainKey in menu) {
let mainMenuItem = menu[mainKey];
if (mainMenuItem.id===findMenuItem) {
return mainMenuItem.id;
}
if (mainMenuItem.menu_items){
for (const subKey in mainMenuItem.menu_items) {
let subMenuItem = mainMenuItem.menu_items[subKey];
if (subMenuItem.id===findMenuItem) {
return mainMenuItem.id;
}
if (subMenuItem.menu_items){
for (const sub2Key in subMenuItem.menu_items) {
let sub2MenuItem = subMenuItem.menu_items[sub2Key];
if (sub2MenuItem.id===findMenuItem) {
return mainMenuItem.id;
}
}
}
}
}
}
return false;
}
/**
* 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 ( fieldsInMenu.length===0 ) {
//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;
}
const addVisibleToMenuItems = (menu) => {
let newMenuItems = Array.isArray(menu.menu_items) ? menu.menu_items : Object.values(menu.menu_items);
for (let [index, menuItem] of newMenuItems.entries()) {
if (typeof menuItem === 'object' && menuItem !== null) {
menuItem.visible = true;
if (menuItem.hasOwnProperty('menu_items')) {
menuItem = addVisibleToMenuItems(menuItem);
}
newMenuItems[index] = menuItem;
}
}
menu.menu_items = newMenuItems;
menu.visible = true;
return menu;
}