Merged in feature/SW-3595-sas-info-boxes (pull request #3177)

Feature/SW-3595 Add info boxes to SAS start page & Eurobonus alert to select-hotel page on SAS

* wip

* feat(SW-3595): Add info boxes to SAS start page

* Add InfoBox to design-system
* Add background gradient to SAS start page

* update variable naming and conditionalize the eurobonus message on select-hotel

* SAS startpage update default message

* make select-hotel a bit more generic with slot={} instead of alert={}


Approved-by: Anton Gunnarsson
This commit is contained in:
Joakim Jäderberg
2025-11-19 10:50:04 +00:00
parent 32e5c8d357
commit db30588f63
15 changed files with 459 additions and 105 deletions

View File

@@ -1,8 +1,11 @@
import { SelectHotelPage as SelectHotelPagePrimitive } from "@scandic-hotels/booking-flow/pages/SelectHotelPage"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { toCapitalCase } from "@scandic-hotels/common/utils/toCapitalCase"
import { Alert } from "@scandic-hotels/design-system/Alert"
import { bookingFlowConfig } from "@/constants/bookingFlowConfig"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import type { Metadata } from "next"
@@ -26,12 +29,29 @@ export async function generateMetadata({
export default async function SelectHotelPage(props: PageArgs<LangParams>) {
const searchParams = await props.searchParams
const lang = await getLang()
const intl = await getIntl()
return (
<SelectHotelPagePrimitive
lang={lang}
searchParams={searchParams}
config={bookingFlowConfig}
topSlot={
bookingFlowConfig.redemptionEnabled ? (
<Alert
heading={intl.formatMessage({
id: "selectHotel.earnEuroBonusPointsAlert.heading",
defaultMessage: "Earn & use EuroBonus points",
})}
text={intl.formatMessage({
id: "selectHotel.earnEuroBonusPointsAlert.text",
defaultMessage:
"Collect new points with every booking, or use your current points to pay for hotel stays.",
})}
type={AlertTypeEnum.Info}
/>
) : undefined
}
/>
)
}

View File

@@ -1,11 +1,42 @@
.mainContent {
/* Calculate height for large screens and displays */
height: calc(100dvh - 402px);
height: calc(100dvh - 100px);
min-height: 480px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
background: linear-gradient(
color-mix(in srgb, var(--Scandic-Grey-100) 14%, transparent),
color-mix(in srgb, var(--Scandic-Red-100) 40%, transparent)
);
}
.contentContainer {
display: flex;
flex-direction: column;
gap: var(--Space-x3);
height: 100%;
justify-content: space-evenly;
@media (min-width: 768px) {
justify-content: center;
}
}
.bookingWidgetWrapper {
display: flex;
flex-direction: column;
gap: var(--Space-x3);
}
.heading {
text-transform: uppercase;
text-align: center;
text-wrap: balance;
color: white;
text-shadow: black 0px 0px 16px;
}
.backdrop {
@@ -15,4 +46,17 @@
height: 100%;
width: 100%;
object-fit: cover;
z-index: -1;
}
.infoBoxes {
width: var(--max-width-content);
margin: 0 auto;
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: var(--Space-x2);
@media (min-width: 768px) {
gap: var(--Space-x3);
grid-template-columns: repeat(2, 1fr);
}
}

View File

@@ -1,10 +1,14 @@
import { FloatingBookingWidget } from "@scandic-hotels/booking-flow/BookingWidget/FloatingBookingWidget"
import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url"
import { IconName } from "@scandic-hotels/design-system/Icons/iconName"
import Image from "@scandic-hotels/design-system/Image"
import { InfoBox } from "@scandic-hotels/design-system/InfoBox"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { bookingFlowConfig } from "@/constants/bookingFlowConfig"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import LandingPageHeroImage from "@/public/_static/img/landing-page-hero.png"
@@ -18,6 +22,7 @@ export default async function Home(props: PageArgs<LangParams>) {
const booking = parseBookingWidgetSearchParams(searchParams)
const lang = await getLang()
const intl = await getIntl()
const trackingData = {
pageName: "startpage",
@@ -31,12 +36,52 @@ export default async function Home(props: PageArgs<LangParams>) {
return (
<>
<section className={styles.mainContent}>
<div className={styles.bookingWidgetWrapper}>
<FloatingBookingWidget
booking={booking}
lang={lang}
config={bookingFlowConfig}
/>
<div className={styles.contentContainer}>
<section className={styles.bookingWidgetWrapper}>
<Typography variant={"Title/lg"}>
<h1 className={styles.heading}>
{intl.formatMessage({
id: "partnerSas.startPage.heading",
defaultMessage: "Book a hotel at the best price",
})}
</h1>
</Typography>
<FloatingBookingWidget
booking={booking}
lang={lang}
config={bookingFlowConfig}
/>
</section>
{bookingFlowConfig.redemptionEnabled && (
<section className={styles.infoBoxes}>
<InfoBox
heading={intl.formatMessage({
id: "partnerSas.startPage.infoBox1.heading",
defaultMessage: "Earn points",
})}
text={intl.formatMessage({
id: "partnerSas.startPage.infoBox1.text",
defaultMessage:
"Collect new SAS EuroBonus points with your bookings.",
})}
theme={"SAS-Blue"}
icon={IconName.Diamond}
/>
<InfoBox
heading={intl.formatMessage({
id: "partnerSas.startPage.infoBox2.heading",
defaultMessage: "Pay with points",
})}
text={intl.formatMessage({
id: "partnerSas.startPage.infoBox2.text",
defaultMessage:
"Then use your points to pay for your next Scandic stay!",
})}
theme={"SAS-Blue"}
icon={IconName.CreditCard}
/>
</section>
)}
</div>
<Image
alt="Hero Image"