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

View File

@@ -1,24 +1,29 @@
"use client"
import { useIntl } from "react-intl"
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 { ArrowRightIcon } from "@/components/Icons"
import { ArrowRightIcon, ChevronDownIcon } from "@/components/Icons"
import Link from "@/components/TempDesignSystem/Link"
import useLang from "@/hooks/useLang"
import { getInitials } from "@/utils/user"
import MainMenuButton from "../MainMenuButton"
import Avatar from "./Avatar"
import styles from "./myPagesMenu.module.css"
type Navigation = Awaited<ReturnType<(typeof navigationQueryRouter)["get"]>>
import { MyPagesMenuProps } from "@/types/components/header/myPagesMenu"
export default function MyPagesMenu({
navigation,
}: {
navigation: Navigation
}) {
const { formatMessage } = useIntl()
// This component is mostly the same as MyPagesMobileDropdown, but with a
// different name and some different styles. Should probably be refactored in
// a later stage to fit the design from Figma better.
export default function MyPagesMenu({ navigation, user }: MyPagesMenuProps) {
const intl = useIntl()
const lang = useLang()
const { toggleMyPagesMobileMenu, isMyPagesMobileMenuOpen } =
useDropdownStore()
@@ -27,55 +32,79 @@ export default function MyPagesMenu({
return null
}
return (
<nav
className={`${styles.myPagesMenu} ${isMyPagesMobileMenuOpen ? styles.isExpanded : ""}`}
>
<div className={styles.friendTypeWrapper}>
<span className={styles.friendType}>Loyal friend</span>
<span className={styles.friendPoints}>12 350 points</span>
</div>
<ul className={styles.groups}>
{navigation.menuItems.map((menuItem, idx) => (
<li
key={`${menuItem.display_sign_out_link}-${idx}`}
id={`${menuItem.display_sign_out_link}-${idx}`}
className={styles.group}
>
<ul className={styles.menuItems}>
{menuItem.links.map((link) => (
<li key={link.uid}>
<Link
href={link.originalUrl || link.url}
partialMatch
size={menuItem.display_sign_out_link ? "small" : "regular"}
variant="myPageMobileDropdown"
color="burgundy"
onClick={toggleMyPagesMobileMenu}
className={styles.link}
>
{link.linkText}
<ArrowRightIcon className={styles.arrow} color="burgundy" />
</Link>
</li>
))}
{menuItem.display_sign_out_link && lang ? (
<li>
<Link
href={logout[lang]}
prefetch={false}
size="small"
color="burgundy"
variant="myPageMobileDropdown"
>
{formatMessage({ id: "Log out" })}
</Link>
</li>
) : null}
</ul>
</li>
))}
</ul>
</nav>
return user ? (
<>
<MainMenuButton
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"
/>
</MainMenuButton>
<nav
className={`${styles.myPagesMenu} ${isMyPagesMobileMenuOpen ? styles.isExpanded : ""}`}
>
{/* TODO: Get information from API/ContentStack, check with design team if this information is needed here. */}
<div className={styles.friendTypeWrapper}>
<span className={styles.friendType}>Loyal friend</span>
<span className={styles.friendPoints}>12 350 points</span>
</div>
<ul className={styles.groups}>
{navigation.menuItems.map((menuItem, idx) => (
<li
key={`${menuItem.display_sign_out_link}-${idx}`}
className={styles.group}
>
<ul className={styles.menuItems}>
{menuItem.links.map((link) => (
<li key={link.uid}>
<Link
href={link.originalUrl || link.url}
partialMatch
size={
menuItem.display_sign_out_link ? "small" : "regular"
}
variant="myPageMobileDropdown"
color="burgundy"
onClick={toggleMyPagesMobileMenu}
className={styles.link}
>
{link.linkText}
<ArrowRightIcon
className={styles.arrow}
color="burgundy"
/>
</Link>
</li>
))}
{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 {
position: absolute;
top: 46px;
@@ -5,7 +17,7 @@
background-color: var(--Base-Surface-Primary-light-Normal);
padding: var(--Spacing-x2) var(--Spacing-x4);
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;
display: none;
}

View File

@@ -5,12 +5,13 @@ import { useState } from "react"
import { ChevronDownIcon } from "@/components/Icons"
import Link from "@/components/TempDesignSystem/Link"
import MenuButton from "../MenuButton"
import { MenuItemProps } from "./menuItem"
import MainMenuButton from "../../MainMenuButton"
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 [isExpanded, setIsExpanded] = useState(false)
@@ -19,13 +20,13 @@ export default function MenuItem({ item }: MenuItemProps) {
}
return children?.length ? (
<MenuButton onClick={handleButtonClick}>
<MainMenuButton onClick={handleButtonClick}>
{title}
<ChevronDownIcon
className={`${styles.chevron} ${isExpanded ? styles.isExpanded : ""}`}
color="red"
/>
</MenuButton>
</MainMenuButton>
) : (
<Link href={href} color="burgundy">
{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;
margin: 0;
display: flex;

View File

@@ -5,32 +5,12 @@ import { serverClient } from "@/lib/trpc/server"
import Image from "@/components/Image"
import { getIntl } from "@/i18n"
import Menu from "./Menu"
import MyPages from "./MyPages"
import { navigationMenuItems } from "../tempHeaderData"
import MyPagesMenu from "./MyPagesMenu"
import NavigationMenu from "./NavigationMenu"
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() {
const intl = await getIntl()
const myPagesNavigation =
@@ -38,82 +18,9 @@ export default async function MainMenu() {
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 (
<div className={styles.mainMenu}>
<nav className={styles.content}>
<nav className={styles.nav}>
<Link className={styles.logoLink} href="/">
<Image
alt={intl.formatMessage({ id: "Back to scandichotels.com" })}
@@ -126,8 +33,8 @@ export default async function MainMenu() {
width={113}
/>
</Link>
<Menu items={menuItems} />
<MyPages myPagesNavigation={myPagesNavigation} user={user} />
<NavigationMenu items={navigationMenuItems} />
<MyPagesMenu navigation={myPagesNavigation} user={user} />
</nav>
</div>
)

View File

@@ -4,7 +4,7 @@
border-bottom: 1px solid var(--Base-Border-Subtle);
}
.content {
.nav {
position: relative;
max-width: 89.5rem;
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 useLang from "@/hooks/useLang"
import Button from "../Button"
import TopMenuButton from "../TopMenuButton"
import styles from "./languageSwitcher.module.css"
@@ -26,7 +26,7 @@ export default function LanguageSwitcher({ urls }: LanguageSwitcherProps) {
return (
<div className={styles.languageSwitcher}>
<Button onClick={toggleExpand}>
<TopMenuButton onClick={toggleExpand}>
<GlobeIcon width={20} height={20} color="burgundy" />
<span>{languages[currentLanguage]}</span>
<ChevronDownIcon
@@ -35,7 +35,7 @@ export default function LanguageSwitcher({ urls }: LanguageSwitcherProps) {
height={20}
color="burgundy"
/>
</Button>
</TopMenuButton>
<div
className={`${styles.dropdown} ${isExpanded ? styles.isExpanded : ""}`}
>

View File

@@ -4,15 +4,15 @@ import { useIntl } from "react-intl"
import { SearchIcon } from "@/components/Icons"
import Button from "../Button"
import TopMenuButton from "../TopMenuButton"
export default function Search() {
const intl = useIntl()
return (
<Button>
<TopMenuButton>
<SearchIcon width={20} height={20} color="burgundy" />
{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> {}