diff --git a/app/[lang]/(live)/(public)/hotelreservation/README.md b/app/[lang]/(live)/(public)/hotelreservation/README.md new file mode 100644 index 000000000..fdc0f1ad4 --- /dev/null +++ b/app/[lang]/(live)/(public)/hotelreservation/README.md @@ -0,0 +1,27 @@ +# Booking flow + +The booking flow is the user journey of booking one or more rooms at our +hotels. Everything from choosing the date to payment and confirmation is +part of the booking flow. + +## Booking widget + +On most of the pages on the website we have a booking widget. This is where +the user starts the booking flow, by filling the form and submit. If they +entered a city as the destination they will land on the select hotel page +and if they entered a specific hotel they will land on the select rate page. + +## Select hotel + +Lists available hotels based on the search criteria. When the user selects +a hotel they land on the select rate page. + +## Select rate, room, breakfast etc + +This is a page with an accordion like design, but every accordion is handled +as its own page with its own URL. + +## State management + +The state, like search parameters and selected alternatives, is kept +throughout the booking flow in the URL. diff --git a/components/Content/Blocks/CardsGrid/index.tsx b/components/Content/Blocks/CardsGrid/index.tsx index 32b3c8f7f..a03666bf3 100644 --- a/components/Content/Blocks/CardsGrid/index.tsx +++ b/components/Content/Blocks/CardsGrid/index.tsx @@ -1,6 +1,7 @@ import SectionContainer from "@/components/Section/Container" import SectionHeader from "@/components/Section/Header" import Card from "@/components/TempDesignSystem/Card" +import ContentCard from "@/components/TempDesignSystem/ContentCard" import Grids from "@/components/TempDesignSystem/Grids" import LoyaltyCard from "@/components/TempDesignSystem/LoyaltyCard" @@ -21,8 +22,19 @@ export default function CardsGrid({ {cards_grid.cards.map((card) => { switch (card.__typename) { - case CardsGridEnum.Card: { - return ( + case CardsGridEnum.Card: + return card.isContentCard ? ( + + ) : ( ) - } case CardsGridEnum.LoyaltyCard: return ( {intl.formatMessage({ id: "See room details" })} - + diff --git a/components/LanguageSwitcher/LanguageSwitcherContainer/index.tsx b/components/LanguageSwitcher/LanguageSwitcherContainer/index.tsx new file mode 100644 index 000000000..ada415172 --- /dev/null +++ b/components/LanguageSwitcher/LanguageSwitcherContainer/index.tsx @@ -0,0 +1,63 @@ +import { useIntl } from "react-intl" + +import useDropdownStore from "@/stores/main-menu" + +import { ChevronLeftIcon } from "@/components/Icons" +import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" + +import styles from "./languageSwitcherContainer.module.css" + +import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown" +import { + type LanguageSwitcherContainerProps, + LanguageSwitcherTypesEnum, +} from "@/types/components/languageSwitcher/languageSwitcher" + +export default function LanguageSwitcherContainer({ + children, + type, +}: LanguageSwitcherContainerProps) { + const { toggleDropdown } = useDropdownStore() + const intl = useIntl() + const isFooter = type === LanguageSwitcherTypesEnum.Footer + const isMobileHeader = type === LanguageSwitcherTypesEnum.MobileHeader + const position = isFooter + ? DropdownTypeEnum.FooterLanguageSwitcher + : DropdownTypeEnum.HamburgerMenu + + return ( +
+ {isMobileHeader ? ( +
+ +
+ ) : null} + {isFooter ? ( +
+ +
+ ) : null} + {children} +
+ ) +} diff --git a/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css b/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css new file mode 100644 index 000000000..e683a5e26 --- /dev/null +++ b/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css @@ -0,0 +1,70 @@ +.backWrapper { + background-color: var(--Base-Surface-Secondary-light-Normal); + padding: var(--Spacing-x2); +} + +.backButton { + background-color: transparent; + border: none; + padding: 0; + cursor: pointer; + display: flex; + align-items: center; + gap: var(--Spacing-x1); +} + +.closeWrapper { + display: flex; + justify-content: flex-end; + padding: var(--Spacing-x2); + border-bottom: 1px solid var(--Base-Border-Subtle); +} + +.closeButton { + background-color: transparent; + border: none; + cursor: pointer; + justify-self: flex-start; + padding: 11px var(--Spacing-x1) var(--Spacing-x2); + user-select: none; +} + +.bar, +.bar::after, +.bar::before { + background: var(--Base-Text-High-contrast); + border-radius: 2.3px; + display: inline-block; + height: 3px; + position: relative; + transition: all 0.3s; + width: var(--Spacing-x4); +} + +.bar::after, +.bar::before { + content: ""; + left: 0; + position: absolute; + top: 0; + transform-origin: 50% 50%; + width: var(--Spacing-x4); +} + +.bar { + background: transparent; +} + +.bar::after { + transform: rotate(-45deg); +} + +.bar::before { + transform: rotate(45deg); +} + +@media screen and (min-width: 768px) { + .closeWrapper { + display: none; + } +} diff --git a/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx b/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx index 9aebfa711..3533ecb93 100644 --- a/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx +++ b/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx @@ -3,9 +3,8 @@ import { useIntl } from "react-intl" import { Lang, languages } from "@/constants/languages" -import useDropdownStore from "@/stores/main-menu" -import { CheckIcon, ChevronLeftIcon } from "@/components/Icons" +import { CheckIcon } from "@/components/Icons" import Link from "@/components/TempDesignSystem/Link" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import useLang from "@/hooks/useLang" @@ -13,38 +12,19 @@ import { useTrapFocus } from "@/hooks/useTrapFocus" import styles from "./languageSwitcherContent.module.css" -import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown" -import type { LanguageSwitcherProps } from "@/types/components/languageSwitcher/languageSwitcher" +import type { LanguageSwitcherContentProps } from "@/types/components/languageSwitcher/languageSwitcher" export default function LanguageSwitcherContent({ urls, - type, -}: LanguageSwitcherProps) { +}: LanguageSwitcherContentProps) { const intl = useIntl() const currentLanguage = useLang() - const { toggleDropdown } = useDropdownStore() + const languageSwitcherRef = useTrapFocus() const urlKeys = Object.keys(urls) as Lang[] - const position = - type === "footer" - ? DropdownTypeEnum.FooterLanguageSwitcher - : DropdownTypeEnum.HamburgerMenu return (
- {type === "mobileHeader" ? ( -
- -
- ) : null} -
{intl.formatMessage({ id: "Select your language" })} diff --git a/components/LanguageSwitcher/LanguageSwitcherContent/languageSwitcherContent.module.css b/components/LanguageSwitcher/LanguageSwitcherContent/languageSwitcherContent.module.css index 465b39c23..24e3febb8 100644 --- a/components/LanguageSwitcher/LanguageSwitcherContent/languageSwitcherContent.module.css +++ b/components/LanguageSwitcher/LanguageSwitcherContent/languageSwitcherContent.module.css @@ -1,22 +1,3 @@ -.backWrapper { - background-color: var(--Base-Surface-Secondary-light-Normal); - padding: var(--Spacing-x2); -} - -.backButton { - background-color: transparent; - border: none; - color: var(--Base-Text-High-contrast); - font-family: var(--typography-Subtitle-1-fontFamily); - font-weight: var(--typography-Subtitle-1-fontWeight); - font-size: var(--typography-Subtitle-1-Mobile-fontSize); - padding: 0; - cursor: pointer; - display: flex; - align-items: center; - gap: var(--Spacing-x1); -} - .languageWrapper { display: grid; gap: var(--Spacing-x3); diff --git a/components/LanguageSwitcher/index.tsx b/components/LanguageSwitcher/index.tsx index 65888d578..7a5ecb6b2 100644 --- a/components/LanguageSwitcher/index.tsx +++ b/components/LanguageSwitcher/index.tsx @@ -1,5 +1,6 @@ "use client" +import { useEffect } from "react" import { useIntl } from "react-intl" import { languages } from "@/constants/languages" @@ -9,13 +10,17 @@ import { ChevronDownIcon, GlobeIcon } from "@/components/Icons" import { useHandleKeyUp } from "@/hooks/useHandleKeyUp" import useLang from "@/hooks/useLang" +import LanguageSwitcherContainer from "./LanguageSwitcherContainer" import LanguageSwitcherContent from "./LanguageSwitcherContent" import { languageSwitcherVariants } from "./variants" import styles from "./languageSwitcher.module.css" import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown" -import type { LanguageSwitcherProps } from "@/types/components/languageSwitcher/languageSwitcher" +import { + type LanguageSwitcherProps, + LanguageSwitcherTypesEnum, +} from "@/types/components/languageSwitcher/languageSwitcher" export default function LanguageSwitcher({ urls, @@ -30,8 +35,11 @@ export default function LanguageSwitcher({ isHeaderLanguageSwitcherMobileOpen, } = useDropdownStore() - const position = type === "footer" ? "footer" : "header" - const color = type === "footer" ? "pale" : "burgundy" + const isFooter = type === LanguageSwitcherTypesEnum.Footer + const isHeader = !isFooter + + const position = isFooter ? "footer" : "header" + const color = isFooter ? "pale" : "burgundy" const dropdownType = { footer: DropdownTypeEnum.FooterLanguageSwitcher, @@ -40,8 +48,8 @@ export default function LanguageSwitcher({ }[type] const isLanguageSwitcherOpen = - (type === "footer" && isFooterLanguageSwitcherOpen) || - (type !== "footer" && + (isFooter && isFooterLanguageSwitcherOpen) || + (isHeader && (isHeaderLanguageSwitcherOpen || isHeaderLanguageSwitcherMobileOpen)) useHandleKeyUp((event: KeyboardEvent) => { @@ -50,6 +58,18 @@ export default function LanguageSwitcher({ } }) + useEffect(() => { + if (isFooter && isFooterLanguageSwitcherOpen) { + document.body.style.overflow = "hidden" + } else { + document.body.style.overflow = "" + } + + return () => { + document.body.style.overflow = "" + } + }, [isFooter, isFooterLanguageSwitcherOpen]) + const classNames = languageSwitcherVariants({ color, position }) return ( @@ -78,7 +98,9 @@ export default function LanguageSwitcher({ className={`${styles.dropdown} ${isLanguageSwitcherOpen ? styles.isExpanded : ""}`} > {isLanguageSwitcherOpen ? ( - + + + ) : null}
diff --git a/components/LanguageSwitcher/languageSwitcher.module.css b/components/LanguageSwitcher/languageSwitcher.module.css index 6c85a22aa..4cde01f31 100644 --- a/components/LanguageSwitcher/languageSwitcher.module.css +++ b/components/LanguageSwitcher/languageSwitcher.module.css @@ -31,20 +31,36 @@ .dropdown { position: fixed; - top: var(--main-menu-mobile-height); - right: -100vw; - bottom: 0; width: 100%; background-color: var(--Base-Surface-Primary-light-Normal); - transition: right 0.3s; z-index: var(--menu-overlay-z-index); } -.dropdown.isExpanded { +.top .dropdown { + right: -100vw; + top: var(--main-menu-mobile-height); + bottom: 0; + transition: right 0.3s; +} + +.top .dropdown.isExpanded { display: block; right: 0; } +.bottom .dropdown { + transition: transform 0.3s; + width: 100%; + height: 100vh; + left: 0; + bottom: 0; + transform: translateY(100%); +} + +.bottom .dropdown.isExpanded { + transform: translateY(0); +} + @media screen and (min-width: 768px) { .languageSwitcher { position: relative; @@ -81,10 +97,16 @@ } .bottom .dropdown { - top: auto; + transition: none; + height: auto; + left: -100%; bottom: 2.25rem; } + .bottom .dropdown.isExpanded { + display: block; + } + .bottom .dropdown::before { top: 100%; } diff --git a/components/TempDesignSystem/ContentCard/contentCard.module.css b/components/TempDesignSystem/ContentCard/contentCard.module.css new file mode 100644 index 000000000..9a90d97c7 --- /dev/null +++ b/components/TempDesignSystem/ContentCard/contentCard.module.css @@ -0,0 +1,71 @@ +.card { + border-radius: var(--Corner-radius-Medium); + display: flex; + flex-direction: column; + max-width: 399px; + overflow: hidden; +} + +.default { + background-color: var(--Base-Surface-Subtle-Normal); +} + +.featured { + background-color: var(--Main-Grey-White); +} + +.default, +.featured { + border: 1px solid var(--Base-Border-Subtle); +} + +.imageContainer { + width: 100%; + height: 12.58625rem; /* 201.38px / 16 = 12.58625rem */ + overflow: hidden; +} + +.backgroundImage { + width: 100%; + height: 100%; + object-fit: cover; +} + +.content { + display: flex; + flex-direction: column; + gap: var(--Spacing-x-one-and-half); + align-items: flex-start; + padding: var(--Spacing-x2) var(--Spacing-x3); +} + +.description { + color: var(--Base-Text-Medium-contrast); +} + +.ctaContainer { + display: grid; + grid-template-columns: 1fr; + gap: var(--Spacing-x1); + width: 100%; +} + +.ctaButton { + width: 100%; +} + +@media (min-width: 1367px) { + .card:not(.alwaysStack) .ctaContainer { + grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); + } + + .card:not(.alwaysStack) .ctaContainer:has(:only-child) { + grid-template-columns: 1fr; + } +} + +.sidePeekCTA { + /* TODO: Create ticket to remove padding on "link" buttons, + align w. design on this. */ + padding: 0 !important; +} diff --git a/components/TempDesignSystem/ContentCard/index.tsx b/components/TempDesignSystem/ContentCard/index.tsx new file mode 100644 index 000000000..bdde9de6f --- /dev/null +++ b/components/TempDesignSystem/ContentCard/index.tsx @@ -0,0 +1,98 @@ +import React from "react" + +import { ChevronRightIcon } from "@/components/Icons" +import Image from "@/components/Image" +import Button from "@/components/TempDesignSystem/Button" +import Link from "@/components/TempDesignSystem/Link" +import Body from "@/components/TempDesignSystem/Text/Body" + +import Subtitle from "../Text/Subtitle" +import { contentCardVariants } from "./variants" + +import styles from "./contentCard.module.css" + +import type { ContentCardProps } from "@/types/components/contentCard" + +export default function ContentCard({ + title, + description, + primaryButton, + secondaryButton, + sidePeekButton, + backgroundImage, + style = "default", + alwaysStack = false, + className, +}: ContentCardProps) { + const cardClasses = contentCardVariants({ style, alwaysStack, className }) + + return ( +
+ {backgroundImage && ( +
+ {backgroundImage.meta?.alt +
+ )} +
+ + {title} + + {description} + {!!sidePeekButton ? ( + + ) : ( +
+ {primaryButton && ( + + )} + {secondaryButton && ( + + )} +
+ )} +
+
+ ) +} diff --git a/components/TempDesignSystem/ContentCard/variants.ts b/components/TempDesignSystem/ContentCard/variants.ts new file mode 100644 index 000000000..a9cc2b67f --- /dev/null +++ b/components/TempDesignSystem/ContentCard/variants.ts @@ -0,0 +1,20 @@ +import { cva } from "class-variance-authority" + +import styles from "./contentCard.module.css" + +export const contentCardVariants = cva(styles.card, { + variants: { + style: { + default: styles.default, + featured: styles.featured, + }, + alwaysStack: { + true: styles.alwaysStack, + false: "", + }, + }, + defaultVariants: { + style: "default", + alwaysStack: false, + }, +}) diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index 788d15008..7b6206a20 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -100,6 +100,7 @@ "Log in here": "Log ind her", "Log in/Join": "Log på/Tilmeld dig", "Log out": "Log ud", + "Main menu": "Hovedmenu", "Manage preferences": "Administrer præferencer", "Map": "Kort", "Map of HOTEL_NAME": "Map of {hotelName}", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index fc35327bd..6e1a4b147 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -98,6 +98,7 @@ "Log in here": "Hier einloggen", "Log in/Join": "Log in/Anmelden", "Log out": "Ausloggen", + "Main menu": "Hauptmenü", "Manage preferences": "Verwalten von Voreinstellungen", "Map": "Karte", "Map of HOTEL_NAME": "Map of {hotelName}", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index 0b8c43c6b..bd73a9f0a 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -104,6 +104,7 @@ "Log in here": "Log in here", "Log in/Join": "Log in/Join", "Log out": "Log out", + "Main menu": "Main menu", "Manage preferences": "Manage preferences", "Map": "Map", "Map of HOTEL_NAME": "Map of {hotelName}", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index 551943aaf..a97dea3fe 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -99,6 +99,7 @@ "Log in here": "Kirjaudu sisään", "Log in/Join": "Kirjaudu sisään/Liittyä", "Log out": "Kirjaudu ulos", + "Main menu": "Päävalikko", "Manage preferences": "Asetusten hallinta", "Map": "Kartta", "Map of HOTEL_NAME": "Map of {hotelName}", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index 511e87c25..81ef12cc2 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -99,6 +99,7 @@ "Log in here": "Logg inn her", "Log in/Join": "Logg på/Bli med", "Log out": "Logg ut", + "Main menu": "Hovedmeny", "Manage preferences": "Administrer preferanser", "Map": "Kart", "Map of HOTEL_NAME": "Map of {hotelName}", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index bbb8eed52..0cf45ea96 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -101,6 +101,7 @@ "Log in here": "Logga in här", "Log in/Join": "Logga in/Gå med", "Log out": "Logga ut", + "Main menu": "Huvudmeny", "Manage preferences": "Hantera inställningar", "Map": "Karta", "Map of HOTEL_NAME": "Map of {hotelName}", diff --git a/lib/graphql/Fragments/Blocks/Card.graphql b/lib/graphql/Fragments/Blocks/Card.graphql index 0fb2e416c..d10ee4d5c 100644 --- a/lib/graphql/Fragments/Blocks/Card.graphql +++ b/lib/graphql/Fragments/Blocks/Card.graphql @@ -1,30 +1,13 @@ fragment CardBlock on Card { + is_content_card heading body_text background_image scripted_top_title title - has_secondary_button - secondary_button { - is_contentstack_link - cta_text - open_in_new_tab - external_link { - title - href - } - linkConnection { - edges { - node { - __typename - ...LoyaltyPageLink - ...ContentPageLink - ...AccountPageLink - } - } - } - } has_primary_button + has_secondary_button + has_sidepeek_button primary_button { is_contentstack_link cta_text @@ -44,6 +27,28 @@ fragment CardBlock on Card { } } } + secondary_button { + is_contentstack_link + cta_text + open_in_new_tab + external_link { + title + href + } + linkConnection { + edges { + node { + __typename + ...LoyaltyPageLink + ...ContentPageLink + ...AccountPageLink + } + } + } + } + sidepeek_button { + call_to_action_text + } system { locale uid diff --git a/server/routers/contentstack/bookingwidget/query.ts b/server/routers/contentstack/bookingwidget/query.ts index 89f8d68b6..9b67dba16 100644 --- a/server/routers/contentstack/bookingwidget/query.ts +++ b/server/routers/contentstack/bookingwidget/query.ts @@ -8,7 +8,7 @@ import { GetLoyaltyPageSettings, } from "@/lib/graphql/Query/BookingWidgetToggle.graphql" import { request } from "@/lib/graphql/request" -import { contentstackExtendedProcedureUID, router } from "@/server/trpc" +import { contentstackBaseProcedure, router } from "@/server/trpc" import { generateTag } from "@/utils/generateTag" @@ -21,7 +21,7 @@ import { affix as bookingwidgetAffix } from "./utils" import { ContentTypeEnum } from "@/types/requests/contentType" export const bookingwidgetQueryRouter = router({ - getToggle: contentstackExtendedProcedureUID.query(async ({ ctx }) => { + getToggle: contentstackBaseProcedure.query(async ({ ctx }) => { const failedResponse = { hideBookingWidget: false } const { contentType, uid, lang } = ctx diff --git a/server/routers/contentstack/contentPage/output.ts b/server/routers/contentstack/contentPage/output.ts index b6b920a78..1aa324041 100644 --- a/server/routers/contentstack/contentPage/output.ts +++ b/server/routers/contentstack/contentPage/output.ts @@ -68,6 +68,7 @@ export const contentPageDynamicContent = z.object({ export const cardBlock = z.object({ __typename: z.literal(CardsGridEnum.Card), + isContentCard: z.boolean(), heading: z.string().nullable(), body_text: z.string().nullable(), background_image: z.any(), @@ -88,6 +89,11 @@ export const cardBlock = z.object({ isExternal: z.boolean(), }) .optional(), + sidePeekButton: z + .object({ + title: z.string(), + }) + .optional(), system: z.object({ locale: z.nativeEnum(Lang), uid: z.string(), diff --git a/server/routers/contentstack/contentPage/query.ts b/server/routers/contentstack/contentPage/query.ts index c37adbd68..16ff7e7c1 100644 --- a/server/routers/contentstack/contentPage/query.ts +++ b/server/routers/contentstack/contentPage/query.ts @@ -102,6 +102,7 @@ export const contentPageQueryRouter = router({ case CardsGridEnum.Card: return { ...card, + isContentCard: !!card.is_content_card, backgroundImage: makeImageVaultImage( card.background_image ), @@ -111,6 +112,14 @@ export const contentPageQueryRouter = router({ secondaryButton: card.has_secondary_button ? makeButtonObject(card.secondary_button) : undefined, + sidePeekButton: + card.has_sidepeek_button || + !!card.sidepeek_button?.call_to_action_text + ? { + title: + card.sidepeek_button.call_to_action_text, + } + : undefined, } case CardsGridEnum.LoyaltyCard: return { diff --git a/types/components/contentCard.ts b/types/components/contentCard.ts new file mode 100644 index 000000000..8c904a2e3 --- /dev/null +++ b/types/components/contentCard.ts @@ -0,0 +1,21 @@ +import { VariantProps } from "class-variance-authority" + +import { contentCardVariants } from "@/components/TempDesignSystem/ContentCard/variants" + +import { ImageVaultAsset } from "@/types/components/imageVault" +import type { CardProps } from "@/components/TempDesignSystem/Card/card" + +interface SidePeekButton { + title: string +} + +export interface ContentCardProps + extends VariantProps { + title: string + description: string + primaryButton?: CardProps["primaryButton"] + secondaryButton?: CardProps["secondaryButton"] + sidePeekButton?: SidePeekButton + backgroundImage?: ImageVaultAsset + className?: string +} diff --git a/types/components/languageSwitcher/languageSwitcher.ts b/types/components/languageSwitcher/languageSwitcher.ts index 6672fbe83..312d28712 100644 --- a/types/components/languageSwitcher/languageSwitcher.ts +++ b/types/components/languageSwitcher/languageSwitcher.ts @@ -1,6 +1,25 @@ +import { ReactElement } from "react" + import type { LanguageSwitcherData } from "@/types/requests/languageSwitcher" +export enum LanguageSwitcherTypesEnum { + MobileHeader = "mobileHeader", + DesktopHeader = "desktopHeader", + Footer = "footer", +} + +export type LanguageSwitcherTypes = `${LanguageSwitcherTypesEnum}` + export interface LanguageSwitcherProps { - type: "mobileHeader" | "desktopHeader" | "footer" + type: LanguageSwitcherTypes urls: LanguageSwitcherData } + +export interface LanguageSwitcherContentProps { + urls: LanguageSwitcherData +} + +export interface LanguageSwitcherContainerProps { + type: LanguageSwitcherTypes + children: ReactElement +}