173 lines
6.6 KiB
TypeScript
173 lines
6.6 KiB
TypeScript
'use client';
|
|
import { FC, useState, useEffect } from "react";
|
|
import { MenuProps } from "@/validations/mutual/dashboard/props";
|
|
import { langGetKey } from "@/lib/langGet";
|
|
import { parseURlFormString } from "@/lib/menuGet";
|
|
import FirstLayerDropdown from "./firstLayerComponent";
|
|
import SecondLayerDropdown from "./secondLayerComponent";
|
|
import ThirdLayerDropdown from "./thirdLayerComponent";
|
|
|
|
// Define types for menu structure
|
|
type ThirdLayerItem = Record<string, any>;
|
|
type SecondLayerItems = Record<string, ThirdLayerItem>;
|
|
type FirstLayerItems = Record<string, SecondLayerItems>;
|
|
type MenuStructure = FirstLayerItems;
|
|
|
|
const MenuComponent: FC<MenuProps> = ({ lang, menuItems, menuTranslationsFlatten, activePageUrl }) => {
|
|
// State for tracking expanded menu items
|
|
const [expandedFirstLayer, setExpandedFirstLayer] = useState<string | null>(null);
|
|
const [expandedSecondLayer, setExpandedSecondLayer] = useState<string | null>(null);
|
|
const [menuStructure, setMenuStructure] = useState<MenuStructure>({});
|
|
|
|
// Parse active URL to determine which menu items should be active
|
|
const activePathLayers = parseURlFormString(activePageUrl).data;
|
|
const activeFirstLayer = activePathLayers[0] || null;
|
|
const activeSecondLayer = activePathLayers[1] || null;
|
|
const activeThirdLayer = activePathLayers[2] || null;
|
|
|
|
// Initialize expanded state based on active path
|
|
useEffect(() => {
|
|
if (activeFirstLayer) {
|
|
setExpandedFirstLayer(activeFirstLayer);
|
|
if (activeSecondLayer) {
|
|
setExpandedSecondLayer(activeSecondLayer);
|
|
}
|
|
}
|
|
}, [activeFirstLayer, activeSecondLayer]);
|
|
|
|
// Process menu items into a hierarchical structure
|
|
useEffect(() => {
|
|
const processedStructure: MenuStructure = {};
|
|
|
|
Object.entries(menuItems).forEach(([path, _]: [string, any]) => {
|
|
const layers = parseURlFormString(path).data;
|
|
const firstLayer = layers[0];
|
|
const secondLayer = layers[1];
|
|
const thirdLayer = layers[2];
|
|
|
|
// Create first layer if it doesn't exist
|
|
if (!processedStructure[firstLayer]) {
|
|
processedStructure[firstLayer] = {};
|
|
}
|
|
|
|
// Create second layer if it doesn't exist
|
|
if (!processedStructure[firstLayer][secondLayer]) {
|
|
processedStructure[firstLayer][secondLayer] = {};
|
|
}
|
|
|
|
// Add third layer
|
|
processedStructure[firstLayer][secondLayer][thirdLayer] = {};
|
|
});
|
|
|
|
setMenuStructure(processedStructure);
|
|
}, [menuItems]);
|
|
|
|
// Handle click on first layer menu item
|
|
const handleFirstLayerClick = (key: string) => {
|
|
if (expandedFirstLayer === key) {
|
|
// If already expanded, collapse it
|
|
setExpandedFirstLayer(null);
|
|
setExpandedSecondLayer(null);
|
|
} else {
|
|
// Otherwise expand it
|
|
setExpandedFirstLayer(key);
|
|
setExpandedSecondLayer(null);
|
|
}
|
|
};
|
|
|
|
// Handle click on second layer menu item
|
|
const handleSecondLayerClick = (key: string) => {
|
|
if (expandedSecondLayer === key) {
|
|
// If already expanded, collapse it
|
|
setExpandedSecondLayer(null);
|
|
} else {
|
|
// Otherwise expand it
|
|
setExpandedSecondLayer(key);
|
|
}
|
|
};
|
|
|
|
// Render third layer menu items
|
|
const renderThirdLayerItems = (firstLayerKey: string, secondLayerKey: string, thirdLayerItems: ThirdLayerItem) => {
|
|
const baseUrl = `/${firstLayerKey}/${secondLayerKey}`;
|
|
|
|
return Object.keys(thirdLayerItems).map(thirdLayerKey => {
|
|
const isActive =
|
|
activeFirstLayer === firstLayerKey &&
|
|
activeSecondLayer === secondLayerKey &&
|
|
activeThirdLayer === thirdLayerKey;
|
|
|
|
const url = `/${lang}${baseUrl}/${thirdLayerKey}`;
|
|
|
|
return (
|
|
<div key={`${thirdLayerKey}-item`} className="ml-2 my-1">
|
|
<ThirdLayerDropdown
|
|
isActive={isActive}
|
|
innerText={langGetKey(menuTranslationsFlatten, thirdLayerKey)}
|
|
url={url}
|
|
/>
|
|
</div>
|
|
);
|
|
});
|
|
};
|
|
|
|
// Render second layer menu items
|
|
const renderSecondLayerItems = (firstLayerKey: string, secondLayerItems: SecondLayerItems) => {
|
|
return Object.entries(secondLayerItems).map(([secondLayerKey, thirdLayerItems]) => {
|
|
const isActive = activeFirstLayer === firstLayerKey && activeSecondLayer === secondLayerKey;
|
|
const isExpanded = expandedSecondLayer === secondLayerKey;
|
|
|
|
return (
|
|
<div key={`${secondLayerKey}-item`} className="ml-2 my-1">
|
|
<SecondLayerDropdown
|
|
isActive={isActive}
|
|
isExpanded={isExpanded}
|
|
innerText={langGetKey(menuTranslationsFlatten, secondLayerKey)}
|
|
onClick={() => handleSecondLayerClick(secondLayerKey)}
|
|
/>
|
|
{isExpanded && (
|
|
<div className="ml-2 mt-1">
|
|
{renderThirdLayerItems(firstLayerKey, secondLayerKey, thirdLayerItems)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
});
|
|
};
|
|
|
|
// Render first layer menu items
|
|
const renderFirstLayerItems = () => {
|
|
return Object.entries(menuStructure).map(([firstLayerKey, secondLayerItems]) => {
|
|
const isActive = activeFirstLayer === firstLayerKey;
|
|
const isExpanded = expandedFirstLayer === firstLayerKey;
|
|
|
|
return (
|
|
<div key={`${firstLayerKey}-item`} className="mb-2">
|
|
<FirstLayerDropdown
|
|
isActive={isActive}
|
|
isExpanded={isExpanded}
|
|
innerText={langGetKey(menuTranslationsFlatten, firstLayerKey)}
|
|
onClick={() => handleFirstLayerClick(firstLayerKey)}
|
|
/>
|
|
{isExpanded && (
|
|
<div className="mt-1">
|
|
{renderSecondLayerItems(firstLayerKey, secondLayerItems)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="fixed top-24 p-5 left-0 right-0 w-80 border-emerald-150 border-r-2 overflow-y-auto h-[calc(100vh-6rem)]">
|
|
<div className="flex flex-col">
|
|
{renderFirstLayerItems()}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
|
|
|
|
export default MenuComponent;
|