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({
|
export default function HeaderLayout({
|
||||||
params,
|
params,
|
||||||
languageSwitcher,
|
languageSwitcher,
|
||||||
|
myPagesMobileDropdown,
|
||||||
}: PageArgs<LangParams> & {
|
}: PageArgs<LangParams> & {
|
||||||
languageSwitcher: React.ReactNode
|
languageSwitcher: React.ReactNode
|
||||||
}) {
|
} & { myPagesMobileDropdown: React.ReactNode }) {
|
||||||
return <Header lang={params.lang} languageSwitcher={languageSwitcher} />
|
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 Header from "@/components/Current/Header"
|
||||||
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
||||||
|
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||||
|
|
||||||
import { LangParams, PageArgs } from "@/types/params"
|
import { LangParams, PageArgs } from "@/types/params"
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ export default async function HeaderPage({ params }: PageArgs<LangParams>) {
|
|||||||
return (
|
return (
|
||||||
<Header
|
<Header
|
||||||
lang={params.lang}
|
lang={params.lang}
|
||||||
|
myPagesMobileDropdown={<MyPagesMobileDropdown lang={params.lang} />}
|
||||||
languageSwitcher={<LanguageSwitcher urls={baseUrls} 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,
|
children,
|
||||||
params,
|
params,
|
||||||
languageSwitcher,
|
languageSwitcher,
|
||||||
|
myPagesMobileDropdown,
|
||||||
}: React.PropsWithChildren<
|
}: React.PropsWithChildren<
|
||||||
LayoutArgs<LangParams> & { languageSwitcher: React.ReactNode }
|
LayoutArgs<LangParams> & { languageSwitcher: React.ReactNode } & {
|
||||||
|
myPagesMobileDropdown: React.ReactNode
|
||||||
|
}
|
||||||
>) {
|
>) {
|
||||||
const { defaultLocale, locale, messages } = await getIntl()
|
const { defaultLocale, locale, messages } = await getIntl()
|
||||||
return (
|
return (
|
||||||
@@ -82,7 +85,11 @@ export default async function RootLayout({
|
|||||||
<LangPopup lang={params.lang} />
|
<LangPopup lang={params.lang} />
|
||||||
<SkipToMainContent />
|
<SkipToMainContent />
|
||||||
<ServerIntlProvider intl={{ defaultLocale, locale, messages }}>
|
<ServerIntlProvider intl={{ defaultLocale, locale, messages }}>
|
||||||
<Header lang={params.lang} languageSwitcher={languageSwitcher} />
|
<Header
|
||||||
|
lang={params.lang}
|
||||||
|
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||||
|
languageSwitcher={languageSwitcher}
|
||||||
|
/>
|
||||||
{children}
|
{children}
|
||||||
<Footer lang={params.lang} />
|
<Footer lang={params.lang} />
|
||||||
</ServerIntlProvider>
|
</ServerIntlProvider>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useIntl } from "react-intl"
|
|||||||
|
|
||||||
import { login } from "@/constants/routes/handleAuth"
|
import { login } from "@/constants/routes/handleAuth"
|
||||||
import { myPages } from "@/constants/routes/myPages"
|
import { myPages } from "@/constants/routes/myPages"
|
||||||
|
import useDropdownStore from "@/stores/main-menu"
|
||||||
|
|
||||||
import Image from "@/components/Image"
|
import Image from "@/components/Image"
|
||||||
import Link from "@/components/TempDesignSystem/Link"
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
@@ -21,16 +22,19 @@ export function MainMenu({
|
|||||||
logo,
|
logo,
|
||||||
topMenuMobileLinks,
|
topMenuMobileLinks,
|
||||||
languageSwitcher,
|
languageSwitcher,
|
||||||
|
myPagesMobileDropdown,
|
||||||
bookingHref,
|
bookingHref,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
lang,
|
lang,
|
||||||
}: MainMenuProps) {
|
}: MainMenuProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const [isOpen, setIsOpen] = useState(false)
|
|
||||||
|
|
||||||
function toogleIsOpen() {
|
const {
|
||||||
setIsOpen((prevIsOpen) => !prevIsOpen)
|
isHamburgerMenuOpen,
|
||||||
}
|
isMyPagesMobileMenuOpen,
|
||||||
|
toggleHamburgerMenu,
|
||||||
|
toggleMyPagesMobileMenu,
|
||||||
|
} = useDropdownStore()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.mainMenu}>
|
<div className={styles.mainMenu}>
|
||||||
@@ -43,8 +47,8 @@ export function MainMenu({
|
|||||||
<nav className={styles.navBar}>
|
<nav className={styles.navBar}>
|
||||||
<button
|
<button
|
||||||
aria-pressed="false"
|
aria-pressed="false"
|
||||||
className={`${styles.expanderBtn} ${isOpen ? styles.expanded : ""}`}
|
className={`${styles.expanderBtn} ${isHamburgerMenuOpen ? styles.expanded : ""}`}
|
||||||
onClick={toogleIsOpen}
|
onClick={toggleHamburgerMenu}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span className={styles.iconBars}></span>
|
<span className={styles.iconBars}></span>
|
||||||
@@ -66,7 +70,7 @@ export function MainMenu({
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<ul
|
<ul
|
||||||
className={`${styles.listWrapper} ${isOpen ? styles.isOpen : ""}`}
|
className={`${styles.listWrapper} ${isHamburgerMenuOpen ? styles.isOpen : ""}`}
|
||||||
>
|
>
|
||||||
<ul className={styles.linkRow}>
|
<ul className={styles.linkRow}>
|
||||||
{isLoggedIn ? (
|
{isLoggedIn ? (
|
||||||
@@ -140,7 +144,17 @@ export function MainMenu({
|
|||||||
</ul>
|
</ul>
|
||||||
<div className={styles.buttonContainer}>
|
<div className={styles.buttonContainer}>
|
||||||
<BookingButton href={bookingHref} />
|
<BookingButton href={bookingHref} />
|
||||||
|
{/* {myPagesMobileDropdown ? ( */}
|
||||||
|
{/* <div */}
|
||||||
|
{/* role="button" */}
|
||||||
|
{/* onClick={() => toggleMyPagesMobileMenu()} */}
|
||||||
|
{/* className={styles.userAvatar} */}
|
||||||
|
{/* > */}
|
||||||
|
{/* <span className={styles.userAvatarInner}>CM</span> */}
|
||||||
|
{/* </div> */}
|
||||||
|
{/* ) : null} */}
|
||||||
</div>
|
</div>
|
||||||
|
{/* {isMyPagesMenuOpen ? myPagesMobileDropdown : null} */}
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</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({
|
export default async function Header({
|
||||||
lang,
|
lang,
|
||||||
languageSwitcher,
|
languageSwitcher,
|
||||||
}: LangParams & { languageSwitcher: React.ReactNode }) {
|
myPagesMobileDropdown,
|
||||||
|
}: LangParams & { languageSwitcher: React.ReactNode } & {
|
||||||
|
myPagesMobileDropdown: React.ReactNode
|
||||||
|
}) {
|
||||||
const data = await serverClient().contentstack.base.header({
|
const data = await serverClient().contentstack.base.header({
|
||||||
lang,
|
lang,
|
||||||
})
|
})
|
||||||
@@ -49,6 +52,7 @@ export default async function Header({
|
|||||||
logo={logo}
|
logo={logo}
|
||||||
topMenuMobileLinks={topMenuMobileLinks}
|
topMenuMobileLinks={topMenuMobileLinks}
|
||||||
languageSwitcher={languageSwitcher}
|
languageSwitcher={languageSwitcher}
|
||||||
|
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||||
bookingHref={homeHref}
|
bookingHref={homeHref}
|
||||||
isLoggedIn={!!session}
|
isLoggedIn={!!session}
|
||||||
lang={lang}
|
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
|
logo: Image
|
||||||
topMenuMobileLinks: TopMenuHeaderLink[]
|
topMenuMobileLinks: TopMenuHeaderLink[]
|
||||||
languageSwitcher: React.ReactNode | null
|
languageSwitcher: React.ReactNode | null
|
||||||
|
myPagesMobileDropdown: React.ReactNode | null
|
||||||
bookingHref: string
|
bookingHref: string
|
||||||
isLoggedIn: boolean
|
isLoggedIn: boolean
|
||||||
lang: Lang
|
lang: Lang
|
||||||
|
|||||||
Reference in New Issue
Block a user