chore: cleanup

This commit is contained in:
Erik Tiekstra
2024-08-21 08:18:22 +02:00
parent c6ad5eecc5
commit 0dcb5a796a
32 changed files with 291 additions and 288 deletions

View File

@@ -0,0 +1,16 @@
import styles from "./menuButton.module.css"
import { MainMenuButtonProps } from "@/types/components/header/mainMenuButton"
export default function MainMenuButton({
className = "",
...props
}: MainMenuButtonProps) {
return (
<button
type="button"
className={`${styles.menuButton} ${className}`}
{...props}
/>
)
}

View File

@@ -1,16 +0,0 @@
import MenuItem from "../MenuItem"
import { MenuProps } from "./menu"
import styles from "./menu.module.css"
export default function Menu({ items }: MenuProps) {
return (
<ul className={styles.menu}>
{items.map((item) => (
<li key={item.id}>
<MenuItem item={item} />
</li>
))}
</ul>
)
}

View File

@@ -1,5 +0,0 @@
import { MenuItem } from ".."
export interface MenuProps {
items: MenuItem[]
}

View File

@@ -1,11 +0,0 @@
import styles from "./menuButton.module.css"
export default function MenuButton({
className,
...props
}: React.ButtonHTMLAttributes<HTMLButtonElement>) {
const classNames = className
? `${styles.menuButton} ${className}`
: styles.menuButton
return <button type="button" className={classNames} {...props} />
}

View File

@@ -1,5 +0,0 @@
import { MenuItem } from ".."
export interface MenuItemProps {
item: MenuItem
}

View File

@@ -1,53 +0,0 @@
"use client"
import Link from "next/link"
import { useIntl } from "react-intl"
import { myPages } from "@/constants/routes/myPages"
import { navigationQueryRouter } from "@/server/routers/contentstack/myPages/navigation/query"
import useDropdownStore from "@/stores/main-menu"
import { ChevronDownIcon } from "@/components/Icons"
import useLang from "@/hooks/useLang"
import { getInitials } from "@/utils/user"
import MenuButton from "../MenuButton"
import MyPagesMenu from "../MyPagesMenu"
import Avatar from "./Avatar"
import styles from "./myPages.module.css"
import { User } from "@/types/user"
export default function MyPages({
myPagesNavigation,
user,
}: {
myPagesNavigation: Awaited<ReturnType<(typeof navigationQueryRouter)["get"]>>
user: Pick<User, "firstName" | "lastName"> | null
}) {
const intl = useIntl()
const lang = useLang()
const { toggleMyPagesMobileMenu, isMyPagesMobileMenuOpen } =
useDropdownStore()
return user ? (
<>
<MenuButton className={styles.button} onClick={toggleMyPagesMobileMenu}>
<Avatar initials={getInitials(user.firstName, user.lastName)} />
{intl.formatMessage({ id: "Hi" })} {user.firstName}!
<ChevronDownIcon
className={`${styles.chevron} ${isMyPagesMobileMenuOpen ? styles.isExpanded : ""}`}
color="red"
/>
</MenuButton>
<MyPagesMenu navigation={myPagesNavigation} />
</>
) : (
<Link href={myPages[lang]} className={styles.link}>
<Avatar />
{intl.formatMessage({ id: "Log in/Join" })}
</Link>
)
}

View File

@@ -1,11 +0,0 @@
.button {
font-weight: 600;
}
.chevron {
transition: transform 0.2s;
}
.chevron.isExpanded {
transform: rotate(180deg);
}

View File

