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;
|
||||
}
|
||||
|
||||
.meetingBookingWidget {
|
||||
padding: var(--Spacing-x4);
|
||||
background-color: var(--Base-Surface-Primary-dark-Normal);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
position: sticky;
|
||||
padding: var(--Spacing-x3) var(--Spacing-x2);
|
||||
|
||||
@@ -20,6 +20,7 @@ import { getLang } from "@/i18n/serverContext"
|
||||
import MeetingsAdditionalContent from "./AdditionalContent/Meetings"
|
||||
import HotelSubpageAdditionalContent from "./AdditionalContent"
|
||||
import HtmlContent from "./HtmlContent"
|
||||
import { MeetingWidget } from "./MeetingWidget"
|
||||
import HotelSubpageSidebar from "./Sidebar"
|
||||
import { getSubpageData, verifySubpageShouldExist } from "./utils"
|
||||
|
||||
@@ -55,24 +56,19 @@ export default async function HotelSubpage({
|
||||
|
||||
let meetingRooms
|
||||
if (hotelData.additionalData.meetingRooms.nameInUrl === subpage) {
|
||||
meetingRooms = await getMeetingRooms({ hotelId: hotelId, language: lang })
|
||||
meetingRooms = await getMeetingRooms({ hotelId, language: lang })
|
||||
}
|
||||
|
||||
const restaurantButton = restaurants.find(
|
||||
(restaurant) => restaurant.nameInUrl === subpage
|
||||
)
|
||||
|
||||
const meetingBookingWidget = meetingRooms ? (
|
||||
<div className={styles.meetingBookingWidget}>
|
||||
Booking Widget Placeholder
|
||||
</div>
|
||||
) : null
|
||||
|
||||
return (
|
||||
<>
|
||||
<section
|
||||
className={`${styles.hotelSubpage} ${restaurantButton?.bookTableUrl ? styles.hasStickyButton : ""} `}
|
||||
>
|
||||
{meetingRooms && <MeetingWidget hotelId={hotelId} />}
|
||||
<div className={styles.header}>
|
||||
<Suspense fallback={<BreadcrumbsSkeleton />}>
|
||||
<Breadcrumbs
|
||||
@@ -81,9 +77,8 @@ export default async function HotelSubpage({
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{pageData.heroImage || meetingBookingWidget ? (
|
||||
{pageData.heroImage ? (
|
||||
<div className={styles.heroWrapper}>
|
||||
{meetingBookingWidget}
|
||||
{pageData.heroImage && (
|
||||
<Hero
|
||||
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 {
|
||||
SITEWIDE_ALERT = "SITEWIDE_ALERT",
|
||||
BOOKING_WIDGET = "BOOKING_WIDGET",
|
||||
MEETING_BOOKING_WIDGET = "MEETING_BOOKING_WIDGET",
|
||||
HOTEL_TAB_NAVIGATION = "HOTEL_TAB_NAVIGATION",
|
||||
HOTEL_STATIC_MAP = "HOTEL_STATIC_MAP",
|
||||
DESTINATION_SIDEBAR = "DESTINATION_SIDEBAR",
|
||||
@@ -36,6 +37,7 @@ const priorityMap: Record<StickyElementNameEnum, number> = {
|
||||
[StickyElementNameEnum.HOTEL_TAB_NAVIGATION]: 3,
|
||||
[StickyElementNameEnum.HOTEL_STATIC_MAP]: 3,
|
||||
|
||||
[StickyElementNameEnum.MEETING_BOOKING_WIDGET]: 3,
|
||||
[StickyElementNameEnum.DESTINATION_SIDEBAR]: 3,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user