Merge branch 'develop' into test
This commit is contained in:
@@ -5,9 +5,9 @@ import styles from "./layout.module.css"
|
||||
export default async function MyPagesLayout({
|
||||
breadcrumbs,
|
||||
children,
|
||||
}: React.PropsWithChildren & {
|
||||
}: React.PropsWithChildren<{
|
||||
breadcrumbs: React.ReactNode
|
||||
}) {
|
||||
}>) {
|
||||
return (
|
||||
<section className={styles.layout}>
|
||||
{breadcrumbs}
|
||||
|
||||
@@ -23,7 +23,7 @@ export default async function CreditCardSlot({ params }: PageArgs<LangParams>) {
|
||||
<section className={styles.container}>
|
||||
<article className={styles.content}>
|
||||
<Subtitle type="two" color="black">
|
||||
{formatMessage({ id: "My credit cards" })}
|
||||
{formatMessage({ id: "My payment cards" })}
|
||||
</Subtitle>
|
||||
<Body color="black">
|
||||
{formatMessage({
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
font-family: var(--typography-Body-Regular-fontFamily);
|
||||
gap: var(--Spacing-x3);
|
||||
grid-template-rows: auto 1fr;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import ContentPage from "@/components/ContentType/ContentPage"
|
||||
import HotelPage from "@/components/ContentType/HotelPage"
|
||||
import LoyaltyPage from "@/components/ContentType/LoyaltyPage"
|
||||
@@ -21,10 +23,16 @@ export default async function ContentTypePage({
|
||||
|
||||
switch (params.contentType) {
|
||||
case "content-page":
|
||||
if (env.HIDE_FOR_NEXT_RELEASE) {
|
||||
return notFound()
|
||||
}
|
||||
return <ContentPage />
|
||||
case "loyalty-page":
|
||||
return <LoyaltyPage />
|
||||
case "hotel-page":
|
||||
if (env.HIDE_FOR_NEXT_RELEASE) {
|
||||
return notFound()
|
||||
}
|
||||
return <HotelPage />
|
||||
default:
|
||||
const type: never = params.contentType
|
||||
|
||||
27
app/[lang]/(live)/(public)/hotelreservation/README.md
Normal file
27
app/[lang]/(live)/(public)/hotelreservation/README.md
Normal file
@@ -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.
|
||||
@@ -1,7 +1,3 @@
|
||||
.hotelInfo {
|
||||
margin-bottom: 64px;
|
||||
}
|
||||
|
||||
.page {
|
||||
min-height: 100dvh;
|
||||
padding-top: var(--Spacing-x6);
|
||||
@@ -12,6 +8,18 @@
|
||||
|
||||
.content {
|
||||
max-width: 1134px;
|
||||
margin-top: var(--Spacing-x5);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: var(--Spacing-x7);
|
||||
}
|
||||
|
||||
.main {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.summary {
|
||||
max-width: 340px;
|
||||
}
|
||||
181
app/[lang]/(live)/(public)/hotelreservation/[section]/page.tsx
Normal file
181
app/[lang]/(live)/(public)/hotelreservation/[section]/page.tsx
Normal file
@@ -0,0 +1,181 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
import tempHotelData from "@/server/routers/hotels/tempHotelData.json"
|
||||
|
||||
import BedSelection from "@/components/HotelReservation/SelectRate/BedSelection"
|
||||
import BreakfastSelection from "@/components/HotelReservation/SelectRate/BreakfastSelection"
|
||||
import Details from "@/components/HotelReservation/SelectRate/Details"
|
||||
import Payment from "@/components/HotelReservation/SelectRate/Payment"
|
||||
import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection"
|
||||
import SectionAccordion from "@/components/HotelReservation/SelectRate/SectionAccordion"
|
||||
import Summary from "@/components/HotelReservation/SelectRate/Summary"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import { SectionPageProps } from "@/types/components/hotelReservation/selectRate/section"
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
const bedAlternatives = [
|
||||
{
|
||||
value: "queen",
|
||||
name: "Queen bed",
|
||||
payment: "160 cm",
|
||||
pricePerNight: 0,
|
||||
membersPricePerNight: 0,
|
||||
currency: "SEK",
|
||||
},
|
||||
{
|
||||
value: "king",
|
||||
name: "King bed",
|
||||
payment: "160 cm",
|
||||
pricePerNight: 0,
|
||||
membersPricePerNight: 0,
|
||||
currency: "SEK",
|
||||
},
|
||||
{
|
||||
value: "twin",
|
||||
name: "Twin bed",
|
||||
payment: "90 cm + 90 cm",
|
||||
pricePerNight: 82,
|
||||
membersPricePerNight: 67,
|
||||
currency: "SEK",
|
||||
},
|
||||
]
|
||||
|
||||
const breakfastAlternatives = [
|
||||
{
|
||||
value: "no",
|
||||
name: "No breakfast",
|
||||
payment: "Always cheeper to get it online",
|
||||
pricePerNight: 0,
|
||||
currency: "SEK",
|
||||
},
|
||||
{
|
||||
value: "buffe",
|
||||
name: "Breakfast buffé",
|
||||
payment: "Always cheeper to get it online",
|
||||
pricePerNight: 150,
|
||||
currency: "SEK",
|
||||
},
|
||||
]
|
||||
|
||||
const getFlexibilityMessage = (value: string) => {
|
||||
switch (value) {
|
||||
case "non-refundable":
|
||||
return "Non refundable"
|
||||
case "free-rebooking":
|
||||
return "Free rebooking"
|
||||
case "free-cancellation":
|
||||
return "Free cancellation"
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export default async function SectionsPage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams & { section: string }, SectionPageProps>) {
|
||||
setLang(params.lang)
|
||||
|
||||
// TODO: Use real endpoint.
|
||||
const hotel = tempHotelData.data.attributes
|
||||
|
||||
const rooms = await serverClient().hotel.rates.get({
|
||||
// TODO: pass the correct hotel ID and all other parameters that should be included in the search
|
||||
hotelId: "1",
|
||||
})
|
||||
const intl = await getIntl()
|
||||
|
||||
const selectedBed = searchParams.bed
|
||||
? bedAlternatives.find((a) => a.value === searchParams.bed)?.name
|
||||
: undefined
|
||||
|
||||
const selectedBreakfast = searchParams.breakfast
|
||||
? breakfastAlternatives.find((a) => a.value === searchParams.breakfast)
|
||||
?.name
|
||||
: undefined
|
||||
|
||||
const selectedRoom = searchParams.roomClass
|
||||
? rooms.find((room) => room.id.toString() === searchParams.roomClass)?.name
|
||||
: undefined
|
||||
const selectedFlexibility = searchParams.flexibility
|
||||
? getFlexibilityMessage(searchParams.flexibility)
|
||||
: undefined
|
||||
|
||||
const currentSearchParams = new URLSearchParams(searchParams).toString()
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* TODO: Add Hotel Listing Card */}
|
||||
<div>Hotel Listing Card TBI</div>
|
||||
|
||||
<div className={styles.content}>
|
||||
<div className={styles.main}>
|
||||
<SectionAccordion
|
||||
header={intl.formatMessage({ id: "Room & Terms" })}
|
||||
selection={
|
||||
selectedRoom
|
||||
? [
|
||||
selectedRoom,
|
||||
intl.formatMessage({ id: selectedFlexibility }),
|
||||
]
|
||||
: undefined
|
||||
}
|
||||
path={`select-rate?${currentSearchParams}`}
|
||||
>
|
||||
{params.section === "select-rate" && (
|
||||
<RoomSelection
|
||||
alternatives={rooms}
|
||||
nextPath="select-bed"
|
||||
// TODO: Get real value
|
||||
nrOfNights={1}
|
||||
// TODO: Get real value
|
||||
nrOfAdults={1}
|
||||
/>
|
||||
)}
|
||||
</SectionAccordion>
|
||||
<SectionAccordion
|
||||
header={intl.formatMessage({ id: "Bed type" })}
|
||||
selection={selectedBed}
|
||||
path={`select-bed?${currentSearchParams}`}
|
||||
>
|
||||
{params.section === "select-bed" && (
|
||||
<BedSelection
|
||||
nextPath="breakfast"
|
||||
alternatives={bedAlternatives}
|
||||
/>
|
||||
)}
|
||||
</SectionAccordion>
|
||||
<SectionAccordion
|
||||
header={intl.formatMessage({ id: "Breakfast" })}
|
||||
selection={selectedBreakfast}
|
||||
path={`breakfast?${currentSearchParams}`}
|
||||
>
|
||||
{params.section === "breakfast" && (
|
||||
<BreakfastSelection
|
||||
alternatives={breakfastAlternatives}
|
||||
nextPath="details"
|
||||
/>
|
||||
)}
|
||||
</SectionAccordion>
|
||||
<SectionAccordion
|
||||
header={intl.formatMessage({ id: "Your details" })}
|
||||
path={`details?${currentSearchParams}`}
|
||||
>
|
||||
{params.section === "details" && <Details nextPath="payment" />}
|
||||
</SectionAccordion>
|
||||
<SectionAccordion
|
||||
header={intl.formatMessage({ id: "Payment info" })}
|
||||
path={`payment?${currentSearchParams}`}
|
||||
>
|
||||
{params.section === "payment" && <Payment />}
|
||||
</SectionAccordion>
|
||||
</div>
|
||||
<div className={styles.summary}>
|
||||
<Summary />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import styles from "./layout.module.css"
|
||||
|
||||
import { LangParams, LayoutArgs } from "@/types/params"
|
||||
@@ -5,5 +9,8 @@ import { LangParams, LayoutArgs } from "@/types/params"
|
||||
export default function HotelReservationLayout({
|
||||
children,
|
||||
}: React.PropsWithChildren<LayoutArgs<LangParams>>) {
|
||||
if (env.HIDE_FOR_NEXT_RELEASE) {
|
||||
return notFound()
|
||||
}
|
||||
return <div className={styles.layout}>{children}</div>
|
||||
}
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
.main {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(min-content, max-content));
|
||||
display: flex;
|
||||
gap: var(--Spacing-x4);
|
||||
padding: var(--Spacing-x4) var(--Spacing-x4) 0 var(--Spacing-x4);
|
||||
height: 100dvh;
|
||||
background-color: var(--Scandic-Brand-Warm-White);
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
.hotelCards {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x4);
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x0);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
import tempHotelData from "@/server/routers/hotels/tempHotelData.json"
|
||||
|
||||
import HotelCard from "@/components/HotelReservation/HotelCard"
|
||||
import HotelCardListing from "@/components/HotelReservation/HotelCardListing"
|
||||
import HotelFilter from "@/components/HotelReservation/SelectHotel/HotelFilter"
|
||||
import { ChevronRightIcon } from "@/components/Icons"
|
||||
import StaticMap from "@/components/Maps/StaticMap"
|
||||
@@ -11,45 +10,98 @@ import { getLang, setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import { AvailabilityInput } from "@/types/components/hotelReservation/selectHotel/availabilityInput"
|
||||
import { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
async function getAvailableHotels(
|
||||
input: AvailabilityInput
|
||||
): Promise<HotelData[]> {
|
||||
const getAvailableHotels = await serverClient().hotel.availability.get(input)
|
||||
|
||||
if (!getAvailableHotels) throw new Error()
|
||||
|
||||
const { availability } = getAvailableHotels
|
||||
|
||||
const hotels = availability.map(async (hotel) => {
|
||||
const hotelData = await serverClient().hotel.hotelData.get({
|
||||
hotelId: hotel.hotelId.toString(),
|
||||
language: getLang(),
|
||||
})
|
||||
|
||||
if (!hotelData) throw new Error()
|
||||
|
||||
return {
|
||||
hotelData: hotelData.data.attributes,
|
||||
price: hotel.bestPricePerNight,
|
||||
}
|
||||
})
|
||||
|
||||
return await Promise.all(hotels)
|
||||
}
|
||||
|
||||
export default async function SelectHotelPage({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
const intl = await getIntl()
|
||||
setLang(params.lang)
|
||||
|
||||
// TODO: Use real endpoint.
|
||||
const hotel = tempHotelData.data.attributes
|
||||
const hotels = [hotel]
|
||||
const tempSearchTerm = "Stockholm"
|
||||
const intl = await getIntl()
|
||||
|
||||
const hotelFilters = await serverClient().hotel.filters.get({
|
||||
hotelId: "879",
|
||||
const hotels = await getAvailableHotels({
|
||||
cityId: "8ec4bba3-1c38-4606-82d1-bbe3f6738e54",
|
||||
roomStayStartDate: "2024-11-02",
|
||||
roomStayEndDate: "2024-11-03",
|
||||
adults: 1,
|
||||
})
|
||||
|
||||
const tempSearchTerm = "Stockholm"
|
||||
const filters = hotels.flatMap((data) => data.hotelData.detailedFacilities)
|
||||
|
||||
const filterIds = [...new Set(filters.map((data) => data.id))]
|
||||
const filterList: {
|
||||
name: string
|
||||
id: number
|
||||
applyToAllHotels: boolean
|
||||
public: boolean
|
||||
icon: string
|
||||
sortOrder: number
|
||||
code?: string
|
||||
iconName?: string
|
||||
}[] = filterIds
|
||||
.map((id) => filters.find((find) => find.id === id))
|
||||
.filter(
|
||||
(
|
||||
filter
|
||||
): filter is {
|
||||
name: string
|
||||
id: number
|
||||
applyToAllHotels: boolean
|
||||
public: boolean
|
||||
icon: string
|
||||
sortOrder: number
|
||||
code?: string
|
||||
iconName?: string
|
||||
} => filter !== undefined
|
||||
)
|
||||
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<section>
|
||||
<section className={styles.section}>
|
||||
<StaticMap
|
||||
city={tempSearchTerm}
|
||||
width={340}
|
||||
height={180}
|
||||
zoomLevel={11}
|
||||
mapType="roadmap"
|
||||
altText={`Map of ${tempSearchTerm} city center`}
|
||||
/>
|
||||
<Link className={styles.link} color="burgundy" href="#">
|
||||
{intl.formatMessage({ id: "Show map" })}
|
||||
<ChevronRightIcon color="burgundy" className={styles.icon} />
|
||||
<ChevronRightIcon color="burgundy" />
|
||||
</Link>
|
||||
<HotelFilter filters={hotelFilters} />
|
||||
</section>
|
||||
<section className={styles.hotelCards}>
|
||||
{hotels.map((hotel) => (
|
||||
<HotelCard key={hotel.name} hotel={hotel} />
|
||||
))}
|
||||
<HotelFilter filters={filterList} />
|
||||
</section>
|
||||
<HotelCardListing hotelData={hotels} />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
import tempHotelData from "@/server/routers/hotels/tempHotelData.json"
|
||||
|
||||
import HotelCard from "@/components/HotelReservation/HotelCard"
|
||||
import BedSelection from "@/components/HotelReservation/SelectRate/BedSelection"
|
||||
import BreakfastSelection from "@/components/HotelReservation/SelectRate/BreakfastSelection"
|
||||
import FlexibilitySelection from "@/components/HotelReservation/SelectRate/FlexibilitySelection"
|
||||
import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SelectRate({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
// TODO: Use real endpoint.
|
||||
const hotel = tempHotelData.data.attributes
|
||||
|
||||
const rooms = await serverClient().hotel.rates.get({
|
||||
// TODO: pass the correct hotel ID and all other parameters that should be included in the search
|
||||
hotelId: "1",
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<main className={styles.content}>
|
||||
<div className={styles.hotelInfo}>
|
||||
<HotelCard hotel={hotel} />
|
||||
</div>
|
||||
<RoomSelection rooms={rooms} />
|
||||
<FlexibilitySelection />
|
||||
<BreakfastSelection />
|
||||
<BedSelection />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
1
app/[lang]/(live)/@bookingwidget/[...paths]/page.tsx
Normal file
1
app/[lang]/(live)/@bookingwidget/[...paths]/page.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from "../page"
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "../../page"
|
||||
1
app/[lang]/(live)/@bookingwidget/default.tsx
Normal file
1
app/[lang]/(live)/@bookingwidget/default.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from "./page"
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "../../page"
|
||||
17
app/[lang]/(live)/@bookingwidget/page.tsx
Normal file
17
app/[lang]/(live)/@bookingwidget/page.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import BookingWidget from "@/components/BookingWidget"
|
||||
|
||||
export default async function BookingWidgetPage() {
|
||||
// Get the booking widget show/hide status based on page specific settings
|
||||
const bookingWidgetToggle =
|
||||
await serverClient().contentstack.bookingwidget.getToggle()
|
||||
|
||||
return (
|
||||
<>
|
||||
{bookingWidgetToggle && bookingWidgetToggle.hideBookingWidget ? null : (
|
||||
<BookingWidget />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { baseUrls } from "@/constants/routes/baseUrls"
|
||||
|
||||
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
||||
|
||||
export default function Error() {
|
||||
return <LanguageSwitcher urls={baseUrls} />
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function LanguageSwitcherRoute({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const data = await serverClient().contentstack.languageSwitcher.get()
|
||||
if (!data) {
|
||||
return null
|
||||
}
|
||||
return <LanguageSwitcher urls={data.urls} />
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function MyPagesMobileDropdownPage({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
const navigation = await serverClient().contentstack.myPages.navigation.get()
|
||||
if (!navigation) return null
|
||||
return <MyPagesMobileDropdown navigation={navigation} />
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import Header from "@/components/Current/Header"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, LayoutArgs } from "@/types/params"
|
||||
|
||||
export default function HeaderLayout({
|
||||
languageSwitcher,
|
||||
myPagesMobileDropdown,
|
||||
params,
|
||||
}: LayoutArgs<LangParams> & {
|
||||
languageSwitcher: React.ReactNode
|
||||
myPagesMobileDropdown: React.ReactNode
|
||||
}) {
|
||||
setLang(params.lang)
|
||||
return (
|
||||
<Header
|
||||
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||
languageSwitcher={languageSwitcher}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1 @@
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default function EmptyHeaderPage({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
return null
|
||||
}
|
||||
export { default } from "../page"
|
||||
|
||||
1
app/[lang]/(live)/@header/[contentType]/[uid]/page.tsx
Normal file
1
app/[lang]/(live)/@header/[contentType]/[uid]/page.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from "../../page"
|
||||
1
app/[lang]/(live)/@header/default.tsx
Normal file
1
app/[lang]/(live)/@header/default.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from "./page"
|
||||
1
app/[lang]/(live)/@header/my-pages/[...path]/page.tsx
Normal file
1
app/[lang]/(live)/@header/my-pages/[...path]/page.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from "../../page"
|
||||
@@ -1,21 +1,17 @@
|
||||
import { baseUrls } from "@/constants/routes/baseUrls"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import Header from "@/components/Current/Header"
|
||||
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
import CurrentHeader from "@/components/Current/Header"
|
||||
import Header from "@/components/Header"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function HeaderPage({ params }: PageArgs<LangParams>) {
|
||||
export default function HeaderPage({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const navigation = await serverClient().contentstack.myPages.navigation.get()
|
||||
return (
|
||||
<Header
|
||||
myPagesMobileDropdown={<MyPagesMobileDropdown navigation={navigation} />}
|
||||
languageSwitcher={<LanguageSwitcher urls={baseUrls} />}
|
||||
/>
|
||||
)
|
||||
if (env.HIDE_FOR_NEXT_RELEASE) {
|
||||
return <CurrentHeader />
|
||||
}
|
||||
|
||||
return <Header />
|
||||
}
|
||||
|
||||
@@ -2,13 +2,17 @@ import "@/app/globals.css"
|
||||
import "@scandic-hotels/design-system/style.css"
|
||||
|
||||
import Script from "next/script"
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { env } from "@/env/server"
|
||||
import TrpcProvider from "@/lib/trpc/Provider"
|
||||
|
||||
import TokenRefresher from "@/components/Auth/TokenRefresher"
|
||||
import AdobeSDKScript from "@/components/Current/AdobeSDKScript"
|
||||
import Footer from "@/components/Current/Footer"
|
||||
import CurrentFooter from "@/components/Current/Footer"
|
||||
import VwoScript from "@/components/Current/VwoScript"
|
||||
import Footer from "@/components/Footer"
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
import { ToastHandler } from "@/components/TempDesignSystem/Toasts"
|
||||
import { preloadUserTracking } from "@/components/TrackingSDK"
|
||||
import { getIntl } from "@/i18n"
|
||||
@@ -21,9 +25,11 @@ export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
header,
|
||||
bookingwidget,
|
||||
}: React.PropsWithChildren<
|
||||
LayoutArgs<LangParams> & {
|
||||
header: React.ReactNode
|
||||
bookingwidget: React.ReactNode
|
||||
}
|
||||
>) {
|
||||
setLang(params.lang)
|
||||
@@ -52,9 +58,12 @@ export default async function RootLayout({
|
||||
<ServerIntlProvider intl={{ defaultLocale, locale, messages }}>
|
||||
<TrpcProvider>
|
||||
{header}
|
||||
{!env.HIDE_FOR_NEXT_RELEASE && <>{bookingwidget}</>}
|
||||
{children}
|
||||
<ToastHandler />
|
||||
<Footer />
|
||||
<Suspense fallback={<LoadingSpinner />}>
|
||||
{env.HIDE_FOR_NEXT_RELEASE ? <CurrentFooter /> : <Footer />}
|
||||
</Suspense>
|
||||
<TokenRefresher />
|
||||
</TrpcProvider>
|
||||
</ServerIntlProvider>
|
||||
|
||||
5
app/[lang]/(live)/loading.tsx
Normal file
5
app/[lang]/(live)/loading.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingSpinner />
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import Header from "@/components/Current/Header"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function HeaderPage({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
return <Header />
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function LanguageSwitcherRoute({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const data = await serverClient().contentstack.languageSwitcher.get()
|
||||
if (!data) {
|
||||
return null
|
||||
}
|
||||
return <LanguageSwitcher urls={data.urls} />
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { baseUrls } from "@/constants/routes/baseUrls"
|
||||
|
||||
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
||||
|
||||
export default function Error() {
|
||||
return <LanguageSwitcher urls={baseUrls} />
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function MyPagesMobileDropdownPage({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const navigation = await serverClient().contentstack.myPages.navigation.get()
|
||||
if (!navigation) {
|
||||
return null
|
||||
}
|
||||
return <MyPagesMobileDropdown navigation={navigation} />
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
|
||||
export default function Error() {
|
||||
return <MyPagesMobileDropdown navigation={null} />
|
||||
}
|
||||
@@ -4,9 +4,9 @@ import "@scandic-hotels/design-system/style.css"
|
||||
import Script from "next/script"
|
||||
|
||||
import TokenRefresher from "@/components/Auth/TokenRefresher"
|
||||
import BookingWidget from "@/components/BookingWidget"
|
||||
import AdobeScript from "@/components/Current/AdobeScript"
|
||||
import Footer from "@/components/Current/Footer"
|
||||
import Header from "@/components/Current/Header"
|
||||
import LangPopup from "@/components/Current/LangPopup"
|
||||
import SkipToMainContent from "@/components/SkipToMainContent"
|
||||
import { getIntl } from "@/i18n"
|
||||
@@ -26,12 +26,9 @@ export const metadata: Metadata = {
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
languageSwitcher,
|
||||
myPagesMobileDropdown,
|
||||
header,
|
||||
}: React.PropsWithChildren<
|
||||
LayoutArgs<LangParams> & { languageSwitcher: React.ReactNode } & {
|
||||
myPagesMobileDropdown: React.ReactNode
|
||||
}
|
||||
LayoutArgs<LangParams> & { header: React.ReactNode }
|
||||
>) {
|
||||
setLang(params.lang)
|
||||
const { defaultLocale, locale, messages } = await getIntl()
|
||||
@@ -67,10 +64,8 @@ export default async function RootLayout({
|
||||
<LangPopup />
|
||||
<SkipToMainContent />
|
||||
<ServerIntlProvider intl={{ defaultLocale, locale, messages }}>
|
||||
<Header
|
||||
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||
languageSwitcher={languageSwitcher}
|
||||
/>
|
||||
{header}
|
||||
<BookingWidget />
|
||||
{children}
|
||||
<Footer />
|
||||
<TokenRefresher />
|
||||
|
||||
Reference in New Issue
Block a user