church-website/src/components/Menu/Menu.tsx
2026-03-09 11:16:32 +01:00

191 lines
5.5 KiB
TypeScript

'use client'
import styles from './styles.module.scss'
import MenuIcon from './menu.svg'
import Image from 'next/image'
import classNames from 'classnames'
import { MegaMenuItemProps, Menu as MenuType, MenuItem as MenuItemType, SimpleItemProps } from './menu.types'
import { Logo } from '@/components/Logo/Logo'
import { Fragment, useCallback, useState } from 'react'
import { MegaMenu } from '@/components/MegaMenu/MegaMenu'
import { CollapsibleArrow } from '@/components/CollapsibleArrow/CollapsibleArrow'
import Link from 'next/link'
/**
* Represents a simple item component.
*
* @param {Object} SimpleItemProps - The properties for the SimpleItem component.
* @param {string} SimpleItemProps.text - The text to display for the item.
* @param {string} SimpleItemProps.href - The URL to navigate to when the item is clicked.
* @param {string} SimpleItemProps.type - The type of the item ("default" or "button").
* @param {function} SimpleItemProps.onItemClick - The function to call when the item is clicked.
* @returns {JSX.Element} A Link component with the specified text, href, type, and onItemClick function.
*/
const SimpleItem = ({text, href, type, onItemClick}: SimpleItemProps) => {
const className = classNames({
[styles.menuLink]: type === "default",
[styles.button]: type === "button"
});
return (
<span>
<Link
className={className}
href={href}
onClick={onItemClick}
>
{text}
</Link>
</span>
)
}
/**
* Represents a mega menu item component.
* @param {Object} MegaMenuItemProps - The props for the MegaMenuItem component.
* @param {string} MegaMenuItemProps.text - The text to display in the menu item.
* @param {string} MegaMenuItemProps.quote - The quote to display in the mega menu.
* @param {string} MegaMenuItemProps.source - The source of the quote.
* @param {Array<string>} MegaMenuItemProps.groups - The groups associated with the menu item.
* @param {Function} MegaMenuItemProps.onItemClick - The function to handle item click event.
* @returns {JSX.Element} A JSX element representing the MegaMenuItem component.
*/
const MegaMenuItem = ({text, quote, source, groups, onItemClick}: MegaMenuItemProps) => {
const [isActive, setIsActive] = useState<boolean>(false);
const itemClicked = useCallback(() => {
setIsActive(false);
if (onItemClick) {
onItemClick();
}
}, [setIsActive, onItemClick]);
return (
<span
onMouseEnter={() => setIsActive(true)}
onMouseLeave={() => setIsActive(false)}
>
<Link
href={""}
className={styles.menuLink}
>
{text} <CollapsibleArrow direction={isActive ? "UP" : "DOWN"} stroke={1.5} />
</Link>
<div
className={classNames({
[styles.megaMenu]: true,
[styles.megaMenuActive]: isActive
})}
>
<MegaMenu
bibleText={quote}
bibleBook={source}
groups={groups}
onItemClick={itemClicked}
/>
</div>
</span>
)
}
type MenuItemsProps = {
items: MenuItemType[]
onItemClick: () => void
}
/**
* Renders a list of menu items based on the provided props.
*
* @param {Object} items - An array of menu items to render.
* @param {Function} onItemClick - Callback function to handle item click events.
*/
const MenuItems = ({items, onItemClick}: MenuItemsProps) => {
return (
<>
{items.map(item => (
<Fragment key={item.id}>
{ item.blockType === "simple-item" &&
<SimpleItem
text={item.text}
href={item.href}
type={item.type}
blockType={item.blockType}
onItemClick={onItemClick}
/>
}
{
item.blockType === "mega-menu" &&
<MegaMenuItem
text={item.text}
quote={item.quote}
source={item.source}
blockType={item.blockType}
groups={item.groups}
onItemClick={onItemClick}
/>
}
</Fragment>
)
)}
</>
)
}
type MenuProps = {
menu: MenuType
}
/**
* Represents a menu component that displays navigation items on the screen.
* @param {Object} MenuProps - The props object containing menu items for left and right side of the menu.
* @returns The rendered menu component.
*/
export const Menu = ({menu}: MenuProps) => {
const [displayMenuMobile, setDisplayMenuMobile] = useState(false)
return (
<>
<nav className={classNames(styles.nav, {[styles.full]: displayMenuMobile})}>
<div className={styles.navMobile}>
<Link
href={"/"} onClick={() => setDisplayMenuMobile(false)}
className={styles.logoLink}
>
<Logo withText={false} height={30} color={"#426156"}/>
</Link>
<Image
src={MenuIcon}
width={25}
height={25}
alt={'Menu'}
onClick={() => setDisplayMenuMobile(!displayMenuMobile)}
/>
</div>
<div className={classNames(styles.itemsLeft, {[styles.hide]: !displayMenuMobile})}>
<MenuItems
items={menu.leftItems}
onItemClick={() => setDisplayMenuMobile(false)}
/>
</div>
<div className={classNames(styles.itemsRight, {[styles.hide]: !displayMenuMobile})}>
<MenuItems
items={menu.rightItems}
onItemClick={() => setDisplayMenuMobile(false)}
/>
</div>
</nav>
</>
)
}