Files
web/packages/booking-flow/lib/components/BookingWidget/MobileToggleButton/index.tsx
2026-01-28 12:02:42 +00:00

229 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import { cx } from "class-variance-authority"
import { Button } from "react-aria-components"
import { useWatch } from "react-hook-form"
import { useIntl } from "react-intl"
import { shortDateFormat } from "@scandic-hotels/common/constants/dateFormats"
import { dt } from "@scandic-hotels/common/dt"
import { Divider } from "@scandic-hotels/design-system/Divider"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
import { Typography } from "@scandic-hotels/design-system/Typography"
import useLang from "../../../hooks/useLang"
import styles from "./button.module.css"
import type { BookingWidgetSchema } from "../Client"
type BookingWidgetToggleButtonProps = {
openMobileSearch: () => void
isFloating: boolean
}
export default function MobileToggleButton({
openMobileSearch,
isFloating,
}: BookingWidgetToggleButtonProps) {
const intl = useIntl()
const lang = useLang()
const date = useWatch<BookingWidgetSchema, "date">({ name: "date" })
const rooms = useWatch<BookingWidgetSchema, "rooms">({ name: "rooms" })
const searchTerm = useWatch<BookingWidgetSchema, "search">({ name: "search" })
const selectedSearchTerm = useWatch<BookingWidgetSchema, "selectedSearch">({
name: "selectedSearch",
})
const selectedFromDate = dt(date.fromDate)
.locale(lang)
.format(shortDateFormat[lang])
const selectedToDate = dt(date.toDate)
.locale(lang)
.format(shortDateFormat[lang])
const locationAndDateIsSet = searchTerm && date
const totalNights = dt(date.toDate).diff(dt(date.fromDate), "days")
const totalRooms = rooms.length
const totalAdults = rooms.reduce((acc, room) => {
if (room.adults) {
acc = acc + room.adults
}
return acc
}, 0)
const totalChildren = rooms.reduce((acc, room) => {
if (room.childrenInRoom) {
acc = acc + room.childrenInRoom.length
}
return acc
}, 0)
const totalNightsMsg = intl.formatMessage(
{
id: "booking.numberOfNights",
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
},
{ totalNights }
)
const totalAdultsMsg = intl.formatMessage(
{
id: "booking.numberOfAdults",
defaultMessage: "{adults, plural, one {# adult} other {# adults}}",
},
{ adults: totalAdults }
)
const totalChildrenMsg = intl.formatMessage(
{
id: "booking.numberOfChildren",
defaultMessage: "{children, plural, one {# child} other {# children}}",
},
{ children: totalChildren }
)
const totalRoomsMsg = intl.formatMessage(
{
id: "booking.numberOfRooms",
defaultMessage: "{totalRooms, plural, one {# room} other {# rooms}}",
},
{ totalRooms }
)
const totalDetails = [totalAdultsMsg]
if (totalChildren > 0) {
totalDetails.push(totalChildrenMsg)
}
totalDetails.push(totalRoomsMsg)
return (
<Button
className={cx(
styles.mobileToggleButton,
locationAndDateIsSet ? styles.complete : styles.partial,
{ [styles.floating]: isFloating }
)}
onPress={openMobileSearch}
>
{!locationAndDateIsSet && (
<>
<span className={styles.block}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.blockLabel}>
{intl.formatMessage({
id: "bookingWidget.label.whereTo",
defaultMessage: "Where to?",
})}
</span>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<span className={styles.placeholder}>
{searchTerm
? searchTerm
: intl.formatMessage({
id: "bookingWidget.label.destination",
defaultMessage: "Destination",
})}
</span>
</Typography>
</span>
{/* Button can't contain HR elements */}
<Divider color="Border/Divider/Subtle" variant="vertical" />
<span className={styles.block}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.blockLabel}>{totalNightsMsg}</span>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<span className={styles.placeholder}>
{intl.formatMessage(
{
id: "booking.selectedDateRange",
defaultMessage: "{selectedFromDate} {selectedToDate}",
},
{
selectedFromDate,
selectedToDate,
}
)}
</span>
</Typography>
</span>
<span className={styles.icon}>
<MaterialIcon icon="search" color="Icon/Inverted" />
</span>
</>
)}
{locationAndDateIsSet && (
<>
<span className={styles.block}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.blockLabel}>{selectedSearchTerm}</span>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<span className={styles.locationAndDate}>
{intl.formatMessage(
{
id: "bookingWidget.mobile.selectedSummary",
defaultMessage:
"{selectedFromDate} {selectedToDate} ({totalNights}) {details}",
},
{
selectedFromDate,
selectedToDate,
totalNights: totalNightsMsg,
details: totalDetails.join(", "),
}
)}
</span>
</Typography>
</span>
<span className={styles.icon}>
<MaterialIcon icon="edit_square" color="Icon/Inverted" />
</span>
</>
)}
</Button>
)
}
export function MobileToggleButtonSkeleton() {
const intl = useIntl()
return (
<div className={cx(styles.mobileToggleButton, styles.partial)}>
<span className={styles.block}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.blockLabel}>
{intl.formatMessage({
id: "bookingWidget.label.whereTo",
defaultMessage: "Where to?",
})}
</span>
</Typography>
<SkeletonShimmer display="block" height="20px" width="11ch" />
</span>
<Divider color="Border/Divider/Subtle" variant="vertical" />
<span className={styles.block}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.blockLabel}>
{intl.formatMessage(
{
id: "booking.numberOfNights",
defaultMessage:
"{totalNights, plural, one {# night} other {# nights}}",
},
{ totalNights: 0 }
)}
</span>
</Typography>
<SkeletonShimmer display="block" height="20px" width="13ch" />
</span>
<span className={styles.icon}>
<MaterialIcon icon="search" color="Icon/Inverted" />
</span>
</div>
)
}