From 706a1db18775385d7fe976cb9695fec83f477eae Mon Sep 17 00:00:00 2001 From: bicochan Date: Tue, 17 Jun 2025 14:00:35 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20LNB=20=EC=9E=91=EB=8F=99=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/components/src/ui/lnb/index.tsx | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/packages/common/components/src/ui/lnb/index.tsx b/packages/common/components/src/ui/lnb/index.tsx index 744ddcfd1..eac98faaa 100644 --- a/packages/common/components/src/ui/lnb/index.tsx +++ b/packages/common/components/src/ui/lnb/index.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect, useRef } from "react"; import { useQuery } from "@tanstack/react-query"; import { ChevronRight } from "lucide-react"; import { getConfig } from "@common/config"; @@ -38,12 +38,47 @@ export function LNB({ }); const [openMenuIds, setOpenMenuIds] = useState([]); + const userClosedMenusRef = useRef(new Set()); + const prevPathRef = useRef(currentPath); function isPathMatched(path: string) { if (!path) return false; return currentPath?.startsWith(path); } + useEffect(() => { + if (!menuList || !currentPath) return; + + const matchedMenuIds: number[] = []; + + const findMatchedMenus = (items: MenuItem[]) => { + items.forEach((item) => { + if (isPathMatched(item.urlPath)) { + const parentIds = getParentIds(item.menuCd)(menuList); + matchedMenuIds.push(...parentIds, item.menuCd); + } + + if (item.children) { + findMatchedMenus(item.children); + } + }); + }; + + findMatchedMenus(menuList); + + if (matchedMenuIds.length > 0) { + const filteredIds = matchedMenuIds.filter( + (id) => !userClosedMenusRef.current.has(id), + ); + setOpenMenuIds((prev) => [...new Set([...prev, ...filteredIds])]); + } + + if (prevPathRef.current !== currentPath) { + setOpenMenuIds(matchedMenuIds); + prevPathRef.current = currentPath; + } + }, [menuList, currentPath]); + function MenuItem({ item }: { item: MenuItem }) { const isMatched = isPathMatched(item.urlPath); @@ -74,20 +109,20 @@ export function LNB({ } function MenuGroup({ item }: { item: MenuItem }) { - const hasMatchedChild = item.children?.some((child) => - isPathMatched(child.urlPath), - ); - - const isOpen = openMenuIds.includes(item.menuCd) || hasMatchedChild; + const isOpen = openMenuIds.includes(item.menuCd); const handleOpenChange = (open: boolean) => { if (open) { + // 열 때는 부모들도 함께 열기 if (!openMenuIds.includes(item.menuCd)) { const parentIds = getParentIds(item.menuCd)(menuList ?? []); - setOpenMenuIds([...parentIds, item.menuCd]); + setOpenMenuIds((prev) => [...prev, ...parentIds, item.menuCd]); } + userClosedMenusRef.current.delete(item.menuCd); } else { + // 닫을 때는 현재 메뉴만 닫기 setOpenMenuIds((prev) => prev.filter((id) => id !== item.menuCd)); + userClosedMenusRef.current.add(item.menuCd); } };