feat: add my pages mobile dropdown cmoponent, parallel route, and consume + zustand store

This commit is contained in:
Chuma McPhoy
2024-06-19 07:57:26 +02:00
committed by Michael Zetterberg
parent f5d998d056
commit cfb08fff2c
11 changed files with 224 additions and 12 deletions

View File

@@ -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} />
}

View File

@@ -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}
/>
)
}

View File

@@ -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} />}
/>
)

View 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} />
}

View File

@@ -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>

View File

@@ -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>

View 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>
)
}

View File

@@ -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;
}
}

View File

@@ -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
View 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

View File

@@ -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