188 lines
6.2 KiB
TypeScript
188 lines
6.2 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname, useRouter } from "next/navigation";
|
|
import { useEffect, useId, useMemo, useState } from "react";
|
|
import LoginModal from "@/components/LoginModal";
|
|
import { fetchAnonymousMenu, isMenuActive, type MenuItem } from "@/app/store/common";
|
|
|
|
const REGISTER_HREF = "/reuse/apply/place";
|
|
const LS_TOKEN_KEY = "reuse_accessToken";
|
|
const LS_USER_KEY = "reuse_userName";
|
|
|
|
const DEFAULT_NAV_ITEMS: Pick<MenuItem, "menuCd" | "menuKornNm" | "urlPath" | "newWndwYn">[] = [
|
|
{ menuCd: 1, menuKornNm: "Intro", urlPath: "/reuse/intro/law", newWndwYn: "N" },
|
|
{ menuCd: 2, menuKornNm: "Status", urlPath: "/reuse/cases/rain", newWndwYn: "N" },
|
|
{ menuCd: 3, menuKornNm: "Business", urlPath: "/reuse/business/rain/suwon", newWndwYn: "N" },
|
|
{ menuCd: 4, menuKornNm: "Demand", urlPath: "/reuse/apply/place", newWndwYn: "N" },
|
|
];
|
|
|
|
export default function TopNav() {
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
|
|
const [loginOpen, setLoginOpen] = useState(false);
|
|
const [userName, setUserName] = useState<string | null>(null);
|
|
const [topMenus, setTopMenus] = useState<MenuItem[]>([]);
|
|
|
|
useEffect(() => {
|
|
const name = localStorage.getItem(LS_USER_KEY);
|
|
setUserName(name);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
let isMounted = true;
|
|
|
|
(async () => {
|
|
try {
|
|
const loaded = await fetchAnonymousMenu();
|
|
if (!isMounted) return;
|
|
|
|
const level1 = loaded.filter((menu) => menu.levelNo === 1 || menu.parentId === null);
|
|
setTopMenus(level1);
|
|
} catch (error) {
|
|
console.error("Failed to load DN top menu", error);
|
|
if (!isMounted) return;
|
|
setTopMenus([]);
|
|
}
|
|
})();
|
|
|
|
return () => {
|
|
isMounted = false;
|
|
};
|
|
}, []);
|
|
|
|
const navItems = useMemo(() => {
|
|
if (topMenus.length > 0) return topMenus;
|
|
|
|
return DEFAULT_NAV_ITEMS.map((item) => ({
|
|
...item,
|
|
parentId: null,
|
|
sortSeq: 0,
|
|
children: [],
|
|
levelNo: 1,
|
|
useYn: "Y",
|
|
otptYn: "Y",
|
|
}));
|
|
}, [topMenus]);
|
|
|
|
const openLogin = () => setLoginOpen(true);
|
|
|
|
const logout = () => {
|
|
localStorage.removeItem(LS_TOKEN_KEY);
|
|
localStorage.removeItem(LS_USER_KEY);
|
|
setUserName(null);
|
|
router.refresh();
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<header className="fixed left-0 right-0 top-0 z-50 border-b bg-white shadow-md backdrop-blur">
|
|
<div className="px-6">
|
|
<div className="relative flex h-[83px] items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<Link href="/main" className="flex items-center">
|
|
<img src="/images/landing/logo.png" alt="HASUON" className="h-9 w-auto" />
|
|
</Link>
|
|
</div>
|
|
|
|
<nav className="absolute left-1/2 flex -translate-x-1/2 items-center gap-[40px] text-sm font-medium">
|
|
{navItems.map((item) => {
|
|
const requiresLogin = (item.urlPath)? item.urlPath.startsWith("/reuse/apply") : false;
|
|
const active = isMenuActive(pathname, item);
|
|
const className = [
|
|
"relative px-3 py-2 text-lg font-bold",
|
|
active ? "text-sky-700" : "text-gray-800 hover:text-sky-700",
|
|
].join(" ");
|
|
|
|
if (requiresLogin && !userName) {
|
|
return (
|
|
<button
|
|
key={item.menuCd}
|
|
type="button"
|
|
onClick={openLogin}
|
|
className={className}
|
|
>
|
|
{item.menuKornNm}
|
|
</button>
|
|
);
|
|
}
|
|
|
|
if (item.newWndwYn === "Y") {
|
|
return (
|
|
<button
|
|
key={item.menuCd}
|
|
type="button"
|
|
onClick={() => window.open(item.urlPath, "_blank")}
|
|
className={className}
|
|
>
|
|
{item.menuKornNm}
|
|
</button>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Link key={item.menuCd} href={item.urlPath || "#"} className={className}>
|
|
{item.menuKornNm}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
<div className="flex items-center gap-3">
|
|
{!userName ? (
|
|
<button
|
|
type="button"
|
|
onClick={openLogin}
|
|
className="inline-flex items-center gap-2 rounded-md bg-sky-500 px-4 py-2 text-base text-white hover:bg-sky-600"
|
|
>
|
|
Login
|
|
<span aria-hidden>
|
|
<img
|
|
src="/images/landing/icon_login.png"
|
|
alt="login icon"
|
|
className="ml-1 h-6 w-6 object-contain"
|
|
/>
|
|
</span>
|
|
</button>
|
|
) : (
|
|
<>
|
|
<span className="text-base text-gray-700">
|
|
<strong className="text-xl text-emerald-600">{userName}</strong>
|
|
</span>
|
|
<button
|
|
type="button"
|
|
onClick={logout}
|
|
className="inline-flex items-center gap-2 rounded-md bg-red-500 px-4 py-2 text-base text-white hover:bg-red-600"
|
|
>
|
|
Logout
|
|
<span aria-hidden>
|
|
<img
|
|
src="/images/landing/icon_logout.png"
|
|
alt="logout icon"
|
|
className="h-6 w-6 object-contain"
|
|
/>
|
|
</span>
|
|
</button>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<LoginModal
|
|
open={loginOpen}
|
|
onClose={() => setLoginOpen(false)}
|
|
onSuccess={({ userName: nextUserName, accessToken }) => {
|
|
localStorage.setItem(LS_USER_KEY, nextUserName);
|
|
if (accessToken) localStorage.setItem(LS_TOKEN_KEY, accessToken);
|
|
setUserName(nextUserName);
|
|
setLoginOpen(false);
|
|
router.refresh();
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
}
|