Merged in feat/SW-1230-meeting-booking-widget (pull request #1507)
feat(SW-1230): Added meeting booking widget to hotel meeting pages * feat(SW-1230): Added meeting booking widget to hotel meeting pages Approved-by: Fredrik Thorsson
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useRef } from "react"
|
||||||
|
|
||||||
|
import { StickyElementNameEnum } from "@/stores/sticky-position"
|
||||||
|
|
||||||
|
import MeetingPackageWidget from "@/components/MeetingPackageWidget"
|
||||||
|
import useStickyPosition from "@/hooks/useStickyPosition"
|
||||||
|
|
||||||
|
import styles from "./meetingWidget.module.css"
|
||||||
|
|
||||||
|
interface MeetingWidgetProps {
|
||||||
|
hotelId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MeetingWidget({ hotelId }: MeetingWidgetProps) {
|
||||||
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
|
useStickyPosition({
|
||||||
|
ref,
|
||||||
|
name: StickyElementNameEnum.MEETING_BOOKING_WIDGET,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ref} className={styles.wrapper}>
|
||||||
|
<MeetingPackageWidget
|
||||||
|
hotelId={hotelId}
|
||||||
|
className={styles.meetingPackageWidget}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
.wrapper {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||||
|
box-shadow: 0px 16px 24px 0px rgba(0, 0, 0, 0.08);
|
||||||
|
z-index: var(--booking-widget-z-index);
|
||||||
|
}
|
||||||
|
|
||||||
|
.meetingPackageWidget {
|
||||||
|
width: 100%;
|
||||||
|
max-width: var(--max-width-page);
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
@@ -43,12 +43,6 @@
|
|||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.meetingBookingWidget {
|
|
||||||
padding: var(--Spacing-x4);
|
|
||||||
background-color: var(--Base-Surface-Primary-dark-Normal);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonContainer {
|
.buttonContainer {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
padding: var(--Spacing-x3) var(--Spacing-x2);
|
padding: var(--Spacing-x3) var(--Spacing-x2);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { getLang } from "@/i18n/serverContext"
|
|||||||
import MeetingsAdditionalContent from "./AdditionalContent/Meetings"
|
import MeetingsAdditionalContent from "./AdditionalContent/Meetings"
|
||||||
import HotelSubpageAdditionalContent from "./AdditionalContent"
|
import HotelSubpageAdditionalContent from "./AdditionalContent"
|
||||||
import HtmlContent from "./HtmlContent"
|
import HtmlContent from "./HtmlContent"
|
||||||
|
import { MeetingWidget } from "./MeetingWidget"
|
||||||
import HotelSubpageSidebar from "./Sidebar"
|
import HotelSubpageSidebar from "./Sidebar"
|
||||||
import { getSubpageData, verifySubpageShouldExist } from "./utils"
|
import { getSubpageData, verifySubpageShouldExist } from "./utils"
|
||||||
|
|
||||||
@@ -55,24 +56,19 @@ export default async function HotelSubpage({
|
|||||||
|
|
||||||
let meetingRooms
|
let meetingRooms
|
||||||
if (hotelData.additionalData.meetingRooms.nameInUrl === subpage) {
|
if (hotelData.additionalData.meetingRooms.nameInUrl === subpage) {
|
||||||
meetingRooms = await getMeetingRooms({ hotelId: hotelId, language: lang })
|
meetingRooms = await getMeetingRooms({ hotelId, language: lang })
|
||||||
}
|
}
|
||||||
|
|
||||||
const restaurantButton = restaurants.find(
|
const restaurantButton = restaurants.find(
|
||||||
(restaurant) => restaurant.nameInUrl === subpage
|
(restaurant) => restaurant.nameInUrl === subpage
|
||||||
)
|
)
|
||||||
|
|
||||||
const meetingBookingWidget = meetingRooms ? (
|
|
||||||
<div className={styles.meetingBookingWidget}>
|
|
||||||
Booking Widget Placeholder
|
|
||||||
</div>
|
|
||||||
) : null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section
|
<section
|
||||||
className={`${styles.hotelSubpage} ${restaurantButton?.bookTableUrl ? styles.hasStickyButton : ""} `}
|
className={`${styles.hotelSubpage} ${restaurantButton?.bookTableUrl ? styles.hasStickyButton : ""} `}
|
||||||
>
|
>
|
||||||
|
{meetingRooms && <MeetingWidget hotelId={hotelId} />}
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<Suspense fallback={<BreadcrumbsSkeleton />}>
|
<Suspense fallback={<BreadcrumbsSkeleton />}>
|
||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
@@ -81,9 +77,8 @@ export default async function HotelSubpage({
|
|||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
{pageData.heroImage || meetingBookingWidget ? (
|
{pageData.heroImage ? (
|
||||||
<div className={styles.heroWrapper}>
|
<div className={styles.heroWrapper}>
|
||||||
{meetingBookingWidget}
|
|
||||||
{pageData.heroImage && (
|
{pageData.heroImage && (
|
||||||
<Hero
|
<Hero
|
||||||
src={pageData.heroImage.src}
|
src={pageData.heroImage.src}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import SkeletonShimmer from "../../SkeletonShimmer"
|
||||||
|
|
||||||
|
import styles from "./skeleton.module.css"
|
||||||
|
|
||||||
|
export default function MeetingPackageWidgetSkeleton() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.mobile}>
|
||||||
|
<SkeletonShimmer height="40px" width="100%" />
|
||||||
|
</div>
|
||||||
|
<div className={styles.desktop}>
|
||||||
|
<SkeletonShimmer height="60px" width="30%" />
|
||||||
|
<SkeletonShimmer height="60px" width="22%" />
|
||||||
|
<SkeletonShimmer height="60px" width="12%" />
|
||||||
|
<SkeletonShimmer height="60px" width="12%" />
|
||||||
|
<SkeletonShimmer height="60px" width="12%" />
|
||||||
|
<SkeletonShimmer height="60px" width="12%" />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
.mobile,
|
||||||
|
.desktop {
|
||||||
|
padding: var(--Spacing-x2) 0;
|
||||||
|
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Meeting booking widget changes design at 948px */
|
||||||
|
@media screen and (min-width: 948px) {
|
||||||
|
.mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.desktop {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--Spacing-x2);
|
||||||
|
}
|
||||||
|
}
|
||||||
54
apps/scandic-web/components/MeetingPackageWidget/index.tsx
Normal file
54
apps/scandic-web/components/MeetingPackageWidget/index.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import Script from "next/script"
|
||||||
|
import { useState } from "react"
|
||||||
|
|
||||||
|
import useLang from "@/hooks/useLang"
|
||||||
|
|
||||||
|
import MeetingPackageWidgetSkeleton from "./Skeleton"
|
||||||
|
import { meetingPackageDestinationByHotelId } from "./utils"
|
||||||
|
|
||||||
|
import styles from "./meetingPackageWidget.module.css"
|
||||||
|
|
||||||
|
const SOURCE = "https://bookingengine-mp.s3.eu-west-2.amazonaws.com/script.js"
|
||||||
|
|
||||||
|
interface MeetingPackageWidgetProps {
|
||||||
|
hotelId?: string
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MeetingPackageWidget({
|
||||||
|
hotelId,
|
||||||
|
className = "",
|
||||||
|
}: MeetingPackageWidgetProps) {
|
||||||
|
const lang = useLang()
|
||||||
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
const destination = hotelId
|
||||||
|
? meetingPackageDestinationByHotelId[hotelId]
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
function handleOnReady() {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{isLoading && <MeetingPackageWidgetSkeleton />}
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="mp-booking-engine-iframe-container"
|
||||||
|
className={`${styles.widget} ${!isLoading ? styles.ready : ""}`}
|
||||||
|
/>
|
||||||
|
<Script
|
||||||
|
//@ts-expect-error: invalid attributes because of external script
|
||||||
|
langcode={lang}
|
||||||
|
destination={destination}
|
||||||
|
whitelabel_id="224905"
|
||||||
|
widget_id="scandic_default_new"
|
||||||
|
version="frontpage-scandic"
|
||||||
|
src={SOURCE}
|
||||||
|
onReady={handleOnReady}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/* Hiding widget on mobile for now as the widget is not ready for mobile use at the moment */
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Meeting booking widget changes design at 948px */
|
||||||
|
@media screen and (min-width: 948px) {
|
||||||
|
.widget {
|
||||||
|
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||||
|
}
|
||||||
|
.widget.ready {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
226
apps/scandic-web/components/MeetingPackageWidget/utils.ts
Normal file
226
apps/scandic-web/components/MeetingPackageWidget/utils.ts
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
// Hotel ids are used as keys to map to the destination id for the meeting package widget
|
||||||
|
// The destination id is used to prefill the correct destination
|
||||||
|
export const meetingPackageDestinationByHotelId: Record<string, string> = {
|
||||||
|
"214": "341161",
|
||||||
|
"215": "371906",
|
||||||
|
"216": "356354",
|
||||||
|
"217": "371946",
|
||||||
|
"218": "371911",
|
||||||
|
"220": "341759",
|
||||||
|
"245": "402316",
|
||||||
|
"301": "356868",
|
||||||
|
"302": "403567",
|
||||||
|
"303": "575521",
|
||||||
|
"305": "399893",
|
||||||
|
"306": "404898",
|
||||||
|
"307": "357266",
|
||||||
|
"310": "356877",
|
||||||
|
"311": "572941",
|
||||||
|
"312": "357692",
|
||||||
|
"313": "356963",
|
||||||
|
"314": "356968",
|
||||||
|
"315": "357087",
|
||||||
|
"316": "357057",
|
||||||
|
"317": "357193",
|
||||||
|
"318": "575528",
|
||||||
|
"319": "404303",
|
||||||
|
"320": "385847",
|
||||||
|
"321": "357003",
|
||||||
|
"322": "357242",
|
||||||
|
"323": "602697",
|
||||||
|
"325": "386725",
|
||||||
|
"326": "357286",
|
||||||
|
"328": "404927",
|
||||||
|
"329": "357299",
|
||||||
|
"332": "357013",
|
||||||
|
"334": "402321",
|
||||||
|
"337": "357077",
|
||||||
|
"343": "357251",
|
||||||
|
"359": "360090",
|
||||||
|
"360": "600413",
|
||||||
|
"363": "359332",
|
||||||
|
"365": "359337",
|
||||||
|
"367": "572946",
|
||||||
|
"368": "359343",
|
||||||
|
"374": "600423",
|
||||||
|
"380": "602876",
|
||||||
|
"388": "359359",
|
||||||
|
"441": "469724",
|
||||||
|
"442": "469717",
|
||||||
|
"550": "357675",
|
||||||
|
"551": "357685",
|
||||||
|
"554": "357680",
|
||||||
|
"555": "357578",
|
||||||
|
"556": "375174",
|
||||||
|
"557": "427128",
|
||||||
|
"558": "533019",
|
||||||
|
"601": "31571",
|
||||||
|
"603": "356654",
|
||||||
|
"605": "356693",
|
||||||
|
"607": "356779",
|
||||||
|
"608": "356638",
|
||||||
|
"609": "356643",
|
||||||
|
"611": "356549",
|
||||||
|
"615": "356559",
|
||||||
|
"617": "356797",
|
||||||
|
"619": "356852",
|
||||||
|
"622": "356564",
|
||||||
|
"624": "356666",
|
||||||
|
"626": "356704",
|
||||||
|
"628": "356769",
|
||||||
|
"629": "356889",
|
||||||
|
"635": "356788",
|
||||||
|
"637": "356754",
|
||||||
|
"638": "356994",
|
||||||
|
"639": "356719",
|
||||||
|
"640": "356904",
|
||||||
|
"666": "357035",
|
||||||
|
"667": "356554",
|
||||||
|
"668": "356544",
|
||||||
|
"669": "341634",
|
||||||
|
"670": "341712",
|
||||||
|
"672": "356539",
|
||||||
|
"674": "356576",
|
||||||
|
"675": "356671",
|
||||||
|
"676": "356859",
|
||||||
|
"677": "356845",
|
||||||
|
"678": "356824",
|
||||||
|
"679": "356764",
|
||||||
|
"683": "356899",
|
||||||
|
"684": "356774",
|
||||||
|
"686": "356759",
|
||||||
|
"687": "356749",
|
||||||
|
"688": "356591",
|
||||||
|
"689": "356607",
|
||||||
|
"691": "356625",
|
||||||
|
"692": "356688",
|
||||||
|
"693": "356612",
|
||||||
|
"694": "356744",
|
||||||
|
"696": "356620",
|
||||||
|
"697": "356534",
|
||||||
|
"698": "372158",
|
||||||
|
"713": "412876",
|
||||||
|
"715": "357670",
|
||||||
|
"716": "371922",
|
||||||
|
"718": "357481",
|
||||||
|
"719": "357492",
|
||||||
|
"721": "357486",
|
||||||
|
"723": "357521",
|
||||||
|
"724": "357634",
|
||||||
|
"725": "357506",
|
||||||
|
"726": "357018",
|
||||||
|
"728": "357601",
|
||||||
|
"729": "357101",
|
||||||
|
"731": "357545",
|
||||||
|
"732": "357466",
|
||||||
|
"733": "357500",
|
||||||
|
"734": "356977",
|
||||||
|
"735": "356813",
|
||||||
|
"736": "356987",
|
||||||
|
"737": "357516",
|
||||||
|
"738": "357008",
|
||||||
|
"744": "357526",
|
||||||
|
"745": "357511",
|
||||||
|
"746": "356982",
|
||||||
|
"747": "357043",
|
||||||
|
"748": "357471",
|
||||||
|
"749": "357476",
|
||||||
|
"751": "357092",
|
||||||
|
"756": "357119",
|
||||||
|
"757": "403058",
|
||||||
|
"759": "357198",
|
||||||
|
"760": "357313",
|
||||||
|
"764": "357114",
|
||||||
|
"765": "357159",
|
||||||
|
"766": "515835",
|
||||||
|
"770": "357164",
|
||||||
|
"771": "357230",
|
||||||
|
"772": "575326",
|
||||||
|
"773": "357181",
|
||||||
|
"774": "359353",
|
||||||
|
"775": "357208",
|
||||||
|
"776": "357261",
|
||||||
|
"778": "357279",
|
||||||
|
"780": "357274",
|
||||||
|
"781": "357294",
|
||||||
|
"782": "357307",
|
||||||
|
"784": "357365",
|
||||||
|
"786": "357188",
|
||||||
|
"787": "357225",
|
||||||
|
"788": "357235",
|
||||||
|
"789": "428447",
|
||||||
|
"790": "357256",
|
||||||
|
"792": "357203",
|
||||||
|
"793": "357213",
|
||||||
|
"795": "386272",
|
||||||
|
"801": "356374",
|
||||||
|
"802": "341786",
|
||||||
|
"803": "341875",
|
||||||
|
"805": "341625",
|
||||||
|
"806": "356425",
|
||||||
|
"808": "341722",
|
||||||
|
"809": "341764",
|
||||||
|
"810": "341728",
|
||||||
|
"811": "32347",
|
||||||
|
"813": "341797",
|
||||||
|
"816": "356458",
|
||||||
|
"817": "356496",
|
||||||
|
"818": "356446",
|
||||||
|
"822": "341965",
|
||||||
|
"823": "356359",
|
||||||
|
"824": "357646",
|
||||||
|
"826": "341717",
|
||||||
|
"827": "341983",
|
||||||
|
"828": "356329",
|
||||||
|
"829": "360047",
|
||||||
|
"830": "341742",
|
||||||
|
"832": "341880",
|
||||||
|
"834": "356396",
|
||||||
|
"835": "341662",
|
||||||
|
"836": "341953",
|
||||||
|
"838": "401127",
|
||||||
|
"839": "356334",
|
||||||
|
"840": "356475",
|
||||||
|
"841": "356529",
|
||||||
|
"842": "360018",
|
||||||
|
"843": "356390",
|
||||||
|
"844": "342031",
|
||||||
|
"845": "360027",
|
||||||
|
"846": "341908",
|
||||||
|
"847": "356379",
|
||||||
|
"848": "341902",
|
||||||
|
"849": "356480",
|
||||||
|
"850": "356489",
|
||||||
|
"852": "342002",
|
||||||
|
"853": "356402",
|
||||||
|
"854": "341970",
|
||||||
|
"855": "356344",
|
||||||
|
"856": "341870",
|
||||||
|
"858": "356409",
|
||||||
|
"859": "356339",
|
||||||
|
"860": "356470",
|
||||||
|
"861": "356324",
|
||||||
|
"863": "341895",
|
||||||
|
"864": "356501",
|
||||||
|
"865": "341993",
|
||||||
|
"866": "341978",
|
||||||
|
"867": "356583",
|
||||||
|
"868": "356384",
|
||||||
|
"869": "341942",
|
||||||
|
"870": "356417",
|
||||||
|
"871": "356349",
|
||||||
|
"872": "341913",
|
||||||
|
"873": "342011",
|
||||||
|
"875": "401143",
|
||||||
|
"876": "341885",
|
||||||
|
"877": "342024",
|
||||||
|
"878": "356453",
|
||||||
|
"879": "341865",
|
||||||
|
"882": "356438",
|
||||||
|
"883": "356364",
|
||||||
|
"885": "341988",
|
||||||
|
"886": "341933",
|
||||||
|
"887": "341918",
|
||||||
|
"889": "356596",
|
||||||
|
"890": "341890",
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import { create } from "zustand"
|
|||||||
export enum StickyElementNameEnum {
|
export enum StickyElementNameEnum {
|
||||||
SITEWIDE_ALERT = "SITEWIDE_ALERT",
|
SITEWIDE_ALERT = "SITEWIDE_ALERT",
|
||||||
BOOKING_WIDGET = "BOOKING_WIDGET",
|
BOOKING_WIDGET = "BOOKING_WIDGET",
|
||||||
|
MEETING_BOOKING_WIDGET = "MEETING_BOOKING_WIDGET",
|
||||||
HOTEL_TAB_NAVIGATION = "HOTEL_TAB_NAVIGATION",
|
HOTEL_TAB_NAVIGATION = "HOTEL_TAB_NAVIGATION",
|
||||||
HOTEL_STATIC_MAP = "HOTEL_STATIC_MAP",
|
HOTEL_STATIC_MAP = "HOTEL_STATIC_MAP",
|
||||||
DESTINATION_SIDEBAR = "DESTINATION_SIDEBAR",
|
DESTINATION_SIDEBAR = "DESTINATION_SIDEBAR",
|
||||||
@@ -36,6 +37,7 @@ const priorityMap: Record<StickyElementNameEnum, number> = {
|
|||||||
[StickyElementNameEnum.HOTEL_TAB_NAVIGATION]: 3,
|
[StickyElementNameEnum.HOTEL_TAB_NAVIGATION]: 3,
|
||||||
[StickyElementNameEnum.HOTEL_STATIC_MAP]: 3,
|
[StickyElementNameEnum.HOTEL_STATIC_MAP]: 3,
|
||||||
|
|
||||||
|
[StickyElementNameEnum.MEETING_BOOKING_WIDGET]: 3,
|
||||||
[StickyElementNameEnum.DESTINATION_SIDEBAR]: 3,
|
[StickyElementNameEnum.DESTINATION_SIDEBAR]: 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user