feat(SW-2708): Meeting package widget mobile UI

Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-05-14 11:31:02 +00:00
parent 4f7edf6ad2
commit a66b632875
9 changed files with 282 additions and 63 deletions

View File

@@ -1,59 +1,100 @@
"use client"
import { useEffect, useState } from "react"
import {
Button,
Dialog,
DialogTrigger,
Modal,
ModalOverlay,
} from "react-aria-components"
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"
import useLang from "@/hooks/useLang"
import { IconButton } from "@scandic-hotels/design-system/IconButton"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import MeetingPackageWidgetSkeleton from "./Skeleton"
import MeetingPackageWidgetContent from "./Content/Content"
import styles from "./meetingPackageWidget.module.css"
const SOURCE =
"https://scandic-bookingengine.s3.eu-central-1.amazonaws.com/script_stage.js"
interface MeetingPackageWidgetProps {
export interface MeetingPackageWidgetProps {
destination?: string
className?: string
}
export default function MeetingPackageWidget({
destination,
className,
}: MeetingPackageWidgetProps) {
const lang = useLang()
const [isLoading, setIsLoading] = useState(true)
export default function MeetingPackageWidget(props: MeetingPackageWidgetProps) {
const intl = useIntl()
/* Meeting booking widget changes design at 948px */
const isDesktop = useMediaQuery("(min-width: 948px)", {
initializeWithValue: false,
})
useEffect(() => {
const script = document.createElement("script")
script.src = SOURCE
script.setAttribute("langcode", lang)
script.setAttribute("whitelabel_id", "224905")
script.setAttribute("widget_id", "scandic_default_new")
script.setAttribute("version", "frontpage-scandic")
if (destination) {
script.setAttribute("destination", destination)
}
document.body.appendChild(script)
function onLoad() {
setIsLoading(false)
}
script.addEventListener("load", onLoad)
return () => {
script.removeEventListener("load", onLoad)
document.body.removeChild(script)
}
}, [destination, lang])
return (
<div className={className}>
{isLoading && <MeetingPackageWidgetSkeleton />}
<div
id="mp-booking-engine-iframe-container"
className={`${styles.widget} ${isLoading ? styles.isLoading : ""}`}
/>
return isDesktop ? (
<MeetingPackageWidgetContent {...props} />
) : (
<div className={props.className}>
<DialogTrigger>
<div className={styles.buttonWrapper}>
<Button className={styles.button}>
<span className={styles.fakeInput}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span>
{intl.formatMessage({
defaultMessage: "Meeting location",
})}
</span>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<span className={styles.fakePlaceholder}>
{intl.formatMessage({
defaultMessage: "Hotels & destinations",
})}
</span>
</Typography>
</span>
<span className={styles.fakeButton}>
<MaterialIcon icon="search" color="CurrentColor" />
<Typography variant="Body/Supporting text (caption)/smBold">
<span>
{intl.formatMessage({
defaultMessage: "Search",
})}
</span>
</Typography>
</span>
</Button>
</div>
<ModalOverlay isDismissable className={styles.overlay}>
<Modal className={styles.modal}>
<Dialog
className={styles.dialog}
aria-label={intl.formatMessage({
defaultMessage: "Book a meeting",
})}
>
{({ close }) => (
<>
<div className={styles.closeButtonWrapper}>
<IconButton
theme="Black"
style="Muted"
onPress={close}
className={styles.closeButton}
aria-label={intl.formatMessage({
defaultMessage: "Close",
})}
>
<MaterialIcon icon="close" />
</IconButton>
</div>
<MeetingPackageWidgetContent {...props} />
</>
)}
</Dialog>
</Modal>
</ModalOverlay>
</DialogTrigger>
</div>
)
}