Files
web/apps/scandic-web/components/Header/MainMenu/MobileMenu/index.tsx
Anton Gunnarsson 002d093af4 Merged in feat/sw-2863-move-contentstack-router-to-trpc-package (pull request #2389)
feat(SW-2863): Move contentstack router to trpc package

* Add exports to packages and lint rule to prevent relative imports

* Add env to trpc package

* Add eslint to trpc package

* Apply lint rules

* Use direct imports from trpc package

* Add lint-staged config to trpc

* Move lang enum to common

* Restructure trpc package folder structure

* WIP first step

* update internal imports in trpc

* Fix most errors in scandic-web

Just 100 left...

* Move Props type out of trpc

* Fix CategorizedFilters types

* Move more schemas in hotel router

* Fix deps

* fix getNonContentstackUrls

* Fix import error

* Fix entry error handling

* Fix generateMetadata metrics

* Fix alertType enum

* Fix duplicated types

* lint:fix

* Merge branch 'master' into feat/sw-2863-move-contentstack-router-to-trpc-package

* Fix broken imports

* Merge branch 'master' into feat/sw-2863-move-contentstack-router-to-trpc-package


Approved-by: Linus Flood
2025-06-26 07:53:01 +00:00

151 lines
4.3 KiB
TypeScript

"use client"
import { useEffect } from "react"
import { Dialog, Modal } from "react-aria-components"
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"
import {
findMyBooking,
findMyBookingCurrentWebPath,
} from "@scandic-hotels/common/constants/routes/findMyBooking"
import { customerService } from "@/constants/webHrefs"
import { env } from "@/env/client"
import useDropdownStore from "@/stores/main-menu"
import { IconName } from "@/components/Icons/iconName"
import LanguageSwitcher from "@/components/LanguageSwitcher"
import { useHandleKeyUp } from "@/hooks/useHandleKeyUp"
import { useIsLangLive } from "@/hooks/useIsLangLive"
import useLang from "@/hooks/useLang"
import { getCurrentWebUrl } from "@/utils/url"
import HeaderLink from "../../HeaderLink"
import TopLink from "../../TopLink"
import styles from "./mobileMenu.module.css"
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
import type { MobileMenuProps } from "@/types/components/header/mobileMenu"
export default function MobileMenu({
children,
topLink,
isLoggedIn,
}: React.PropsWithChildren<MobileMenuProps>) {
const isLangLive = useIsLangLive()
const lang = useLang()
const intl = useIntl()
const {
toggleDropdown,
isHamburgerMenuOpen,
isMyPagesMobileMenuOpen,
isHeaderLanguageSwitcherMobileOpen,
isFooterLanguageSwitcherOpen,
} = useDropdownStore()
const isHamburgerExtended =
isHamburgerMenuOpen ||
isMyPagesMobileMenuOpen ||
isHeaderLanguageSwitcherMobileOpen ||
isFooterLanguageSwitcherOpen
const isAboveMobile = useMediaQuery("(min-width: 768px)")
useEffect(() => {
if (isAboveMobile && isHamburgerMenuOpen) {
toggleDropdown(DropdownTypeEnum.HamburgerMenu)
}
}, [isAboveMobile, isHamburgerMenuOpen, toggleDropdown])
useHandleKeyUp((event: KeyboardEvent) => {
if (event.key === "Escape" && isHamburgerMenuOpen) {
toggleDropdown(DropdownTypeEnum.HamburgerMenu)
}
})
// Making sure the menu is always opened at the top of the page, just below the header.
useEffect(() => {
if (isHamburgerMenuOpen) {
window.scrollTo({ top: 0, behavior: "instant" })
}
}, [isHamburgerMenuOpen])
const closeMsg = intl.formatMessage({
defaultMessage: "Close menu",
})
const openMsg = intl.formatMessage({
defaultMessage: "Open menu",
})
const baseUrl = env.NEXT_PUBLIC_PUBLIC_URL || "https://www.scandichotels.com"
const findMyBookingUrl = !isLangLive
? getCurrentWebUrl({
path: findMyBookingCurrentWebPath[lang],
lang,
baseUrl,
})
: findMyBooking[lang]
return (
<>
<button
type="button"
className={`${styles.hamburger} ${isHamburgerExtended ? styles.isExpanded : ""}`}
aria-label={isHamburgerExtended ? closeMsg : openMsg}
onClick={() => toggleDropdown(DropdownTypeEnum.HamburgerMenu)}
>
<span className={styles.bar} />
</button>
<Modal className={styles.modal} isOpen={isHamburgerMenuOpen}>
<Dialog
className={styles.dialog}
aria-label={intl.formatMessage({
defaultMessage: "Menu",
})}
>
{children}
<footer className={styles.footer}>
<HeaderLink
href={findMyBookingUrl}
iconName={IconName.Search}
onClick={() => toggleDropdown(DropdownTypeEnum.HamburgerMenu)}
>
{intl.formatMessage({
defaultMessage: "Find booking",
})}
</HeaderLink>
<TopLink isLoggedIn={isLoggedIn} topLink={topLink} iconSize={20} />
<HeaderLink
href={customerService[lang]}
iconName={IconName.Service}
>
{intl.formatMessage({
defaultMessage: "Customer service",
})}
</HeaderLink>
<LanguageSwitcher type="mobileHeader" />
</footer>
</Dialog>
</Modal>
</>
)
}
export function MobileMenuSkeleton() {
const intl = useIntl()
return (
<button
type="button"
disabled
className={styles.hamburger}
aria-label={intl.formatMessage({
defaultMessage: "Open menu",
})}
>
<span className={styles.bar} />
</button>
)
}