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:
@@ -1,7 +1,6 @@
|
||||
.floatingBookingWidget {
|
||||
width: var(--max-width-content);
|
||||
margin: 0 auto;
|
||||
min-height: 88px;
|
||||
position: relative;
|
||||
|
||||
.floatingBackground {
|
||||
@@ -25,9 +24,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) and (max-width: 1366px) {
|
||||
.floatingBookingWidget {
|
||||
min-height: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ export function FloatingBookingWidgetClient(props: Props) {
|
||||
useEffect(() => {
|
||||
observerRef.current = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
const hasScrolledPastTop = entry.boundingClientRect.top < 0
|
||||
const hasScrolledPastTop = entry.boundingClientRect.bottom < 0
|
||||
setStickyTop(hasScrolledPastTop)
|
||||
},
|
||||
{ threshold: 0, rootMargin: "0px 0px -100% 0px" }
|
||||
{ threshold: 0, rootMargin: "0px 0px 0% 0px" }
|
||||
)
|
||||
|
||||
if (containerRef.current) {
|
||||
|
||||
@@ -32,6 +32,7 @@ interface SelectHotelProps {
|
||||
isBookingCodeRateAvailable?: boolean
|
||||
title: ReactNode
|
||||
lang: Lang
|
||||
topSlot?: ReactNode
|
||||
}
|
||||
|
||||
export function SelectHotel({
|
||||
@@ -42,6 +43,7 @@ export function SelectHotel({
|
||||
isBookingCodeRateAvailable = false,
|
||||
title,
|
||||
lang,
|
||||
topSlot,
|
||||
}: SelectHotelProps) {
|
||||
const isAllUnavailable = hotels.every(
|
||||
(hotel) => hotel.availability.status !== "Available"
|
||||
@@ -83,54 +85,60 @@ export function SelectHotel({
|
||||
</div>
|
||||
</header>
|
||||
<main className={styles.main}>
|
||||
{showBookingCodeFilter ? <BookingCodeFilter /> : null}
|
||||
<div className={styles.sideBar}>
|
||||
{hotels.length ? (
|
||||
<Link
|
||||
className={styles.link}
|
||||
href={
|
||||
isAlternative
|
||||
? alternativeHotelsMap(lang)
|
||||
: selectHotelMap(lang)
|
||||
}
|
||||
keepSearchParams
|
||||
>
|
||||
<MapWithButtonWrapper>
|
||||
{topSlot && <div className={styles.topSlotContainer}>{topSlot}</div>}
|
||||
<div className={styles.availabilityContainer}>
|
||||
{showBookingCodeFilter ? <BookingCodeFilter /> : null}
|
||||
<div className={styles.sideBar}>
|
||||
{hotels.length ? (
|
||||
<Link
|
||||
className={styles.link}
|
||||
href={
|
||||
isAlternative
|
||||
? alternativeHotelsMap(lang)
|
||||
: selectHotelMap(lang)
|
||||
}
|
||||
keepSearchParams
|
||||
>
|
||||
<MapWithButtonWrapper>
|
||||
<StaticMap
|
||||
city={city.name}
|
||||
country={isCityWithCountry(city) ? city.country : undefined}
|
||||
width={340}
|
||||
height={200}
|
||||
zoomLevel={11}
|
||||
mapType="roadmap"
|
||||
altText={`Map of ${city.name} city center`}
|
||||
/>
|
||||
</MapWithButtonWrapper>
|
||||
</Link>
|
||||
) : (
|
||||
<div className={styles.mapContainer}>
|
||||
<StaticMap
|
||||
city={city.name}
|
||||
country={isCityWithCountry(city) ? city.country : undefined}
|
||||
width={340}
|
||||
height={200}
|
||||
zoomLevel={11}
|
||||
mapType="roadmap"
|
||||
altText={`Map of ${city.name} city center`}
|
||||
/>
|
||||
</MapWithButtonWrapper>
|
||||
</Link>
|
||||
) : (
|
||||
<div className={styles.mapContainer}>
|
||||
<StaticMap
|
||||
city={city.name}
|
||||
width={340}
|
||||
height={200}
|
||||
zoomLevel={11}
|
||||
mapType="roadmap"
|
||||
altText={`Map of ${city.name} city center`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<HotelFilter filters={filterList} className={styles.filter} />
|
||||
</div>
|
||||
<div className={styles.hotelList}>
|
||||
<NoAvailabilityAlert
|
||||
hotelsLength={hotels.length}
|
||||
isAlternative={isAlternative}
|
||||
isAllUnavailable={isAllUnavailable}
|
||||
operaId={hotels?.[0]?.hotel.operaId}
|
||||
bookingCode={bookingCode}
|
||||
isBookingCodeRateNotAvailable={!isBookingCodeRateAvailable}
|
||||
/>
|
||||
<HotelCardListing hotelData={hotels} isAlternative={isAlternative} />
|
||||
</div>
|
||||
)}
|
||||
<HotelFilter filters={filterList} className={styles.filter} />
|
||||
</div>
|
||||
<div className={styles.hotelList}>
|
||||
<NoAvailabilityAlert
|
||||
hotelsLength={hotels.length}
|
||||
isAlternative={isAlternative}
|
||||
isAllUnavailable={isAllUnavailable}
|
||||
operaId={hotels?.[0]?.hotel.operaId}
|
||||
bookingCode={bookingCode}
|
||||
isBookingCodeRateNotAvailable={!isBookingCodeRateAvailable}
|
||||
/>
|
||||
<HotelCardListing
|
||||
hotelData={hotels}
|
||||
isAlternative={isAlternative}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Space-x5);
|
||||
justify-items: center;
|
||||
padding-top: var(--Space-x4);
|
||||
}
|
||||
|
||||
.topSlotContainer {
|
||||
width: var(--max-width-page);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.availabilityContainer {
|
||||
display: flex;
|
||||
background-color: var(--Scandic-Brand-Warm-White);
|
||||
min-height: min(100dvh, 750px);
|
||||
flex-direction: column;
|
||||
max-width: var(--max-width-page);
|
||||
width: var(--max-width-page);
|
||||
margin: 0 auto;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
flex-direction: row;
|
||||
gap: var(--Space-x5);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: var(--Space-x3) 0 var(--Space-x2);
|
||||
|
||||
@media (min-width: 768px) {
|
||||
background-color: var(--Base-Surface-Subtle-Normal);
|
||||
padding: var(--Space-x4) 0 var(--Space-x3);
|
||||
}
|
||||
}
|
||||
|
||||
.headerContent {
|
||||
@@ -17,6 +41,9 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Space-x2);
|
||||
@media (min-width: 768px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.cityInformation {
|
||||
@@ -28,19 +55,37 @@
|
||||
|
||||
.sorter {
|
||||
display: none;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
display: block;
|
||||
width: 339px;
|
||||
}
|
||||
}
|
||||
|
||||
.sideBar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
max-width: 340px;
|
||||
}
|
||||
}
|
||||
|
||||
.sideBarItem {
|
||||
display: none;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
display: none;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
display: flex;
|
||||
margin-bottom: var(--Space-x6);
|
||||
}
|
||||
}
|
||||
|
||||
.hotelList {
|
||||
@@ -56,59 +101,26 @@
|
||||
|
||||
.skeletonContainer .title {
|
||||
margin-bottom: var(--Space-x3);
|
||||
|
||||
@media (min-width: 768px) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.main {
|
||||
padding: var(--Space-x5) 0;
|
||||
flex-direction: row;
|
||||
gap: var(--Space-x5);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.headerContent {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: var(--Base-Surface-Subtle-Normal);
|
||||
padding: var(--Space-x4) 0 var(--Space-x3);
|
||||
}
|
||||
|
||||
.sorter {
|
||||
display: block;
|
||||
width: 339px;
|
||||
}
|
||||
|
||||
.title {
|
||||
.title {
|
||||
@media (min-width: 768px) {
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
max-width: var(--max-width-navigation);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.sideBar {
|
||||
max-width: 340px;
|
||||
}
|
||||
|
||||
.sideBarItem {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.filter {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
margin-bottom: var(--Space-x6);
|
||||
}
|
||||
|
||||
.skeletonContainer .title {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.skeletonContainer .sideBar {
|
||||
gap: var(--Space-x3);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { getSelectHotelTracking } from "../misc/selectHotelTracking"
|
||||
import { parseSelectHotelSearchParams } from "../utils/url"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
import type { ReactNode } from "react"
|
||||
|
||||
import type { NextSearchParams } from "../types"
|
||||
|
||||
@@ -23,10 +24,12 @@ export async function SelectHotelPage({
|
||||
lang,
|
||||
searchParams,
|
||||
config,
|
||||
topSlot,
|
||||
}: {
|
||||
lang: Lang
|
||||
searchParams: NextSearchParams
|
||||
config: BookingFlowConfig
|
||||
topSlot?: ReactNode
|
||||
}) {
|
||||
const booking = parseSelectHotelSearchParams(searchParams)
|
||||
|
||||
@@ -111,6 +114,7 @@ export async function SelectHotelPage({
|
||||
hotels={hotels}
|
||||
title={city.name}
|
||||
lang={lang}
|
||||
topSlot={topSlot}
|
||||
/>
|
||||
|
||||
<TrackingSDK hotelInfo={hotelsTrackingData} pageData={pageTrackingData} />
|
||||
|
||||
Reference in New Issue
Block a user