@@ -1,10 +1,10 @@
import { PersonIcon } from "@/components/Icons" import { PersonIcon } from "@/components/Icons"
import Image from "@/components/Image" import Image from "@/components/Image"
import { AvatarProps } from "./avatar"
import styles from "./avatar.module.css" import styles from "./avatar.module.css"
import { AvatarProps } from "@/types/components/header/avatar"
export default function Avatar({ image, initials }: AvatarProps) { export default function Avatar({ image, initials }: AvatarProps) {
let classNames = [styles.avatar] let classNames = [styles.avatar]
let element = <PersonIcon color="white" /> let element = <PersonIcon color="white" />

View File

@@ -1,24 +1,29 @@
"use client" "use client"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { logout } from "@/constants/routes/handleAuth" import { logout } from "@/constants/routes/handleAuth"
import { navigationQueryRouter } from "@/server/routers/contentstack/myPages/navigation/query" import { myPages } from "@/constants/routes/myPages"
import useDropdownStore from "@/stores/main-menu" import useDropdownStore from "@/stores/main-menu"
import { ArrowRightIcon } from "@/components/Icons" import { ArrowRightIcon, ChevronDownIcon } from "@/components/Icons"
import Link from "@/components/TempDesignSystem/Link" import Link from "@/components/TempDesignSystem/Link"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import { getInitials } from "@/utils/user"
import MainMenuButton from "../MainMenuButton"
import Avatar from "./Avatar"
import styles from "./myPagesMenu.module.css" import styles from "./myPagesMenu.module.css"
type Navigation = Awaited<ReturnType<(typeof navigationQueryRouter)["get"]>> import { MyPagesMenuProps } from "@/types/components/header/myPagesMenu"
export default function MyPagesMenu({ // This component is mostly the same as MyPagesMobileDropdown, but with a
navigation, // different name and some different styles. Should probably be refactored in
}: { // a later stage to fit the design from Figma better.
navigation: Navigation
}) { export default function MyPagesMenu({ navigation, user }: MyPagesMenuProps) {
const { formatMessage } = useIntl() const intl = useIntl()
const lang = useLang() const lang = useLang()
const { toggleMyPagesMobileMenu, isMyPagesMobileMenuOpen } = const { toggleMyPagesMobileMenu, isMyPagesMobileMenuOpen } =
useDropdownStore() useDropdownStore()
@@ -27,55 +32,79 @@ export default function MyPagesMenu({
return null return null
} }
return ( return user ? (
<nav <>
className={`${styles.myPagesMenu} ${isMyPagesMobileMenuOpen ? styles.isExpanded : ""}`} <MainMenuButton
> className={styles.button}
<div className={styles.friendTypeWrapper}> onClick={toggleMyPagesMobileMenu}
<span className={styles.friendType}>Loyal friend</span> >
<span className={styles.friendPoints}>12 350 points</span> <Avatar initials={getInitials(user.firstName, user.lastName)} />
</div> {intl.formatMessage({ id: "Hi" })} {user.firstName}!
<ul className={styles.groups}> <ChevronDownIcon
{navigation.menuItems.map((menuItem, idx) => ( className={`${styles.chevron} ${isMyPagesMobileMenuOpen ? styles.isExpanded : ""}`}
<li color="red"
key={`${menuItem.display_sign_out_link}-${idx}`} />
id={`${menuItem.display_sign_out_link}-${idx}`} </MainMenuButton>
className={styles.group} <nav
> className={`${styles.myPagesMenu} ${isMyPagesMobileMenuOpen ? styles.isExpanded : ""}`}
<ul className={styles.menuItems}> >
{menuItem.links.map((link) => ( {/* TODO: Get information from API/ContentStack, check with design team if this information is needed here. */}
<li key={link.uid}> <div className={styles.friendTypeWrapper}>
<Link <span className={styles.friendType}>Loyal friend</span>
href={link.originalUrl || link.url} <span className={styles.friendPoints}>12 350 points</span>
partialMatch </div>
size={menuItem.display_sign_out_link ? "small" : "regular"}
variant="myPageMobileDropdown" <ul className={styles.groups}>
color="burgundy" {navigation.menuItems.map((menuItem, idx) => (
onClick={toggleMyPagesMobileMenu} <li
className={styles.link} key={`${menuItem.display_sign_out_link}-${idx}`}
> className={styles.group}
{link.linkText} >
<ArrowRightIcon className={styles.arrow} color="burgundy" /> <ul className={styles.menuItems}>
</Link> {menuItem.links.map((link) => (
</li> <li key={link.uid}>
))} <Link
{menuItem.display_sign_out_link && lang ? ( href={link.originalUrl || link.url}
<li> partialMatch
<Link size={
href={logout[lang]} menuItem.display_sign_out_link ? "small" : "regular"
prefetch={false} }
size="small" variant="myPageMobileDropdown"
color="burgundy" color="burgundy"
variant="myPageMobileDropdown" onClick={toggleMyPagesMobileMenu}
> className={styles.link}
{formatMessage({ id: "Log out" })} >
</Link> {link.linkText}
</li> <ArrowRightIcon
) : null} className={styles.arrow}
</ul> color="burgundy"
</li> />
))} </Link>
</ul> </li>
</nav> ))}
{menuItem.display_sign_out_link && lang ? (
<li>
<Link
href={logout[lang]}
prefetch={false}
size="small"
color="burgundy"
variant="myPageMobileDropdown"
>
{intl.formatMessage({ id: "Log out" })}
</Link>
</li>
) : null}
</ul>
</li>
))}
</ul>
</nav>
</>
) : (
<Link href={myPages[lang]} className={styles.link}>
<Avatar />
{intl.formatMessage({ id: "Log in/Join" })}
</Link>
) )
} }

View File

@@ -1,3 +1,15 @@
.button {
font-weight: 600;
}
.chevron {
transition: transform 0.2s;
}
.chevron.isExpanded {
transform: rotate(180deg);
}
.myPagesMenu { .myPagesMenu {
position: absolute; position: absolute;
top: 46px; top: 46px;
@@ -5,7 +17,7 @@
background-color: var(--Base-Surface-Primary-light-Normal); background-color: var(--Base-Surface-Primary-light-Normal);
padding: var(--Spacing-x2) var(--Spacing-x4); padding: var(--Spacing-x2) var(--Spacing-x4);
border-radius: var(--Corner-radius-Large); border-radius: var(--Corner-radius-Large);
box-shadow: 0px 0px 14px 6px #0000001a; box-shadow: 0px 0px 14px 6px rgba(0, 0, 0, 0.1);
z-index: 1; z-index: 1;
display: none; display: none;
} }

View File

@@ -5,12 +5,13 @@ import { useState } from "react"
import { ChevronDownIcon } from "@/components/Icons" import { ChevronDownIcon } from "@/components/Icons"
import Link from "@/components/TempDesignSystem/Link" import Link from "@/components/TempDesignSystem/Link"
import MenuButton from "../MenuButton" import MainMenuButton from "../../MainMenuButton"
import { MenuItemProps } from "./menuItem"
import styles from "./menuItem.module.css" import styles from "./navigationMenuItem.module.css"
export default function MenuItem({ item }: MenuItemProps) { import { NavigationMenuItemProps } from "@/types/components/header/navigationMenuItem"
export default function MenuItem({ item }: NavigationMenuItemProps) {
const { children, title, href, seeAllLinkText, infoCard } = item const { children, title, href, seeAllLinkText, infoCard } = item
const [isExpanded, setIsExpanded] = useState(false) const [isExpanded, setIsExpanded] = useState(false)
@@ -19,13 +20,13 @@ export default function MenuItem({ item }: MenuItemProps) {
} }
return children?.length ? ( return children?.length ? (
<MenuButton onClick={handleButtonClick}> <MainMenuButton onClick={handleButtonClick}>
{title} {title}
<ChevronDownIcon <ChevronDownIcon
className={`${styles.chevron} ${isExpanded ? styles.isExpanded : ""}`} className={`${styles.chevron} ${isExpanded ? styles.isExpanded : ""}`}
color="red" color="red"
/> />
</MenuButton> </MainMenuButton>
) : ( ) : (
<Link href={href} color="burgundy"> <Link href={href} color="burgundy">
{title} {title}

View File

@@ -0,0 +1,17 @@
import NavigationMenuItem from "./NavigationMenuItem"
import styles from "./navigationMenu.module.css"
import { NavigationMenuProps } from "@/types/components/header/navigationMenu"
export default function NavigationMenu({ items }: NavigationMenuProps) {
return (
<ul className={styles.navigationMenu}>
{items.map((item) => (
<li key={item.id}>
<NavigationMenuItem item={item} />
</li>
))}
</ul>
)
}

View File

@@ -1,4 +1,4 @@
.menu { .navigationMenu {
list-style: none; list-style: none;
margin: 0; margin: 0;
display: flex; display: flex;

View File

@@ -5,32 +5,12 @@ import { serverClient } from "@/lib/trpc/server"
import Image from "@/components/Image" import Image from "@/components/Image"
import { getIntl } from "@/i18n" import { getIntl } from "@/i18n"
import Menu from "./Menu" import { navigationMenuItems } from "../tempHeaderData"
import MyPages from "./MyPages" import MyPagesMenu from "./MyPagesMenu"
import NavigationMenu from "./NavigationMenu"
import styles from "./mainMenu.module.css" import styles from "./mainMenu.module.css"
export interface MenuItem {
id: string
title: string
href: string
children?: {
groupTitle: string
children: {
id: string
title: string
href: string
}[]
}[]
seeAllLinkText?: string
infoCard?: {
scriptedTitle: string
title: string
description: string
ctaLink: string
}
}
export default async function MainMenu() { export default async function MainMenu() {
const intl = await getIntl() const intl = await getIntl()
const myPagesNavigation = const myPagesNavigation =
@@ -38,82 +18,9 @@ export default async function MainMenu() {
const user = await serverClient().user.name() const user = await serverClient().user.name()
const menuItems: MenuItem[] = [
{
id: "hotels",
title: "Hotels",
href: "/hotels",
children: [],
},
{
id: "business",
title: "Business",
href: "/business",
children: [
{
groupTitle: "Top conference venues",
children: [
{
id: "stockholm",
title: "Stockholm",
href: "/stockholm",
},
{
id: "bergen",
title: "Bergen",
href: "/bergen",
},
{
id: "copenhagen",
title: "Copenhagen",
href: "/copenhagen",
},
],
},
{
groupTitle: "Scandic for business",
children: [
{
id: "book-a-venue",
title: "Book a venue",
href: "/book-a-venue",
},
{
id: "conference-packages",
title: "Conference packages",
href: "/conference-packages",
},
{
id: "co-working",
title: "Co-working",
href: "/co-working",
},
],
},
],
seeAllLinkText: "See all conference & meeting venues",
infoCard: {
scriptedTitle: "Stockholm",
title: "Meeting venues in Stockholm",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et felis metus. Sed et felis metus.",
ctaLink: "/stockholm",
},
},
{
id: "offers",
title: "Offers",
href: "/offers",
},
{
id: "restaurants",
title: "Restaurants",
href: "/restaurants",
},
]
return ( return (
<div className={styles.mainMenu}> <div className={styles.mainMenu}>
<nav className={styles.content}> <nav className={styles.nav}>
<Link className={styles.logoLink} href="/"> <Link className={styles.logoLink} href="/">
<Image <Image
alt={intl.formatMessage({ id: "Back to scandichotels.com" })} alt={intl.formatMessage({ id: "Back to scandichotels.com" })}
@@ -126,8 +33,8 @@ export default async function MainMenu() {
width={113} width={113}
/> />
</Link> </Link>
<Menu items={menuItems} /> <NavigationMenu items={navigationMenuItems} />
<MyPages myPagesNavigation={myPagesNavigation} user={user} /> <MyPagesMenu navigation={myPagesNavigation} user={user} />
</nav> </nav>
</div> </div>
) )

View File

@@ -4,7 +4,7 @@
border-bottom: 1px solid var(--Base-Border-Subtle); border-bottom: 1px solid var(--Base-Border-Subtle);
} }
.content { .nav {
position: relative; position: relative;
max-width: 89.5rem; max-width: 89.5rem;
margin: 0 auto; margin: 0 auto;

View File

@@ -1,11 +0,0 @@
import { ButtonProps } from "./button"
import styles from "./button.module.css"
export default function Button({ children, ...props }: ButtonProps) {
return (
<button type="button" className={styles.button} {...props}>
{children}
</button>
)
}

View File

@@ -8,7 +8,7 @@ import { Lang, languages } from "@/constants/languages"
import { CheckIcon, ChevronDownIcon, GlobeIcon } from "@/components/Icons" import { CheckIcon, ChevronDownIcon, GlobeIcon } from "@/components/Icons"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import Button from "../Button" import TopMenuButton from "../TopMenuButton"
import styles from "./languageSwitcher.module.css" import styles from "./languageSwitcher.module.css"
@@ -26,7 +26,7 @@ export default function LanguageSwitcher({ urls }: LanguageSwitcherProps) {
return ( return (
<div className={styles.languageSwitcher}> <div className={styles.languageSwitcher}>
<Button onClick={toggleExpand}> <TopMenuButton onClick={toggleExpand}>
<GlobeIcon width={20} height={20} color="burgundy" /> <GlobeIcon width={20} height={20} color="burgundy" />
<span>{languages[currentLanguage]}</span> <span>{languages[currentLanguage]}</span>
<ChevronDownIcon <ChevronDownIcon
@@ -35,7 +35,7 @@ export default function LanguageSwitcher({ urls }: LanguageSwitcherProps) {
height={20} height={20}
color="burgundy" color="burgundy"
/> />
</Button> </TopMenuButton>
<div <div
className={`${styles.dropdown} ${isExpanded ? styles.isExpanded : ""}`} className={`${styles.dropdown} ${isExpanded ? styles.isExpanded : ""}`}
> >

View File

@@ -4,15 +4,15 @@ import { useIntl } from "react-intl"
import { SearchIcon } from "@/components/Icons" import { SearchIcon } from "@/components/Icons"
import Button from "../Button" import TopMenuButton from "../TopMenuButton"
export default function Search() { export default function Search() {
const intl = useIntl() const intl = useIntl()
return ( return (
<Button> <TopMenuButton>
<SearchIcon width={20} height={20} color="burgundy" /> <SearchIcon width={20} height={20} color="burgundy" />
{intl.formatMessage({ id: "Find booking" })} {intl.formatMessage({ id: "Find booking" })}
</Button> </TopMenuButton>
) )
} }

View File

@@ -0,0 +1,14 @@
import styles from "./topMenuButton.module.css"
import { TopMenuButtonProps } from "@/types/components/header/topMenuButton"
export default function TopMenuButton({
children,
...props
}: TopMenuButtonProps) {
return (
<button type="button" className={styles.button} {...props}>
{children}
</button>
)
}

View File

@@ -0,0 +1,75 @@
import { MainNavigationItem } from "@/types/components/header/mainNavigationItem"
export const navigationMenuItems: MainNavigationItem[] = [
{
id: "hotels",
title: "Hotels",
href: "/hotels",
children: [],
},
{
id: "business",
title: "Business",
href: "/business",
children: [
{
groupTitle: "Top conference venues",
children: [
{
id: "stockholm",
title: "Stockholm",
href: "/stockholm",
},
{
id: "bergen",
title: "Bergen",
href: "/bergen",
},
{
id: "copenhagen",
title: "Copenhagen",
href: "/copenhagen",
},
],
},
{
groupTitle: "Scandic for business",
children: [
{
id: "book-a-venue",
title: "Book a venue",
href: "/book-a-venue",
},
{
id: "conference-packages",
title: "Conference packages",
href: "/conference-packages",
},
{
id: "co-working",
title: "Co-working",
href: "/co-working",
},
],
},
],
seeAllLinkText: "See all conference & meeting venues",
infoCard: {
scriptedTitle: "Stockholm",
title: "Meeting venues in Stockholm",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et felis metus. Sed et felis metus.",
ctaLink: "/stockholm",
},
},
{
id: "offers",
title: "Offers",
href: "/offers",
},
{
id: "restaurants",
title: "Restaurants",
href: "/restaurants",
},
]

View File

@@ -0,0 +1,2 @@
export interface MainMenuButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}

View File

@@ -0,0 +1,20 @@
export interface MainNavigationItem {
id: string
title: string
href: string
children?: {
groupTitle: string
children: {
id: string
title: string
href: string
}[]
}[]
seeAllLinkText?: string
infoCard?: {
scriptedTitle: string
title: string
description: string
ctaLink: string
}
}

View File

@@ -0,0 +1,12 @@
import { navigationQueryRouter } from "@/server/routers/contentstack/myPages/navigation/query"
import { User } from "@/types/user"
type MyPagesNavigation = Awaited<
ReturnType<(typeof navigationQueryRouter)["get"]>
>
export interface MyPagesMenuProps {
navigation: MyPagesNavigation
user: Pick<User, "firstName" | "lastName"> | null
}

View File

@@ -0,0 +1,5 @@
import { MainNavigationItem } from "@/types/components/header/mainNavigationItem"
export interface NavigationMenuProps {
items: MainNavigationItem[]
}

View File

@@ -0,0 +1,5 @@
import { MainNavigationItem } from "@/types/components/header/mainNavigationItem"
export interface NavigationMenuItemProps {
item: MainNavigationItem
}

View File

@@ -1,2 +1,2 @@
export interface ButtonProps export interface TopMenuButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {} extends React.ButtonHTMLAttributes<HTMLButtonElement> {}