feat: add my pages mobile dropdown cmoponent, parallel route, and consume + zustand store
This commit is contained in:
committed by
Michael Zetterberg
parent
f5d998d056
commit
cfb08fff2c
@@ -0,0 +1,10 @@
|
||||
import { logout } from "@/constants/routes/handleAuth"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
|
||||
export default async function MyPagesMobileDropdownPage() {
|
||||
// TODO: Figure out how to pass down props at the paralell route level.
|
||||
// - POssibly by parsing [...paths]
|
||||
return <MyPagesMobileDropdown lang={null} />
|
||||
}
|
||||
@@ -5,8 +5,15 @@ import { LangParams, PageArgs } from "@/types/params"
|
||||
export default function HeaderLayout({
|
||||
params,
|
||||
languageSwitcher,
|
||||
myPagesMobileDropdown,
|
||||
}: PageArgs<LangParams> & {
|
||||
languageSwitcher: React.ReactNode
|
||||
}) {
|
||||
return <Header lang={params.lang} languageSwitcher={languageSwitcher} />
|
||||
} & { myPagesMobileDropdown: React.ReactNode }) {
|
||||
return (
|
||||
<Header
|
||||
lang={params.lang}
|
||||
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||
languageSwitcher={languageSwitcher}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { baseUrls } from "@/constants/routes/baseUrls"
|
||||
|
||||
import Header from "@/components/Current/Header"
|
||||
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
@@ -9,6 +10,7 @@ export default async function HeaderPage({ params }: PageArgs<LangParams>) {
|
||||
return (
|
||||
<Header
|
||||
lang={params.lang}
|
||||
myPagesMobileDropdown={<MyPagesMobileDropdown lang={params.lang} />}
|
||||
languageSwitcher={<LanguageSwitcher urls={baseUrls} lang={params.lang} />}
|
||||
/>
|
||||
)
|
||||
|
||||
12
app/[lang]/(live-current)/@myPagesMobileDropdown/page.tsx
Normal file
12
app/[lang]/(live-current)/@myPagesMobileDropdown/page.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
|
||||
export default async function MyPagesMobileDropdownPage() {
|
||||
// TODO: Dirty way to get lang value. Figure out a proper way.
|
||||
const data = await serverClient().contentstack.languageSwitcher.get()
|
||||
if (!data) {
|
||||
return null
|
||||
}
|
||||
return <MyPagesMobileDropdown lang={data.lang} />
|
||||
}
|
||||
@@ -24,8 +24,11 @@ export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
languageSwitcher,
|
||||
myPagesMobileDropdown,
|
||||
}: React.PropsWithChildren<
|
||||
LayoutArgs<LangParams> & { languageSwitcher: React.ReactNode }
|
||||
LayoutArgs<LangParams> & { languageSwitcher: React.ReactNode } & {
|
||||
myPagesMobileDropdown: React.ReactNode
|
||||
}
|
||||
>) {
|
||||
const { defaultLocale, locale, messages } = await getIntl()
|
||||
return (
|
||||
@@ -82,7 +85,11 @@ export default async function RootLayout({
|
||||
<LangPopup lang={params.lang} />
|
||||
<SkipToMainContent />
|
||||
<ServerIntlProvider intl={{ defaultLocale, locale, messages }}>
|
||||
<Header lang={params.lang} languageSwitcher={languageSwitcher} />
|
||||
<Header
|
||||
lang={params.lang}
|
||||
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||
languageSwitcher={languageSwitcher}
|
||||
/>
|
||||
{children}
|
||||
<Footer lang={params.lang} />
|
||||
</ServerIntlProvider>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useIntl } from "react-intl"
|
||||
|
||||
import { login } from "@/constants/routes/handleAuth"
|
||||
import { myPages } from "@/constants/routes/myPages"
|
||||
import useDropdownStore from "@/stores/main-menu"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
@@ -21,16 +22,19 @@ export function MainMenu({
|
||||
logo,
|
||||
topMenuMobileLinks,
|
||||
languageSwitcher,
|
||||
myPagesMobileDropdown,
|
||||
bookingHref,
|
||||
isLoggedIn,
|
||||
lang,
|
||||
}: MainMenuProps) {
|
||||
const intl = useIntl()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
function toogleIsOpen() {
|
||||
setIsOpen((prevIsOpen) => !prevIsOpen)
|
||||
}
|
||||
const {
|
||||
isHamburgerMenuOpen,
|
||||
isMyPagesMobileMenuOpen,
|
||||
toggleHamburgerMenu,
|
||||
toggleMyPagesMobileMenu,
|
||||
} = useDropdownStore()
|
||||
|
||||
return (
|
||||
<div className={styles.mainMenu}>
|
||||
@@ -43,8 +47,8 @@ export function MainMenu({
|
||||
<nav className={styles.navBar}>
|
||||
<button
|
||||
aria-pressed="false"
|
||||
className={`${styles.expanderBtn} ${isOpen ? styles.expanded : ""}`}
|
||||
onClick={toogleIsOpen}
|
||||
className={`${styles.expanderBtn} ${isHamburgerMenuOpen ? styles.expanded : ""}`}
|
||||
onClick={toggleHamburgerMenu}
|
||||
type="button"
|
||||
>
|
||||
<span className={styles.iconBars}></span>
|
||||
@@ -66,7 +70,7 @@ export function MainMenu({
|
||||
</a>
|
||||
|
||||
<ul
|
||||
className={`${styles.listWrapper} ${isOpen ? styles.isOpen : ""}`}
|
||||
className={`${styles.listWrapper} ${isHamburgerMenuOpen ? styles.isOpen : ""}`}
|
||||
>
|
||||
<ul className={styles.linkRow}>
|
||||
{isLoggedIn ? (
|
||||
@@ -140,7 +144,17 @@ export function MainMenu({
|
||||
</ul>
|
||||
<div className={styles.buttonContainer}>
|
||||
<BookingButton href={bookingHref} />
|
||||
{/* {myPagesMobileDropdown ? ( */}
|
||||
{/* <div */}
|
||||
{/* role="button" */}
|
||||
{/* onClick={() => toggleMyPagesMobileMenu()} */}
|
||||
{/* className={styles.userAvatar} */}
|
||||
{/* > */}
|
||||
{/* <span className={styles.userAvatarInner}>CM</span> */}
|
||||
{/* </div> */}
|
||||
{/* ) : null} */}
|
||||
</div>
|
||||
{/* {isMyPagesMenuOpen ? myPagesMobileDropdown : null} */}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
69
components/Current/Header/MyPagesMobileDropdown/index.tsx
Normal file
69
components/Current/Header/MyPagesMobileDropdown/index.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Fragment } from "react"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { logout } from "@/constants/routes/handleAuth"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import styles from "./my-pages-mobile-dropdown.module.css"
|
||||
|
||||
export default async function MyPagesMobileDropdown({
|
||||
lang,
|
||||
}: {
|
||||
lang: Lang | null
|
||||
}) {
|
||||
const navigation = await serverClient().contentstack.myPages.navigation.get()
|
||||
if (!navigation) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<nav
|
||||
className={`${styles.navigationMenu} ${/*isMyPagesMenuOpen*/ true ? styles.navigationMenuIsOpen : ""}`}
|
||||
>
|
||||
<Title className={styles.heading} textTransform="capitalize" level="h5">
|
||||
{navigation.title}
|
||||
</Title>
|
||||
{navigation.menuItems.map((menuItem, idx) => (
|
||||
<Fragment key={`${menuItem.display_sign_out_link}-${idx}`}>
|
||||
{/*TODO: add pale color? */}
|
||||
<Divider color="peach" />
|
||||
<ul className={styles.dropdownWrapper}>
|
||||
<ul className={styles.dropdownLinks}>
|
||||
{menuItem.links.map((link) => (
|
||||
<li key={link.uid}>
|
||||
<Link
|
||||
href={link.originalUrl || link.url}
|
||||
partialMatch
|
||||
size={menuItem.display_sign_out_link ? "small" : "regular"}
|
||||
variant="myPage"
|
||||
color="burgundy"
|
||||
>
|
||||
{/*TODO: add myPageMobileMenu variant */}
|
||||
{link.linkText}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
{/* {menuItem.display_sign_out_link ? ( */}
|
||||
{/* <li> */}
|
||||
{/* <Link */}
|
||||
{/* color="burgundy" */}
|
||||
{/* href={logout[lang]} */}
|
||||
{/* prefetch={false} */}
|
||||
{/* size="small" */}
|
||||
{/* variant="sidebar" */}
|
||||
{/* > */}
|
||||
{/* {formatMessage({ id: "Log out" })} */}
|
||||
{/* </Link> */}
|
||||
{/* </li> */}
|
||||
{/* ) : null} */}
|
||||
</ul>
|
||||
</ul>
|
||||
</Fragment>
|
||||
))}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
.navigationMenu {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #e3e0db;
|
||||
display: none;
|
||||
list-style: none;
|
||||
overflow-y: visible;
|
||||
margin: 0;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
|
||||
.navigationMenu.navigationMenuIsOpen {
|
||||
display: block;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 100%;
|
||||
}
|
||||
|
||||
.dropdownWrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
background-color: var(--Main-Grey-White);
|
||||
box-shadow:
|
||||
0px 276px 77px 0px rgba(0, 0, 0, 0),
|
||||
0px 177px 71px 0px rgba(0, 0, 0, 0.01),
|
||||
0px 99px 60px 0px rgba(0, 0, 0, 0.05),
|
||||
0px 44px 44px 0px rgba(0, 0, 0, 0.09),
|
||||
0px 11px 24px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.heading {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.dropdownLinks {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x-half);
|
||||
width: 100%;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 950px) {
|
||||
.navigationMenu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigationMenu.navigationMenuIsOpen {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,10 @@ import { LangParams } from "@/types/params"
|
||||
export default async function Header({
|
||||
lang,
|
||||
languageSwitcher,
|
||||
}: LangParams & { languageSwitcher: React.ReactNode }) {
|
||||
myPagesMobileDropdown,
|
||||
}: LangParams & { languageSwitcher: React.ReactNode } & {
|
||||
myPagesMobileDropdown: React.ReactNode
|
||||
}) {
|
||||
const data = await serverClient().contentstack.base.header({
|
||||
lang,
|
||||
})
|
||||
@@ -49,6 +52,7 @@ export default async function Header({
|
||||
logo={logo}
|
||||
topMenuMobileLinks={topMenuMobileLinks}
|
||||
languageSwitcher={languageSwitcher}
|
||||
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||
bookingHref={homeHref}
|
||||
isLoggedIn={!!session}
|
||||
lang={lang}
|
||||
|
||||
31
stores/main-menu.ts
Normal file
31
stores/main-menu.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { create } from "zustand"
|
||||
|
||||
interface DropdownState {
|
||||
isHamburgerMenuOpen: boolean
|
||||
isMyPagesMobileMenuOpen: boolean
|
||||
toggleHamburgerMenu: () => void
|
||||
toggleMyPagesMobileMenu: () => void
|
||||
}
|
||||
|
||||
const useDropdownStore = create<DropdownState>((set) => ({
|
||||
isHamburgerMenuOpen: false,
|
||||
isMyPagesMobileMenuOpen: false,
|
||||
toggleHamburgerMenu: () =>
|
||||
set((state) => {
|
||||
// Close the other dropdown if it's open
|
||||
if (!state.isHamburgerMenuOpen && state.isMyPagesMobileMenuOpen) {
|
||||
set({ isMyPagesMobileMenuOpen: false })
|
||||
}
|
||||
return { isHamburgerMenuOpen: !state.isHamburgerMenuOpen }
|
||||
}),
|
||||
toggleMyPagesMobileMenu: () =>
|
||||
set((state) => {
|
||||
// Close the other dropdown if it's open
|
||||
if (!state.isMyPagesMobileMenuOpen && state.isHamburgerMenuOpen) {
|
||||
set({ isHamburgerMenuOpen: false })
|
||||
}
|
||||
return { isMyPagesMobileMenuOpen: !state.isMyPagesMobileMenuOpen }
|
||||
}),
|
||||
}))
|
||||
|
||||
export default useDropdownStore
|
||||
@@ -13,6 +13,7 @@ export type MainMenuProps = {
|
||||
logo: Image
|
||||
topMenuMobileLinks: TopMenuHeaderLink[]
|
||||
languageSwitcher: React.ReactNode | null
|
||||
myPagesMobileDropdown: React.ReactNode | null
|
||||
bookingHref: string
|
||||
isLoggedIn: boolean
|
||||
lang: Lang
|
||||
|
||||
Reference in New Issue
Block a user