feat(SW-2863): Move contentstack router to trpc package * Add exports to packages and lint rule to prevent relative imports * Add env to trpc package * Add eslint to trpc package * Apply lint rules * Use direct imports from trpc package * Add lint-staged config to trpc * Move lang enum to common * Restructure trpc package folder structure * WIP first step * update internal imports in trpc * Fix most errors in scandic-web Just 100 left... * Move Props type out of trpc * Fix CategorizedFilters types * Move more schemas in hotel router * Fix deps * fix getNonContentstackUrls * Fix import error * Fix entry error handling * Fix generateMetadata metrics * Fix alertType enum * Fix duplicated types * lint:fix * Merge branch 'master' into feat/sw-2863-move-contentstack-router-to-trpc-package * Fix broken imports * Merge branch 'master' into feat/sw-2863-move-contentstack-router-to-trpc-package Approved-by: Linus Flood
214 lines
6.6 KiB
TypeScript
214 lines
6.6 KiB
TypeScript
"use client"
|
|
|
|
import { Button } from "react-aria-components"
|
|
import { useWatch } from "react-hook-form"
|
|
import { useIntl } from "react-intl"
|
|
|
|
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 { Typography } from "@scandic-hotels/design-system/Typography"
|
|
|
|
import { shortDateFormat } from "@/constants/dateFormats"
|
|
|
|
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
|
import useLang from "@/hooks/useLang"
|
|
|
|
import styles from "./button.module.css"
|
|
|
|
import type {
|
|
BookingWidgetSchema,
|
|
BookingWidgetToggleButtonProps,
|
|
} from "@/types/components/bookingWidget"
|
|
|
|
export default function MobileToggleButton({
|
|
openMobileSearch,
|
|
}: 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(
|
|
{
|
|
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
|
|
},
|
|
{ totalNights }
|
|
)
|
|
|
|
const totalAdultsMsg = intl.formatMessage(
|
|
{
|
|
defaultMessage: "{totalAdults, plural, one {# adult} other {# adults}}",
|
|
},
|
|
{ totalAdults }
|
|
)
|
|
|
|
const totalChildrenMsg = intl.formatMessage(
|
|
{
|
|
defaultMessage:
|
|
"{totalChildren, plural, one {# child} other {# children}}",
|
|
},
|
|
{ totalChildren }
|
|
)
|
|
|
|
const totalRoomsMsg = intl.formatMessage(
|
|
{
|
|
defaultMessage: "{totalRooms, plural, one {# room} other {# rooms}}",
|
|
},
|
|
{ totalRooms }
|
|
)
|
|
|
|
const totalDetails = [totalAdultsMsg]
|
|
if (totalChildren > 0) {
|
|
totalDetails.push(totalChildrenMsg)
|
|
}
|
|
totalDetails.push(totalRoomsMsg)
|
|
|
|
return (
|
|
<Button
|
|
className={locationAndDateIsSet ? styles.complete : styles.partial}
|
|
onPress={openMobileSearch}
|
|
>
|
|
{!locationAndDateIsSet && (
|
|
<>
|
|
<span className={styles.block}>
|
|
<Typography variant={"Body/Supporting text (caption)/smBold"}>
|
|
<span className={styles.blockLabel}>
|
|
{intl.formatMessage({
|
|
defaultMessage: "Where to?",
|
|
})}
|
|
</span>
|
|
</Typography>
|
|
<Typography variant={"Body/Paragraph/mdRegular"}>
|
|
<span className={styles.placeholder}>
|
|
{searchTerm
|
|
? searchTerm
|
|
: intl.formatMessage({
|
|
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(
|
|
{
|
|
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)/smRegular"}>
|
|
<span className={styles.blockLabel}>{selectedSearchTerm}</span>
|
|
</Typography>
|
|
<Typography variant={"Body/Supporting text (caption)/smRegular"}>
|
|
<span className={styles.locationAndDate}>
|
|
{intl.formatMessage(
|
|
{
|
|
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={styles.partial}>
|
|
<span className={styles.block}>
|
|
<Typography variant={"Body/Supporting text (caption)/smBold"}>
|
|
<span className={styles.blockLabel}>
|
|
{intl.formatMessage({
|
|
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(
|
|
{
|
|
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>
|
|
)
|
|
}
|