/** * @file app/components/layout/MobileLegalMenu.tsx * @description Client component providing a mobile toggle menu for accessing legal links and copyright information in a slide-up overlay. */ "use client"; import { useState, useRef, useEffect } from "react"; import Link from "next/link"; import { MoreHorizontal, X } from "lucide-react"; import { LEGAL_LINKS, COPYRIGHT_TEXT, ICON_MAP } from "@/lib/utils/legal"; import SignOutButton from "@/app/components/ui/buttons/SignOutButton"; /** * Renders a mobile menu button and a slide-up modal overlay containing * links to legal documentation and copyright details. * * @returns {JSX.Element} The rendered mobile legal menu component. */ export default function MobileLegalMenu() { const [isOpen, setIsOpen] = useState(false); const currentYear = new Date().getFullYear(); const menuRef = useRef(null); const buttonRef = useRef(null); useEffect(() => { if (!isOpen) return; /** * Closes the menu overlay when a click or touch event occurs outside the menu or trigger button. * * @param {MouseEvent | TouchEvent} event - The pointer or touch event object. */ const handleClickOutside = (event: MouseEvent | TouchEvent) => { const target = event.target as Node; if ( menuRef.current && !menuRef.current.contains(target) && buttonRef.current && !buttonRef.current.contains(target) ) { setIsOpen(false); } }; /** * Closes the menu overlay when the Escape key is pressed. * * @param {KeyboardEvent} event - The keyboard event object. */ const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") { setIsOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); document.addEventListener("touchstart", handleClickOutside); document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("touchstart", handleClickOutside); document.removeEventListener("keydown", handleKeyDown); }; }, [isOpen]); return ( <> {/* "More" Button */} {/* Slide-Up Overlay */} {isOpen && ( <> {/* Backdrop Overlay */}
setIsOpen(false)} /> {/* MenĂ¼-Card */}
{/* Header */}
Legal & Info
{/* Shared Links */}
{LEGAL_LINKS.map((link) => { const IconComponent = ICON_MAP[link.iconName]; return ( setIsOpen(false)} className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-foreground-muted hover:text-foreground hover:bg-foreground/5 transition-colors cursor-pointer" > {link.name} ); })} {/* Sign Out Button */}
{/* Shared Copyright */}

{COPYRIGHT_TEXT(currentYear)}

)} ); }