Merged in feat/SW-3289-replace-sidepeek-hotel-reservation (pull request #2686)
feat(SW-3289): replace sidepeek * fix(SW-3289): replace sidepeek * fix(SW-3289): add wrapping prop and change prop name to buttonVariant * fix(SW-3289): replace body with typography * fix(SW-3289): fix intl message Approved-by: Joakim Jäderberg
This commit is contained in:
@@ -125,6 +125,7 @@ export default async function DetailsPage(
|
|||||||
searchParamsStr={selectRoomParams.toString()}
|
searchParamsStr={selectRoomParams.toString()}
|
||||||
user={user}
|
user={user}
|
||||||
vat={hotel.vat}
|
vat={hotel.vat}
|
||||||
|
roomCategories={hotelData.roomCategories}
|
||||||
>
|
>
|
||||||
<HotelHeader hotelData={hotelData} />
|
<HotelHeader hotelData={hotelData} />
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import SidePeek from "@scandic-hotels/booking-flow/components/HotelReservationSidePeek"
|
|
||||||
|
|
||||||
import styles from "./layout.module.css"
|
import styles from "./layout.module.css"
|
||||||
|
|
||||||
import type { LangParams, LayoutArgs } from "@/types/params"
|
import type { LangParams, LayoutArgs } from "@/types/params"
|
||||||
@@ -7,10 +5,5 @@ import type { LangParams, LayoutArgs } from "@/types/params"
|
|||||||
export default function StandardHotelReservationLayout({
|
export default function StandardHotelReservationLayout({
|
||||||
children,
|
children,
|
||||||
}: React.PropsWithChildren<LayoutArgs<LangParams>>) {
|
}: React.PropsWithChildren<LayoutArgs<LangParams>>) {
|
||||||
return (
|
return <div className={styles.layout}>{children}</div>
|
||||||
<div className={styles.layout}>
|
|
||||||
{children}
|
|
||||||
<SidePeek />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { DialogTrigger } from "react-aria-components"
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import { RoomSidePeekContent } from "@scandic-hotels/booking-flow/components/RoomSidePeekContent"
|
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
import { getBookedHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
|
||||||
|
|
||||||
import { useBookingConfirmationStore } from "@/stores/booking-confirmation"
|
|
||||||
|
|
||||||
import SidePeekSelfControlled from "@/components/TempDesignSystem/SidePeekSelfControlled"
|
|
||||||
|
|
||||||
interface RoomDetailsSidePeekProps {
|
|
||||||
roomTypeCode: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function RoomDetailsSidePeek({
|
|
||||||
roomTypeCode,
|
|
||||||
}: RoomDetailsSidePeekProps) {
|
|
||||||
const { roomCategories } = useBookingConfirmationStore((state) => ({
|
|
||||||
roomCategories: state.roomCategories,
|
|
||||||
}))
|
|
||||||
const room = getBookedHotelRoom(roomCategories, roomTypeCode)
|
|
||||||
const intl = useIntl()
|
|
||||||
|
|
||||||
if (!room) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DialogTrigger>
|
|
||||||
<Button
|
|
||||||
variant="Text"
|
|
||||||
color="Primary"
|
|
||||||
size="Small"
|
|
||||||
typography="Body/Supporting text (caption)/smBold"
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ defaultMessage: "View room details" })}
|
|
||||||
<MaterialIcon icon="chevron_right" size={14} color="CurrentColor" />
|
|
||||||
</Button>
|
|
||||||
<SidePeekSelfControlled title={room.name}>
|
|
||||||
<RoomSidePeekContent room={room} />
|
|
||||||
</SidePeekSelfControlled>
|
|
||||||
</DialogTrigger>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -11,13 +11,14 @@ import Caption from "@scandic-hotels/design-system/Caption"
|
|||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import Image from "@scandic-hotels/design-system/Image"
|
import Image from "@scandic-hotels/design-system/Image"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
import { getHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
||||||
|
|
||||||
import { CancellationRuleEnum } from "@/constants/booking"
|
import { CancellationRuleEnum } from "@/constants/booking"
|
||||||
|
import { useBookingConfirmationStore } from "@/stores/booking-confirmation"
|
||||||
|
|
||||||
|
import RoomDetailsSidePeek from "@/components/SidePeeks/RoomDetailsSidePeek"
|
||||||
import useLang from "@/hooks/useLang"
|
import useLang from "@/hooks/useLang"
|
||||||
|
|
||||||
import RoomDetailsSidePeek from "./RoomDetailsSidePeek"
|
|
||||||
|
|
||||||
import styles from "./room.module.css"
|
import styles from "./room.module.css"
|
||||||
|
|
||||||
import type { RoomProps } from "@/types/components/hotelReservation/bookingConfirmation/rooms/room"
|
import type { RoomProps } from "@/types/components/hotelReservation/bookingConfirmation/rooms/room"
|
||||||
@@ -31,6 +32,10 @@ export default function Room({
|
|||||||
}: RoomProps) {
|
}: RoomProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const lang = useLang()
|
const lang = useLang()
|
||||||
|
const { roomCategories } = useBookingConfirmationStore((state) => ({
|
||||||
|
roomCategories: state.roomCategories,
|
||||||
|
}))
|
||||||
|
const room = getHotelRoom(roomCategories, booking.roomTypeCode)
|
||||||
|
|
||||||
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`
|
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`
|
||||||
const fromDate = dt(booking.checkInDate).locale(lang)
|
const fromDate = dt(booking.checkInDate).locale(lang)
|
||||||
@@ -116,7 +121,18 @@ export default function Room({
|
|||||||
<Typography variant="Title/Subtitle/md">
|
<Typography variant="Title/Subtitle/md">
|
||||||
<h2>{roomName}</h2>
|
<h2>{roomName}</h2>
|
||||||
</Typography>
|
</Typography>
|
||||||
<RoomDetailsSidePeek roomTypeCode={booking.roomTypeCode} />
|
{room && (
|
||||||
|
<RoomDetailsSidePeek
|
||||||
|
hotelId={booking.hotelId}
|
||||||
|
room={room}
|
||||||
|
roomTypeCode={booking.roomTypeCode}
|
||||||
|
buttonVariant="primary"
|
||||||
|
triggerLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "View room details",
|
||||||
|
})}
|
||||||
|
wrapping={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
<ul className={styles.details}>
|
<ul className={styles.details}>
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import useSidePeekStore, {
|
|
||||||
SidePeekEnum,
|
|
||||||
} from "@scandic-hotels/booking-flow/stores/sidepeek"
|
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
|
|
||||||
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
|
||||||
|
|
||||||
import type { ToggleSidePeekProps } from "@/types/components/hotelReservation/toggleSidePeekProps"
|
|
||||||
|
|
||||||
export default function ToggleSidePeek({ hotelId }: ToggleSidePeekProps) {
|
|
||||||
const intl = useIntl()
|
|
||||||
const openSidePeek = useSidePeekStore((state) => state.openSidePeek)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
onPress={() => {
|
|
||||||
openSidePeek({ key: SidePeekEnum.hotelDetails, hotelId })
|
|
||||||
trackOpenSidePeekEvent({
|
|
||||||
name: SidePeekEnum.hotelDetails,
|
|
||||||
hotelId,
|
|
||||||
includePathname: true,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
size="Small"
|
|
||||||
variant="Secondary"
|
|
||||||
color="Inverted"
|
|
||||||
wrapping
|
|
||||||
typography="Body/Paragraph/mdBold"
|
|
||||||
>
|
|
||||||
{intl.formatMessage({
|
|
||||||
defaultMessage: "See hotel details",
|
|
||||||
})}
|
|
||||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -2,17 +2,18 @@ import Image from "@scandic-hotels/design-system/Image"
|
|||||||
import Title from "@scandic-hotels/design-system/Title"
|
import Title from "@scandic-hotels/design-system/Title"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import ToggleSidePeek from "./ToggleSidePeek"
|
import HotelDetailsSidePeek from "@/components/SidePeeks/HotelDetailsSidePeek"
|
||||||
|
import { getIntl } from "@/i18n"
|
||||||
|
|
||||||
import styles from "./header.module.css"
|
import styles from "./header.module.css"
|
||||||
|
|
||||||
import type { HotelHeaderProps } from "@/types/components/hotelReservation/enterDetails/hotelHeader"
|
import type { HotelHeaderProps } from "@/types/components/hotelReservation/enterDetails/hotelHeader"
|
||||||
|
|
||||||
export default async function HotelHeader({
|
export default async function HotelHeader({
|
||||||
hotelData: { hotel },
|
hotelData: { hotel, url, restaurants, additionalData },
|
||||||
}: HotelHeaderProps) {
|
}: HotelHeaderProps) {
|
||||||
const image = hotel.hotelContent?.images
|
const image = hotel.hotelContent?.images
|
||||||
|
const intl = await getIntl()
|
||||||
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
|
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -49,7 +50,16 @@ export default async function HotelHeader({
|
|||||||
<div className={styles.address}>{addressStr}</div>
|
<div className={styles.address}>{addressStr}</div>
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<ToggleSidePeek hotelId={hotel.operaId} />
|
|
||||||
|
<HotelDetailsSidePeek
|
||||||
|
hotel={{ ...hotel, url: url }}
|
||||||
|
restaurants={restaurants}
|
||||||
|
additionalHotelData={additionalData}
|
||||||
|
triggerLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "See hotel details",
|
||||||
|
})}
|
||||||
|
buttonVariant={"secondary"}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import useSidePeekStore, {
|
|
||||||
SidePeekEnum,
|
|
||||||
} from "@scandic-hotels/booking-flow/stores/sidepeek"
|
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
|
|
||||||
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
|
||||||
|
|
||||||
import type { ToggleSidePeekProps } from "@/types/components/hotelReservation/toggleSidePeekProps"
|
|
||||||
|
|
||||||
export default function ToggleSidePeek({
|
|
||||||
hotelId,
|
|
||||||
roomTypeCode,
|
|
||||||
title,
|
|
||||||
}: ToggleSidePeekProps) {
|
|
||||||
const intl = useIntl()
|
|
||||||
const openSidePeek = useSidePeekStore((state) => state.openSidePeek)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
onPress={() => {
|
|
||||||
openSidePeek({ key: SidePeekEnum.roomDetails, hotelId, roomTypeCode })
|
|
||||||
trackOpenSidePeekEvent({
|
|
||||||
name: SidePeekEnum.roomDetails,
|
|
||||||
hotelId,
|
|
||||||
roomTypeCode,
|
|
||||||
includePathname: true,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
size="Small"
|
|
||||||
variant="Text"
|
|
||||||
wrapping
|
|
||||||
typography="Body/Paragraph/mdBold"
|
|
||||||
>
|
|
||||||
{title ||
|
|
||||||
intl.formatMessage({
|
|
||||||
defaultMessage: "See room details",
|
|
||||||
})}
|
|
||||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -9,14 +9,14 @@ import { Button } from "@scandic-hotels/design-system/Button"
|
|||||||
import Footnote from "@scandic-hotels/design-system/Footnote"
|
import Footnote from "@scandic-hotels/design-system/Footnote"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import Subtitle from "@scandic-hotels/design-system/Subtitle"
|
import Subtitle from "@scandic-hotels/design-system/Subtitle"
|
||||||
|
import { getHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
||||||
|
|
||||||
import { useEnterDetailsStore } from "@/stores/enter-details"
|
import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||||
|
|
||||||
|
import RoomDetailsSidePeek from "@/components/SidePeeks/RoomDetailsSidePeek"
|
||||||
import { useRoomContext } from "@/contexts/Details/Room"
|
import { useRoomContext } from "@/contexts/Details/Room"
|
||||||
import useLang from "@/hooks/useLang"
|
import useLang from "@/hooks/useLang"
|
||||||
|
|
||||||
import ToggleSidePeek from "./ToggleSidePeek"
|
|
||||||
|
|
||||||
import styles from "./selectedRoom.module.css"
|
import styles from "./selectedRoom.module.css"
|
||||||
|
|
||||||
export default function SelectedRoom() {
|
export default function SelectedRoom() {
|
||||||
@@ -25,10 +25,13 @@ export default function SelectedRoom() {
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [isPending, startTransition] = useTransition()
|
const [isPending, startTransition] = useTransition()
|
||||||
const { room, idx } = useRoomContext()
|
const { room, idx } = useRoomContext()
|
||||||
const { hotelId, searchParamsStr } = useEnterDetailsStore((state) => ({
|
const { hotelId, roomCategories, searchParamsStr } = useEnterDetailsStore(
|
||||||
hotelId: state.booking.hotelId,
|
(state) => ({
|
||||||
searchParamsStr: state.searchParamString,
|
hotelId: state.booking.hotelId,
|
||||||
}))
|
roomCategories: state.roomCategories,
|
||||||
|
searchParamsStr: state.searchParamString,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
function changeRoom() {
|
function changeRoom() {
|
||||||
const searchParams = new URLSearchParams(searchParamsStr)
|
const searchParams = new URLSearchParams(searchParamsStr)
|
||||||
@@ -39,6 +42,8 @@ export default function SelectedRoom() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectedRoom = getHotelRoom(roomCategories, room.roomTypeCode)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper} data-available={room.isAvailable}>
|
<div className={styles.wrapper} data-available={room.isAvailable}>
|
||||||
<div className={styles.main}>
|
<div className={styles.main}>
|
||||||
@@ -79,6 +84,7 @@ export default function SelectedRoom() {
|
|||||||
size="Small"
|
size="Small"
|
||||||
onPress={changeRoom}
|
onPress={changeRoom}
|
||||||
isDisabled={isPending}
|
isDisabled={isPending}
|
||||||
|
wrapping={false}
|
||||||
typography="Body/Supporting text (caption)/smBold"
|
typography="Body/Supporting text (caption)/smBold"
|
||||||
>
|
>
|
||||||
<MaterialIcon icon="edit_square" size={20} color="CurrentColor" />
|
<MaterialIcon icon="edit_square" size={20} color="CurrentColor" />
|
||||||
@@ -87,11 +93,17 @@ export default function SelectedRoom() {
|
|||||||
})}
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{room.roomTypeCode && (
|
{room.roomTypeCode && selectedRoom && (
|
||||||
<div className={styles.details}>
|
<div className={styles.details}>
|
||||||
<ToggleSidePeek
|
<RoomDetailsSidePeek
|
||||||
hotelId={hotelId}
|
hotelId={hotelId}
|
||||||
roomTypeCode={room.roomTypeCode}
|
roomTypeCode={room.roomTypeCode}
|
||||||
|
room={selectedRoom}
|
||||||
|
buttonVariant="primary"
|
||||||
|
triggerLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "See room details",
|
||||||
|
})}
|
||||||
|
wrapping={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
.details {
|
.details {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
margin-top: var(--Space-x05);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import {
|
|||||||
import { memo } from "react"
|
import { memo } from "react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import OpenSidePeekButton from "@scandic-hotels/booking-flow/components/OpenSidePeekButton"
|
|
||||||
import TripAdvisorChip from "@scandic-hotels/booking-flow/components/TripAdvisorChip"
|
import TripAdvisorChip from "@scandic-hotels/booking-flow/components/TripAdvisorChip"
|
||||||
import { SidePeekEnum } from "@scandic-hotels/booking-flow/stores/sidepeek"
|
|
||||||
import {
|
import {
|
||||||
alternativeHotelsMap,
|
alternativeHotelsMap,
|
||||||
selectHotelMap,
|
selectHotelMap,
|
||||||
@@ -30,6 +28,7 @@ import { useHotelsMapStore } from "@/stores/hotels-map"
|
|||||||
|
|
||||||
import BookingCodeChip from "@/components/BookingCodeChip"
|
import BookingCodeChip from "@/components/BookingCodeChip"
|
||||||
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||||
|
import HotelDetailsSidePeek from "@/components/SidePeeks/HotelDetailsSidePeek"
|
||||||
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||||
|
|
||||||
import HotelChequeCard from "./HotelChequeCard"
|
import HotelChequeCard from "./HotelChequeCard"
|
||||||
@@ -47,7 +46,7 @@ import { HotelCardListingTypeEnum } from "@/types/components/hotelReservation/se
|
|||||||
import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps"
|
import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps"
|
||||||
|
|
||||||
function HotelCard({
|
function HotelCard({
|
||||||
hotelData: { availability, hotel },
|
hotelData: { availability, hotel, additionalData, restaurants, url },
|
||||||
isUserLoggedIn,
|
isUserLoggedIn,
|
||||||
state = "default",
|
state = "default",
|
||||||
type = HotelCardListingTypeEnum.PageListing,
|
type = HotelCardListingTypeEnum.PageListing,
|
||||||
@@ -184,13 +183,14 @@ function HotelCard({
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<OpenSidePeekButton
|
<HotelDetailsSidePeek
|
||||||
label={intl.formatMessage({
|
hotel={{ ...hotel, url: url }}
|
||||||
|
restaurants={restaurants}
|
||||||
|
additionalHotelData={additionalData}
|
||||||
|
triggerLabel={intl.formatMessage({
|
||||||
defaultMessage: "See hotel details",
|
defaultMessage: "See hotel details",
|
||||||
})}
|
})}
|
||||||
hotelId={hotel.operaId}
|
buttonVariant="primary"
|
||||||
showCTA={true}
|
|
||||||
sidePeekKey={SidePeekEnum.hotelDetails}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<PricesWrapper
|
<PricesWrapper
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { Button as ButtonRAC, DialogTrigger } from "react-aria-components"
|
|||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
|
|
||||||
import BookedRoomSidePeek from "@/components/SidePeeks/BookedRoomSidePeek"
|
import BookedRoomSidePeek from "@/components/SidePeeks/BookedRoomSidePeek"
|
||||||
|
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
||||||
|
|
||||||
import styles from "./sidePeek.module.css"
|
import styles from "./sidePeek.module.css"
|
||||||
|
|
||||||
|
import { SidePeekEnum } from "@/types/sidepeek"
|
||||||
import type { Room as MyStayRoom } from "@/types/stores/my-stay"
|
import type { Room as MyStayRoom } from "@/types/stores/my-stay"
|
||||||
import type { SafeUser } from "@/types/user"
|
import type { SafeUser } from "@/types/user"
|
||||||
|
|
||||||
@@ -21,7 +23,16 @@ export default function RoomDetailsSidePeek({
|
|||||||
}: RoomDetailsSidePeekProps) {
|
}: RoomDetailsSidePeekProps) {
|
||||||
return (
|
return (
|
||||||
<DialogTrigger>
|
<DialogTrigger>
|
||||||
<ButtonRAC className={styles.trigger}>
|
<ButtonRAC
|
||||||
|
className={styles.trigger}
|
||||||
|
onPress={() => {
|
||||||
|
trackOpenSidePeekEvent({
|
||||||
|
name: SidePeekEnum.bookedRoomDetails,
|
||||||
|
hotelId: booking.hotelId,
|
||||||
|
includePathname: true,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
<MaterialIcon icon="pan_zoom" color="CurrentColor" />
|
<MaterialIcon icon="pan_zoom" color="CurrentColor" />
|
||||||
</ButtonRAC>
|
</ButtonRAC>
|
||||||
<BookedRoomSidePeek hotelRoom={booking.room} room={booking} user={user} />
|
<BookedRoomSidePeek hotelRoom={booking.room} room={booking} user={user} />
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton
|
|||||||
import { useMyStayStore } from "@/stores/my-stay"
|
import { useMyStayStore } from "@/stores/my-stay"
|
||||||
|
|
||||||
import BookedRoomSidePeek from "@/components/SidePeeks/BookedRoomSidePeek"
|
import BookedRoomSidePeek from "@/components/SidePeeks/BookedRoomSidePeek"
|
||||||
|
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
||||||
|
|
||||||
|
import { SidePeekEnum } from "@/types/sidepeek"
|
||||||
import type { SafeUser } from "@/types/user"
|
import type { SafeUser } from "@/types/user"
|
||||||
|
|
||||||
interface RoomDetailsSidePeekProps {
|
interface RoomDetailsSidePeekProps {
|
||||||
@@ -21,9 +23,23 @@ export default function RoomDetailsSidePeek({
|
|||||||
}: RoomDetailsSidePeekProps) {
|
}: RoomDetailsSidePeekProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const bookedRoom = useMyStayStore((state) => state.bookedRoom)
|
const bookedRoom = useMyStayStore((state) => state.bookedRoom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogTrigger>
|
<DialogTrigger>
|
||||||
<Button intent="text" size="small" theme="base" variant="icon" wrapping>
|
<Button
|
||||||
|
intent="text"
|
||||||
|
size="small"
|
||||||
|
theme="base"
|
||||||
|
variant="icon"
|
||||||
|
wrapping
|
||||||
|
onPress={() => {
|
||||||
|
trackOpenSidePeekEvent({
|
||||||
|
name: SidePeekEnum.bookedRoomDetails,
|
||||||
|
hotelId: bookedRoom.hotelId,
|
||||||
|
includePathname: true,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
{intl.formatMessage({ defaultMessage: "See room details" })}
|
{intl.formatMessage({ defaultMessage: "See room details" })}
|
||||||
<MaterialIcon icon="chevron_right" size={14} color="CurrentColor" />
|
<MaterialIcon icon="chevron_right" size={14} color="CurrentColor" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { cookies } from "next/headers"
|
import { cookies } from "next/headers"
|
||||||
import { notFound } from "next/navigation"
|
import { notFound } from "next/navigation"
|
||||||
|
|
||||||
import SidePeek from "@scandic-hotels/booking-flow/components/HotelReservationSidePeek"
|
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { logger } from "@scandic-hotels/common/logger"
|
import { logger } from "@scandic-hotels/common/logger"
|
||||||
import * as maskValue from "@scandic-hotels/common/utils/maskValue"
|
import * as maskValue from "@scandic-hotels/common/utils/maskValue"
|
||||||
@@ -268,7 +267,6 @@ export default async function MyStay(props: {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<SidePeek />
|
|
||||||
</MyStayProvider>
|
</MyStayProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ import { getLang } from "@/i18n/serverContext"
|
|||||||
|
|
||||||
import type { HotelsAvailabilityItem } from "@scandic-hotels/trpc/types/availability"
|
import type { HotelsAvailabilityItem } from "@scandic-hotels/trpc/types/availability"
|
||||||
import type { Child } from "@scandic-hotels/trpc/types/child"
|
import type { Child } from "@scandic-hotels/trpc/types/child"
|
||||||
import type { AdditionalData, Hotel } from "@scandic-hotels/trpc/types/hotel"
|
import type {
|
||||||
|
AdditionalData,
|
||||||
|
Hotel,
|
||||||
|
Restaurant,
|
||||||
|
} from "@scandic-hotels/trpc/types/hotel"
|
||||||
import type {
|
import type {
|
||||||
HotelLocation,
|
HotelLocation,
|
||||||
Location,
|
Location,
|
||||||
@@ -32,6 +36,8 @@ export interface HotelResponse {
|
|||||||
availability: HotelsAvailabilityItem
|
availability: HotelsAvailabilityItem
|
||||||
hotel: Hotel
|
hotel: Hotel
|
||||||
additionalData: AdditionalData
|
additionalData: AdditionalData
|
||||||
|
url: string | null
|
||||||
|
restaurants: Restaurant[]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result = AvailabilityResponse | null
|
type Result = AvailabilityResponse | null
|
||||||
@@ -55,6 +61,8 @@ async function enhanceHotels(hotels: HotelsAvailabilityItem[]) {
|
|||||||
availability,
|
availability,
|
||||||
hotel: hotelData.hotel,
|
hotel: hotelData.hotel,
|
||||||
additionalData: hotelData.additionalData,
|
additionalData: hotelData.additionalData,
|
||||||
|
url: hotelData.url,
|
||||||
|
restaurants: hotelData.restaurants,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,25 +4,32 @@ import { useState } from "react"
|
|||||||
import { Button as ButtonRAC } from "react-aria-components"
|
import { Button as ButtonRAC } from "react-aria-components"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import OpenSidePeekButton from "@scandic-hotels/booking-flow/components/OpenSidePeekButton"
|
|
||||||
import { SidePeekEnum } from "@scandic-hotels/booking-flow/stores/sidepeek"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||||
|
import HotelDetailsSidePeek from "@/components/SidePeeks/HotelDetailsSidePeek"
|
||||||
import Alert from "@/components/TempDesignSystem/Alert"
|
import Alert from "@/components/TempDesignSystem/Alert"
|
||||||
|
|
||||||
import styles from "./hotelDescription.module.css"
|
import styles from "./hotelDescription.module.css"
|
||||||
|
|
||||||
import type { Hotel } from "@scandic-hotels/trpc/types/hotel"
|
import type {
|
||||||
|
AdditionalData,
|
||||||
|
Hotel,
|
||||||
|
Restaurant,
|
||||||
|
} from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
export default function HotelDescription({
|
export default function HotelDescription({
|
||||||
description,
|
description,
|
||||||
hotel,
|
hotel,
|
||||||
sortedFacilities,
|
sortedFacilities,
|
||||||
|
restaurants,
|
||||||
|
additionalData,
|
||||||
}: {
|
}: {
|
||||||
description?: string
|
description?: string
|
||||||
hotel: Hotel
|
hotel: Hotel
|
||||||
sortedFacilities: Hotel["detailedFacilities"]
|
sortedFacilities: Hotel["detailedFacilities"]
|
||||||
|
restaurants: Restaurant[]
|
||||||
|
additionalData: AdditionalData | undefined
|
||||||
}) {
|
}) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
@@ -69,13 +76,14 @@ export default function HotelDescription({
|
|||||||
|
|
||||||
{expanded && (
|
{expanded && (
|
||||||
<div className={styles.expandedContent}>
|
<div className={styles.expandedContent}>
|
||||||
<OpenSidePeekButton
|
<HotelDetailsSidePeek
|
||||||
label={intl.formatMessage({
|
hotel={{ ...hotel, url: null }}
|
||||||
|
restaurants={restaurants}
|
||||||
|
additionalHotelData={additionalData}
|
||||||
|
triggerLabel={intl.formatMessage({
|
||||||
defaultMessage: "See all amenities",
|
defaultMessage: "See all amenities",
|
||||||
})}
|
})}
|
||||||
hotelId={hotel.operaId}
|
buttonVariant="primary"
|
||||||
showCTA={false}
|
|
||||||
sidePeekKey={SidePeekEnum.hotelDetails}
|
|
||||||
/>
|
/>
|
||||||
{hotel.specialAlerts.map((alert) => (
|
{hotel.specialAlerts.map((alert) => (
|
||||||
<Alert
|
<Alert
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import OpenSidePeekButton from "@scandic-hotels/booking-flow/components/OpenSidePeekButton"
|
|
||||||
import TripAdvisorChip from "@scandic-hotels/booking-flow/components/TripAdvisorChip"
|
import TripAdvisorChip from "@scandic-hotels/booking-flow/components/TripAdvisorChip"
|
||||||
import { SidePeekEnum } from "@scandic-hotels/booking-flow/stores/sidepeek"
|
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { getSingleDecimal } from "@scandic-hotels/common/utils/numberFormatting"
|
import { getSingleDecimal } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
@@ -9,6 +7,7 @@ import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
|||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||||
|
import HotelDetailsSidePeek from "@/components/SidePeeks/HotelDetailsSidePeek"
|
||||||
import Alert from "@/components/TempDesignSystem/Alert"
|
import Alert from "@/components/TempDesignSystem/Alert"
|
||||||
import { getIntl } from "@/i18n"
|
import { getIntl } from "@/i18n"
|
||||||
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||||
@@ -18,16 +17,27 @@ import HotelDescription from "./HotelDescription"
|
|||||||
|
|
||||||
import styles from "./hotelInfoCard.module.css"
|
import styles from "./hotelInfoCard.module.css"
|
||||||
|
|
||||||
import type { Hotel } from "@scandic-hotels/trpc/types/hotel"
|
import type {
|
||||||
|
AdditionalData,
|
||||||
|
Hotel,
|
||||||
|
Restaurant,
|
||||||
|
} from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
import type { SelectRateBooking } from "@/types/components/hotelReservation/selectRate/selectRate"
|
import type { SelectRateBooking } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||||
|
|
||||||
export type HotelInfoCardProps = {
|
export type HotelInfoCardProps = {
|
||||||
booking: SelectRateBooking
|
booking: SelectRateBooking
|
||||||
hotel: Hotel
|
hotel: Hotel
|
||||||
|
restaurants: Restaurant[]
|
||||||
|
additionalData: AdditionalData | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function HotelInfoCard({ booking, hotel }: HotelInfoCardProps) {
|
export async function HotelInfoCard({
|
||||||
|
booking,
|
||||||
|
hotel,
|
||||||
|
restaurants,
|
||||||
|
additionalData,
|
||||||
|
}: HotelInfoCardProps) {
|
||||||
const intl = await getIntl()
|
const intl = await getIntl()
|
||||||
|
|
||||||
const sortedFacilities = hotel.detailedFacilities
|
const sortedFacilities = hotel.detailedFacilities
|
||||||
@@ -85,6 +95,8 @@ export async function HotelInfoCard({ booking, hotel }: HotelInfoCardProps) {
|
|||||||
key={hotel.operaId}
|
key={hotel.operaId}
|
||||||
description={hotel.hotelContent.texts.descriptions?.medium}
|
description={hotel.hotelContent.texts.descriptions?.medium}
|
||||||
hotel={hotel}
|
hotel={hotel}
|
||||||
|
restaurants={restaurants}
|
||||||
|
additionalData={additionalData}
|
||||||
sortedFacilities={sortedFacilities}
|
sortedFacilities={sortedFacilities}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -101,13 +113,14 @@ export async function HotelInfoCard({ booking, hotel }: HotelInfoCardProps) {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<OpenSidePeekButton
|
<HotelDetailsSidePeek
|
||||||
label={intl.formatMessage({
|
hotel={{ ...hotel, url: null }}
|
||||||
|
restaurants={restaurants}
|
||||||
|
additionalHotelData={additionalData}
|
||||||
|
triggerLabel={intl.formatMessage({
|
||||||
defaultMessage: "See all amenities",
|
defaultMessage: "See all amenities",
|
||||||
})}
|
})}
|
||||||
hotelId={hotel.operaId}
|
buttonVariant="primary"
|
||||||
showCTA={false}
|
|
||||||
sidePeekKey={SidePeekEnum.hotelDetails}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import useSidePeekStore, {
|
|
||||||
SidePeekEnum,
|
|
||||||
} from "@scandic-hotels/booking-flow/stores/sidepeek"
|
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
|
|
||||||
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
|
||||||
|
|
||||||
import styles from "./details.module.css"
|
|
||||||
|
|
||||||
import type { ToggleSidePeekProps } from "@/types/components/hotelReservation/toggleSidePeekProps"
|
|
||||||
|
|
||||||
export default function ToggleSidePeek({
|
|
||||||
hotelId,
|
|
||||||
roomTypeCode,
|
|
||||||
}: ToggleSidePeekProps) {
|
|
||||||
const intl = useIntl()
|
|
||||||
const openSidePeek = useSidePeekStore((state) => state.openSidePeek)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
openSidePeek({
|
|
||||||
key: SidePeekEnum.roomDetails,
|
|
||||||
hotelId,
|
|
||||||
roomTypeCode,
|
|
||||||
})
|
|
||||||
trackOpenSidePeekEvent({
|
|
||||||
name: SidePeekEnum.roomDetails,
|
|
||||||
hotelId,
|
|
||||||
roomTypeCode,
|
|
||||||
includePathname: true,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
size="Small"
|
|
||||||
variant="Text"
|
|
||||||
wrapping
|
|
||||||
typography="Body/Supporting text (caption)/smBold"
|
|
||||||
color="Inverted"
|
|
||||||
className={styles.sidePeekButton}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ defaultMessage: "View room details" })}
|
|
||||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -4,12 +4,13 @@ import { useIntl } from "react-intl"
|
|||||||
|
|
||||||
import ImageGallery from "@scandic-hotels/design-system/ImageGallery"
|
import ImageGallery from "@scandic-hotels/design-system/ImageGallery"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
import { getHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
||||||
|
|
||||||
import { IconForFeatureCode } from "@/components/HotelReservation/utils"
|
import { IconForFeatureCode } from "@/components/HotelReservation/utils"
|
||||||
|
import RoomDetailsSidePeek from "@/components/SidePeeks/RoomDetailsSidePeek"
|
||||||
|
import { useSelectRateContext } from "@/contexts/SelectRate/SelectRateContext"
|
||||||
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||||
|
|
||||||
import ToggleSidePeek from "../Details/ToggleSidePeek"
|
|
||||||
|
|
||||||
import styles from "./image.module.css"
|
import styles from "./image.module.css"
|
||||||
|
|
||||||
import type { ApiImage } from "@scandic-hotels/trpc/types/hotel"
|
import type { ApiImage } from "@scandic-hotels/trpc/types/hotel"
|
||||||
@@ -34,7 +35,9 @@ const RoomImage = memo(function RoomImage({
|
|||||||
hotelId,
|
hotelId,
|
||||||
}: RoomListItemImageProps) {
|
}: RoomListItemImageProps) {
|
||||||
const galleryImages = mapApiImagesToGalleryImages(images || [])
|
const galleryImages = mapApiImagesToGalleryImages(images || [])
|
||||||
|
const { hotel } = useSelectRateContext()
|
||||||
|
const room = getHotelRoom(hotel?.data?.roomCategories ?? [], roomTypeCode)
|
||||||
|
const intl = useIntl()
|
||||||
return (
|
return (
|
||||||
<div className={styles.imageContainer}>
|
<div className={styles.imageContainer}>
|
||||||
<div className={styles.chipContainer}>
|
<div className={styles.chipContainer}>
|
||||||
@@ -53,8 +56,16 @@ const RoomImage = memo(function RoomImage({
|
|||||||
imageCountPosition="top"
|
imageCountPosition="top"
|
||||||
/>
|
/>
|
||||||
<div className={styles.toggleSidePeek}>
|
<div className={styles.toggleSidePeek}>
|
||||||
{roomTypeCode && (
|
{roomTypeCode && room && (
|
||||||
<ToggleSidePeek hotelId={hotelId} roomTypeCode={roomTypeCode} />
|
<RoomDetailsSidePeek
|
||||||
|
hotelId={hotelId}
|
||||||
|
room={room}
|
||||||
|
roomTypeCode={roomTypeCode}
|
||||||
|
triggerLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "View room details",
|
||||||
|
})}
|
||||||
|
buttonVariant="secondary"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,7 +29,12 @@ export default async function SelectRatePage({
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<HotelInfoCard hotel={hotelData.hotel} booking={booking} />
|
<HotelInfoCard
|
||||||
|
hotel={hotelData.hotel}
|
||||||
|
restaurants={hotelData.restaurants}
|
||||||
|
additionalData={hotelData.additionalData}
|
||||||
|
booking={booking}
|
||||||
|
/>
|
||||||
|
|
||||||
{isInValidFNF ? (
|
{isInValidFNF ? (
|
||||||
<FnFNotAllowedAlert />
|
<FnFNotAllowedAlert />
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import AdditionalAmenities from "@scandic-hotels/booking-flow/components/AdditionalAmenities"
|
||||||
|
import Contact from "@scandic-hotels/booking-flow/components/Contact"
|
||||||
|
import BreakfastAccordionItem from "@scandic-hotels/booking-flow/components/SidePeekAccordions/BreakfastAccordionItem"
|
||||||
|
import CheckInCheckOutAccordionItem from "@scandic-hotels/booking-flow/components/SidePeekAccordions/CheckInCheckOutAccordionItem"
|
||||||
|
import ParkingAccordionItem from "@scandic-hotels/booking-flow/components/SidePeekAccordions/ParkingAccordionItem"
|
||||||
|
import Accordion from "@scandic-hotels/design-system/Accordion"
|
||||||
|
import AccordionItem from "@scandic-hotels/design-system/Accordion/AccordionItem"
|
||||||
|
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
|
||||||
|
import { IconName } from "@scandic-hotels/design-system/Icons/iconName"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import { trackAccordionClick } from "@/utils/tracking"
|
||||||
|
|
||||||
|
import styles from "./hotelSidePeek.module.css"
|
||||||
|
|
||||||
|
import type {
|
||||||
|
AdditionalData,
|
||||||
|
Hotel,
|
||||||
|
Restaurant,
|
||||||
|
} from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
|
interface HotelSidePeekContentProps {
|
||||||
|
hotel: Hotel & { url: string | null }
|
||||||
|
restaurants: Restaurant[]
|
||||||
|
additionalHotelData: AdditionalData | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HotelSidePeekContent({
|
||||||
|
hotel,
|
||||||
|
restaurants,
|
||||||
|
additionalHotelData,
|
||||||
|
}: HotelSidePeekContentProps) {
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.content}>
|
||||||
|
<Typography variant="Title/Subtitle/lg">
|
||||||
|
<h3>
|
||||||
|
{intl.formatMessage({ defaultMessage: "Practical information" })}
|
||||||
|
</h3>
|
||||||
|
</Typography>
|
||||||
|
<Contact hotel={hotel} />
|
||||||
|
|
||||||
|
<Accordion>
|
||||||
|
<ParkingAccordionItem
|
||||||
|
parking={hotel.parking}
|
||||||
|
elevatorPitch={additionalHotelData?.hotelParking.elevatorPitch}
|
||||||
|
/>
|
||||||
|
<BreakfastAccordionItem
|
||||||
|
restaurants={restaurants}
|
||||||
|
hotelType={hotel.hotelType}
|
||||||
|
/>
|
||||||
|
<CheckInCheckOutAccordionItem checkInData={hotel.hotelFacts.checkin} />
|
||||||
|
<AccessibilityAccordionItem
|
||||||
|
elevatorPitch={additionalHotelData?.hotelSpecialNeeds.elevatorPitch}
|
||||||
|
/>
|
||||||
|
<AdditionalAmenities amenities={hotel.detailedFacilities} />
|
||||||
|
</Accordion>
|
||||||
|
{hotel.url ? (
|
||||||
|
<ButtonLink
|
||||||
|
href={hotel.url}
|
||||||
|
variant="Secondary"
|
||||||
|
size="Medium"
|
||||||
|
typography="Body/Paragraph/mdBold"
|
||||||
|
>
|
||||||
|
{intl.formatMessage({
|
||||||
|
defaultMessage: "Read more about the hotel",
|
||||||
|
})}
|
||||||
|
</ButtonLink>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessibilityAccordionItemProps = {
|
||||||
|
elevatorPitch?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function AccessibilityAccordionItem({
|
||||||
|
elevatorPitch,
|
||||||
|
}: AccessibilityAccordionItemProps) {
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
|
if (!elevatorPitch) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AccordionItem
|
||||||
|
title={intl.formatMessage({
|
||||||
|
defaultMessage: "Accessibility",
|
||||||
|
})}
|
||||||
|
iconName={IconName.Accessibility}
|
||||||
|
className={styles.accordionItem}
|
||||||
|
variant="sidepeek"
|
||||||
|
onOpen={() => trackAccordionClick("amenities:accessibility")}
|
||||||
|
>
|
||||||
|
<div className={styles.accessibilityContent}>
|
||||||
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
|
<p>{elevatorPitch}</p>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</AccordionItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { DialogTrigger } from "react-aria-components"
|
||||||
|
|
||||||
|
import { Button } from "@scandic-hotels/design-system/Button"
|
||||||
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
|
|
||||||
|
import SidePeekSelfControlled from "@/components/TempDesignSystem/SidePeekSelfControlled"
|
||||||
|
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
||||||
|
|
||||||
|
import { HotelSidePeekContent } from "./HotelSidePeekContent"
|
||||||
|
|
||||||
|
import type {
|
||||||
|
AdditionalData,
|
||||||
|
Hotel,
|
||||||
|
Restaurant,
|
||||||
|
} from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
|
import { SidePeekEnum } from "@/types/sidepeek"
|
||||||
|
|
||||||
|
interface HotelDetailsSidePeekProps {
|
||||||
|
hotel: Hotel & { url: string | null }
|
||||||
|
restaurants: Restaurant[]
|
||||||
|
additionalHotelData: AdditionalData | undefined
|
||||||
|
triggerLabel: string
|
||||||
|
buttonVariant: "primary" | "secondary"
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonPropsMap: Record<
|
||||||
|
HotelDetailsSidePeekProps["buttonVariant"],
|
||||||
|
Pick<
|
||||||
|
React.ComponentProps<typeof Button>,
|
||||||
|
"variant" | "color" | "size" | "typography"
|
||||||
|
>
|
||||||
|
> = {
|
||||||
|
primary: {
|
||||||
|
variant: "Text",
|
||||||
|
color: "Primary",
|
||||||
|
size: "Medium",
|
||||||
|
typography: "Body/Paragraph/mdBold",
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
variant: "Secondary",
|
||||||
|
color: "Inverted",
|
||||||
|
size: "Small",
|
||||||
|
typography: "Body/Supporting text (caption)/smBold",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function HotelDetailsSidePeek({
|
||||||
|
hotel,
|
||||||
|
restaurants,
|
||||||
|
additionalHotelData,
|
||||||
|
triggerLabel,
|
||||||
|
buttonVariant,
|
||||||
|
}: HotelDetailsSidePeekProps) {
|
||||||
|
const buttonProps = buttonPropsMap[buttonVariant]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DialogTrigger>
|
||||||
|
<Button
|
||||||
|
{...buttonProps}
|
||||||
|
wrapping
|
||||||
|
onPress={() =>
|
||||||
|
trackOpenSidePeekEvent({
|
||||||
|
name: SidePeekEnum.hotelDetails,
|
||||||
|
hotelId: hotel.operaId,
|
||||||
|
includePathname: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{triggerLabel}
|
||||||
|
<MaterialIcon
|
||||||
|
icon="chevron_right"
|
||||||
|
size={buttonVariant === "primary" ? 24 : 20}
|
||||||
|
color="CurrentColor"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<SidePeekSelfControlled title={hotel.name}>
|
||||||
|
<HotelSidePeekContent
|
||||||
|
hotel={hotel}
|
||||||
|
restaurants={restaurants}
|
||||||
|
additionalHotelData={additionalHotelData}
|
||||||
|
/>
|
||||||
|
</SidePeekSelfControlled>
|
||||||
|
</DialogTrigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import {
|
||||||
|
BED_TYPE_ICONS,
|
||||||
|
type BedTypes,
|
||||||
|
} from "@scandic-hotels/booking-flow/bedTypeIcons"
|
||||||
import { FacilityIcon } from "@scandic-hotels/design-system/Icons/FacilityIcon"
|
import { FacilityIcon } from "@scandic-hotels/design-system/Icons/FacilityIcon"
|
||||||
import ImageGallery from "@scandic-hotels/design-system/ImageGallery"
|
import ImageGallery from "@scandic-hotels/design-system/ImageGallery"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import { BED_TYPE_ICONS, type BedTypes } from "../../../misc/bedTypeIcons"
|
|
||||||
|
|
||||||
import styles from "./roomSidePeekContent.module.css"
|
import styles from "./roomSidePeekContent.module.css"
|
||||||
|
|
||||||
import type { ApiImage, Room } from "@scandic-hotels/trpc/types/hotel"
|
import type { ApiImage, Room } from "@scandic-hotels/trpc/types/hotel"
|
||||||
@@ -79,7 +81,7 @@ export function RoomSidePeekContent({ room }: RoomSidePeekContentProps) {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
<ul className={styles.facilityList}>
|
<ul className={styles.facilityList}>
|
||||||
{room.roomFacilities
|
{[...room.roomFacilities]
|
||||||
.sort((a, b) => a.sortOrder - b.sortOrder)
|
.sort((a, b) => a.sortOrder - b.sortOrder)
|
||||||
.map((facility) => {
|
.map((facility) => {
|
||||||
return (
|
return (
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { DialogTrigger } from "react-aria-components"
|
||||||
|
|
||||||
|
import { Button } from "@scandic-hotels/design-system/Button"
|
||||||
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
|
|
||||||
|
import SidePeekSelfControlled from "@/components/TempDesignSystem/SidePeekSelfControlled"
|
||||||
|
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
||||||
|
|
||||||
|
import { RoomSidePeekContent } from "./RoomSidePeekContent"
|
||||||
|
|
||||||
|
import type { Room } from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
|
import { SidePeekEnum } from "@/types/sidepeek"
|
||||||
|
|
||||||
|
interface RoomDetailsSidePeekProps {
|
||||||
|
hotelId: string
|
||||||
|
room: Room
|
||||||
|
triggerLabel: string
|
||||||
|
roomTypeCode?: string
|
||||||
|
buttonVariant?: "primary" | "secondary"
|
||||||
|
wrapping?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonPropsMap: Record<
|
||||||
|
NonNullable<RoomDetailsSidePeekProps["buttonVariant"]>,
|
||||||
|
Pick<
|
||||||
|
React.ComponentProps<typeof Button>,
|
||||||
|
"variant" | "color" | "size" | "typography"
|
||||||
|
>
|
||||||
|
> = {
|
||||||
|
primary: {
|
||||||
|
variant: "Text",
|
||||||
|
color: "Primary",
|
||||||
|
size: "Medium",
|
||||||
|
typography: "Body/Paragraph/mdBold",
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
variant: "Text",
|
||||||
|
color: "Inverted",
|
||||||
|
size: "Small",
|
||||||
|
typography: "Body/Supporting text (caption)/smBold",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RoomDetailsSidePeek({
|
||||||
|
hotelId,
|
||||||
|
room,
|
||||||
|
roomTypeCode,
|
||||||
|
triggerLabel,
|
||||||
|
wrapping = true,
|
||||||
|
buttonVariant: variant = "primary",
|
||||||
|
}: RoomDetailsSidePeekProps) {
|
||||||
|
const buttonProps = buttonPropsMap[variant]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DialogTrigger>
|
||||||
|
<Button
|
||||||
|
{...buttonProps}
|
||||||
|
wrapping={wrapping}
|
||||||
|
onPress={() =>
|
||||||
|
trackOpenSidePeekEvent({
|
||||||
|
name: SidePeekEnum.roomDetails,
|
||||||
|
hotelId,
|
||||||
|
roomTypeCode,
|
||||||
|
includePathname: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{triggerLabel}
|
||||||
|
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<SidePeekSelfControlled title={room.name}>
|
||||||
|
<RoomSidePeekContent room={room} />
|
||||||
|
</SidePeekSelfControlled>
|
||||||
|
</DialogTrigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -4,8 +4,8 @@ import { useEffect } from "react"
|
|||||||
import { Dialog, Modal, ModalOverlay } from "react-aria-components"
|
import { Dialog, Modal, ModalOverlay } from "react-aria-components"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import useSetOverflowVisibleOnRA from "@/hooks/useSetOverflowVisibleOnRA"
|
import useSetOverflowVisibleOnRA from "@/hooks/useSetOverflowVisibleOnRA"
|
||||||
@@ -34,19 +34,20 @@ export default function SidePeekSelfControlled({
|
|||||||
<h2>{title}</h2>
|
<h2>{title}</h2>
|
||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
<Button
|
<IconButton
|
||||||
|
theme="Black"
|
||||||
|
style="Muted"
|
||||||
|
onPress={close}
|
||||||
aria-label={intl.formatMessage({
|
aria-label={intl.formatMessage({
|
||||||
defaultMessage: "Close",
|
defaultMessage: "Close",
|
||||||
})}
|
})}
|
||||||
className={styles.closeButton}
|
|
||||||
intent="text"
|
|
||||||
onPress={close}
|
|
||||||
>
|
>
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
icon="close"
|
icon="close"
|
||||||
|
size={24}
|
||||||
color="Icon/Interactive/Default"
|
color="Icon/Interactive/Default"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</IconButton>
|
||||||
</header>
|
</header>
|
||||||
<div className={styles.sidePeekContent}>{children}</div>
|
<div className={styles.sidePeekContent}>{children}</div>
|
||||||
<KeepBodyVisible />
|
<KeepBodyVisible />
|
||||||
|
|||||||
@@ -72,10 +72,6 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.closeButton {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
color: var(--Text-Heading);
|
color: var(--Text-Heading);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export default function EnterDetailsProvider({
|
|||||||
searchParamsStr,
|
searchParamsStr,
|
||||||
user,
|
user,
|
||||||
vat,
|
vat,
|
||||||
|
roomCategories,
|
||||||
}: DetailsProviderProps) {
|
}: DetailsProviderProps) {
|
||||||
// This state is needed to be able to use defaultValues for
|
// This state is needed to be able to use defaultValues for
|
||||||
// react-hook-form since values needs to be there on mount
|
// react-hook-form since values needs to be there on mount
|
||||||
@@ -70,6 +71,7 @@ export default function EnterDetailsProvider({
|
|||||||
isFlexRate: room.isFlexRate,
|
isFlexRate: room.isFlexRate,
|
||||||
})),
|
})),
|
||||||
vat,
|
vat,
|
||||||
|
roomCategories,
|
||||||
}
|
}
|
||||||
|
|
||||||
storeRef.current = createDetailsStore(
|
storeRef.current = createDetailsStore(
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ export function createDetailsStore(
|
|||||||
return create<DetailsState>()((set) => ({
|
return create<DetailsState>()((set) => ({
|
||||||
availableBeds,
|
availableBeds,
|
||||||
booking: initialState.booking,
|
booking: initialState.booking,
|
||||||
|
roomCategories: initialState.roomCategories,
|
||||||
breakfastPackages,
|
breakfastPackages,
|
||||||
canProceedToPayment: false,
|
canProceedToPayment: false,
|
||||||
isSubmitting: false,
|
isSubmitting: false,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { produce } from "immer"
|
|||||||
import { useContext } from "react"
|
import { useContext } from "react"
|
||||||
import { create, useStore } from "zustand"
|
import { create, useStore } from "zustand"
|
||||||
|
|
||||||
import { getBookedHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
import { getHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
||||||
|
|
||||||
import { mapRoomDetails } from "@/components/HotelReservation/MyStay/utils/mapRoomDetails"
|
import { mapRoomDetails } from "@/components/HotelReservation/MyStay/utils/mapRoomDetails"
|
||||||
import { MyStayContext } from "@/contexts/MyStay"
|
import { MyStayContext } from "@/contexts/MyStay"
|
||||||
@@ -39,7 +39,7 @@ export function createMyStayStore({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mappedRooms = rooms.map((booking, idx) => {
|
const mappedRooms = rooms.map((booking, idx) => {
|
||||||
const room = getBookedHotelRoom(roomCategories, booking.roomTypeCode)
|
const room = getHotelRoom(roomCategories, booking.roomTypeCode)
|
||||||
return mapRoomDetails({
|
return mapRoomDetails({
|
||||||
booking,
|
booking,
|
||||||
rates,
|
rates,
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import type { SidePeekEnum } from "@scandic-hotels/booking-flow/stores/sidepeek"
|
|
||||||
import type {
|
|
||||||
AdditionalData,
|
|
||||||
Hotel,
|
|
||||||
Restaurant,
|
|
||||||
} from "@scandic-hotels/trpc/types/hotel"
|
|
||||||
|
|
||||||
export type AmenitiesSidePeekProps = {
|
|
||||||
hotel: Hotel & { url: string | null }
|
|
||||||
restaurants: Restaurant[]
|
|
||||||
additionalHotelData: AdditionalData | undefined
|
|
||||||
activeSidePeek: SidePeekEnum
|
|
||||||
close: () => void
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
|
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
export interface HotelHeaderProps {
|
export interface HotelHeaderProps {
|
||||||
hotelData: HotelData
|
hotelData: HotelData & { url: string | null }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import type { SafeUser } from "@/types/user"
|
|
||||||
|
|
||||||
export type ToggleSidePeekProps = {
|
|
||||||
hotelId: string
|
|
||||||
roomTypeCode?: string
|
|
||||||
title?: string
|
|
||||||
user?: SafeUser
|
|
||||||
confirmationNumber?: string
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
|
import type { RoomCategories } from "@scandic-hotels/trpc/types/hotel"
|
||||||
import type { Room } from "@scandic-hotels/trpc/types/room"
|
import type { Room } from "@scandic-hotels/trpc/types/room"
|
||||||
|
|
||||||
import type { SafeUser } from "@/types/user"
|
import type { SafeUser } from "@/types/user"
|
||||||
@@ -13,4 +14,5 @@ export interface DetailsProviderProps extends React.PropsWithChildren {
|
|||||||
searchParamsStr: string
|
searchParamsStr: string
|
||||||
user: SafeUser
|
user: SafeUser
|
||||||
vat: number
|
vat: number
|
||||||
|
roomCategories: RoomCategories
|
||||||
}
|
}
|
||||||
|
|||||||
5
apps/scandic-web/types/sidepeek.ts
Normal file
5
apps/scandic-web/types/sidepeek.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum SidePeekEnum {
|
||||||
|
hotelDetails = "hotel-detail-side-peek",
|
||||||
|
roomDetails = "room-detail-side-peek",
|
||||||
|
bookedRoomDetails = "booked-room-detail-side-peek",
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
||||||
import type { BedTypeSelection } from "@scandic-hotels/trpc/types/bedTypeSelection"
|
import type { BedTypeSelection } from "@scandic-hotels/trpc/types/bedTypeSelection"
|
||||||
import type { Child } from "@scandic-hotels/trpc/types/child"
|
import type { Child } from "@scandic-hotels/trpc/types/child"
|
||||||
|
import type { RoomCategories } from "@scandic-hotels/trpc/types/hotel"
|
||||||
import type { Packages } from "@scandic-hotels/trpc/types/packages"
|
import type { Packages } from "@scandic-hotels/trpc/types/packages"
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@@ -80,6 +81,7 @@ export type InitialState = {
|
|||||||
booking: DetailsBooking
|
booking: DetailsBooking
|
||||||
rooms: InitialRoomData[]
|
rooms: InitialRoomData[]
|
||||||
vat: number
|
vat: number
|
||||||
|
roomCategories: RoomCategories
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DetailsState {
|
export interface DetailsState {
|
||||||
@@ -100,6 +102,7 @@ export interface DetailsState {
|
|||||||
searchParamString: string
|
searchParamString: string
|
||||||
totalPrice: Price
|
totalPrice: Price
|
||||||
vat: number
|
vat: number
|
||||||
|
roomCategories: RoomCategories
|
||||||
defaultCurrency: CurrencyEnum
|
defaultCurrency: CurrencyEnum
|
||||||
preSubmitCallbacks: Record<string, () => void>
|
preSubmitCallbacks: Record<string, () => void>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,9 +59,3 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
|
||||||
text-decoration: underline;
|
|
||||||
font-family: var(--typography-Body-Regular-fontFamily);
|
|
||||||
color: var(--Text-Interactive-Secondary);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import Body from "@scandic-hotels/design-system/Body"
|
|
||||||
import FacebookIcon from "@scandic-hotels/design-system/Icons/FacebookIcon"
|
import FacebookIcon from "@scandic-hotels/design-system/Icons/FacebookIcon"
|
||||||
import InstagramIcon from "@scandic-hotels/design-system/Icons/InstagramIcon"
|
import InstagramIcon from "@scandic-hotels/design-system/Icons/InstagramIcon"
|
||||||
import Image from "@scandic-hotels/design-system/Image"
|
import Image from "@scandic-hotels/design-system/Image"
|
||||||
@@ -13,6 +12,7 @@ import useLang from "../../hooks/useLang"
|
|||||||
import styles from "./contact.module.css"
|
import styles from "./contact.module.css"
|
||||||
|
|
||||||
import type { Hotel } from "@scandic-hotels/trpc/types/hotel"
|
import type { Hotel } from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
interface ContactProps {
|
interface ContactProps {
|
||||||
hotel: Hotel
|
hotel: Hotel
|
||||||
@@ -30,55 +30,67 @@ export default function Contact({ hotel }: ContactProps) {
|
|||||||
<address className={styles.address}>
|
<address className={styles.address}>
|
||||||
<ul className={styles.contactInfo}>
|
<ul className={styles.contactInfo}>
|
||||||
<li>
|
<li>
|
||||||
<Body textTransform="bold">
|
<Typography variant="Body/Paragraph/mdBold">
|
||||||
{intl.formatMessage({
|
<p>
|
||||||
defaultMessage: "Address",
|
{intl.formatMessage({
|
||||||
})}
|
defaultMessage: "Address",
|
||||||
</Body>
|
})}
|
||||||
<Body>
|
</p>
|
||||||
{addressStr}
|
</Typography>
|
||||||
<br />
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
{cityStr}
|
<p>
|
||||||
</Body>
|
{addressStr}
|
||||||
|
<br />
|
||||||
|
{cityStr}
|
||||||
|
</p>
|
||||||
|
</Typography>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Body textTransform="bold">
|
<Typography variant="Body/Paragraph/mdBold">
|
||||||
{intl.formatMessage({
|
<p>
|
||||||
defaultMessage: "Driving directions",
|
{intl.formatMessage({
|
||||||
})}
|
defaultMessage: "Driving directions",
|
||||||
</Body>
|
})}
|
||||||
|
</p>
|
||||||
|
</Typography>
|
||||||
<Link
|
<Link
|
||||||
href={`https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(
|
href={`https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(
|
||||||
`${hotel.name}, ${hotel.address.streetAddress}, ${hotel.address.zipCode} ${hotel.address.city}`
|
`${hotel.name}, ${hotel.address.streetAddress}, ${hotel.address.zipCode} ${hotel.address.city}`
|
||||||
)}`}
|
)}`}
|
||||||
>
|
>
|
||||||
<span className={styles.link}>
|
<Typography variant="Body/Underline/md">
|
||||||
{intl.formatMessage({
|
<p>
|
||||||
defaultMessage: "Google Maps",
|
{intl.formatMessage({
|
||||||
})}
|
defaultMessage: "Google Maps",
|
||||||
</span>
|
})}
|
||||||
|
</p>
|
||||||
|
</Typography>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Body textTransform="bold">
|
<Typography variant="Body/Paragraph/mdBold">
|
||||||
{intl.formatMessage({
|
<p>
|
||||||
defaultMessage: "Contact us",
|
{intl.formatMessage({
|
||||||
})}
|
defaultMessage: "Contact us",
|
||||||
</Body>
|
})}
|
||||||
|
</p>
|
||||||
|
</Typography>
|
||||||
<Link href={`tel:${hotel.contactInformation.phoneNumber}`}>
|
<Link href={`tel:${hotel.contactInformation.phoneNumber}`}>
|
||||||
<span className={styles.link}>
|
<Typography variant="Body/Underline/md">
|
||||||
{hotel.contactInformation.phoneNumber}
|
<p>{hotel.contactInformation.phoneNumber}</p>
|
||||||
</span>
|
</Typography>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
{(hotel.socialMedia.facebook || hotel.socialMedia.instagram) && (
|
{(hotel.socialMedia.facebook || hotel.socialMedia.instagram) && (
|
||||||
<>
|
<>
|
||||||
<Body textTransform="bold">
|
<Typography variant="Body/Paragraph/mdBold">
|
||||||
{intl.formatMessage({
|
<p>
|
||||||
defaultMessage: "Follow us",
|
{intl.formatMessage({
|
||||||
})}
|
defaultMessage: "Follow us",
|
||||||
</Body>
|
})}
|
||||||
|
</p>
|
||||||
|
</Typography>
|
||||||
<div className={styles.soMeIcons}>
|
<div className={styles.soMeIcons}>
|
||||||
{hotel.socialMedia.instagram && (
|
{hotel.socialMedia.instagram && (
|
||||||
<Link href={hotel.socialMedia.instagram} target="_blank">
|
<Link href={hotel.socialMedia.instagram} target="_blank">
|
||||||
@@ -95,15 +107,17 @@ export default function Contact({ hotel }: ContactProps) {
|
|||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Body textTransform="bold">
|
<Typography variant="Body/Paragraph/mdBold">
|
||||||
{intl.formatMessage({
|
<p>
|
||||||
defaultMessage: "Email",
|
{intl.formatMessage({
|
||||||
})}
|
defaultMessage: "Email",
|
||||||
</Body>
|
})}
|
||||||
|
</p>
|
||||||
|
</Typography>
|
||||||
<Link href={`mailto:${hotel.contactInformation.email}`}>
|
<Link href={`mailto:${hotel.contactInformation.email}`}>
|
||||||
<span className={styles.link}>
|
<Typography variant="Body/Underline/md">
|
||||||
{hotel.contactInformation.email}
|
<p>{hotel.contactInformation.email}</p>
|
||||||
</span>
|
</Typography>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
.spacing {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--Spacing-x2);
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useEffect } from "react"
|
|
||||||
|
|
||||||
import { trpc } from "@scandic-hotels/trpc/client"
|
|
||||||
|
|
||||||
import useLang from "../../hooks/useLang"
|
|
||||||
import useSidePeekStore from "../../stores/sidepeek"
|
|
||||||
import HotelSidePeek from "../HotelSidePeek"
|
|
||||||
import RoomSidePeek from "../RoomSidePeek"
|
|
||||||
|
|
||||||
export default function HotelReservationSidePeek() {
|
|
||||||
const { activeSidePeek, hotelId, roomTypeCode, showCTA } = useSidePeekStore(
|
|
||||||
(state) => ({
|
|
||||||
activeSidePeek: state.activeSidePeek,
|
|
||||||
hotelId: state.hotelId,
|
|
||||||
roomTypeCode: state.roomTypeCode,
|
|
||||||
showCTA: state.showCTA,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
const closeFn = useSidePeekStore((state) => state.closeSidePeek)
|
|
||||||
const lang = useLang()
|
|
||||||
|
|
||||||
const { data: hotelData } = trpc.hotel.get.useQuery(
|
|
||||||
{
|
|
||||||
hotelId: hotelId ?? "",
|
|
||||||
language: lang,
|
|
||||||
isCardOnlyPayment: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: !!hotelId,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const selectedRoom = hotelData?.roomCategories.find((room) =>
|
|
||||||
room.roomTypes.some((type) => type.code === roomTypeCode)
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (activeSidePeek) {
|
|
||||||
window.history.pushState(null, "", window.location.href)
|
|
||||||
}
|
|
||||||
}, [activeSidePeek])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
function handlePopState() {
|
|
||||||
if (activeSidePeek) {
|
|
||||||
closeFn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("popstate", handlePopState)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("popstate", handlePopState)
|
|
||||||
}
|
|
||||||
}, [activeSidePeek, closeFn])
|
|
||||||
|
|
||||||
if (activeSidePeek) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{hotelData && (
|
|
||||||
<HotelSidePeek
|
|
||||||
additionalHotelData={hotelData.additionalData}
|
|
||||||
hotel={{ ...hotelData.hotel, url: hotelData.url }}
|
|
||||||
restaurants={hotelData.restaurants}
|
|
||||||
activeSidePeek={activeSidePeek}
|
|
||||||
close={closeFn}
|
|
||||||
showCTA={showCTA}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{selectedRoom && (
|
|
||||||
<RoomSidePeek
|
|
||||||
room={selectedRoom}
|
|
||||||
activeSidePeek={activeSidePeek}
|
|
||||||
close={closeFn}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import Accordion from "@scandic-hotels/design-system/Accordion"
|
|
||||||
import AccordionItem from "@scandic-hotels/design-system/Accordion/AccordionItem"
|
|
||||||
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
|
|
||||||
import { IconName } from "@scandic-hotels/design-system/Icons/iconName"
|
|
||||||
import SidePeek from "@scandic-hotels/design-system/SidePeek"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
|
||||||
|
|
||||||
import { SidePeekEnum } from "../../stores/sidepeek"
|
|
||||||
import { useTrackingContext } from "../../trackingContext"
|
|
||||||
import AdditionalAmenities from "../AdditionalAmenities"
|
|
||||||
import Contact from "../Contact"
|
|
||||||
import BreakfastAccordionItem from "../SidePeekAccordions/BreakfastAccordionItem"
|
|
||||||
import CheckInCheckOutAccordionItem from "../SidePeekAccordions/CheckInCheckOutAccordionItem"
|
|
||||||
import ParkingAccordionItem from "../SidePeekAccordions/ParkingAccordionItem"
|
|
||||||
|
|
||||||
import styles from "./hotelSidePeek.module.css"
|
|
||||||
|
|
||||||
import type {
|
|
||||||
AdditionalData,
|
|
||||||
Hotel,
|
|
||||||
Restaurant,
|
|
||||||
} from "@scandic-hotels/trpc/types/hotel"
|
|
||||||
|
|
||||||
type HotelSidePeekProps = {
|
|
||||||
hotel: Hotel & { url: string | null }
|
|
||||||
restaurants: Restaurant[]
|
|
||||||
additionalHotelData: AdditionalData | undefined
|
|
||||||
activeSidePeek: SidePeekEnum
|
|
||||||
close: () => void
|
|
||||||
showCTA: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function HotelSidePeek({
|
|
||||||
hotel,
|
|
||||||
restaurants,
|
|
||||||
additionalHotelData,
|
|
||||||
activeSidePeek,
|
|
||||||
close,
|
|
||||||
}: HotelSidePeekProps) {
|
|
||||||
const intl = useIntl()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SidePeek
|
|
||||||
title={hotel.name}
|
|
||||||
isOpen={activeSidePeek === SidePeekEnum.hotelDetails}
|
|
||||||
handleClose={close}
|
|
||||||
closeLabel={intl.formatMessage({
|
|
||||||
defaultMessage: "Close",
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<div className={styles.content}>
|
|
||||||
<Typography variant="Title/Subtitle/lg">
|
|
||||||
<h3>
|
|
||||||
{intl.formatMessage({ defaultMessage: "Practical information" })}
|
|
||||||
</h3>
|
|
||||||
</Typography>
|
|
||||||
<Contact hotel={hotel} />
|
|
||||||
|
|
||||||
<Accordion>
|
|
||||||
<ParkingAccordionItem
|
|
||||||
parking={hotel.parking}
|
|
||||||
elevatorPitch={additionalHotelData?.hotelParking.elevatorPitch}
|
|
||||||
/>
|
|
||||||
<BreakfastAccordionItem
|
|
||||||
restaurants={restaurants}
|
|
||||||
hotelType={hotel.hotelType}
|
|
||||||
/>
|
|
||||||
<CheckInCheckOutAccordionItem
|
|
||||||
checkInData={hotel.hotelFacts.checkin}
|
|
||||||
/>
|
|
||||||
<AccessibilityAccordionItem
|
|
||||||
elevatorPitch={additionalHotelData?.hotelSpecialNeeds.elevatorPitch}
|
|
||||||
/>
|
|
||||||
<AdditionalAmenities amenities={hotel.detailedFacilities} />
|
|
||||||
</Accordion>
|
|
||||||
{hotel.url ? (
|
|
||||||
<ButtonLink
|
|
||||||
href={hotel.url}
|
|
||||||
variant="Secondary"
|
|
||||||
size="Medium"
|
|
||||||
typography="Body/Paragraph/mdBold"
|
|
||||||
>
|
|
||||||
{intl.formatMessage({
|
|
||||||
defaultMessage: "Read more about the hotel",
|
|
||||||
})}
|
|
||||||
</ButtonLink>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</SidePeek>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccessibilityAccordionItemProps = {
|
|
||||||
elevatorPitch?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
function AccessibilityAccordionItem({
|
|
||||||
elevatorPitch,
|
|
||||||
}: AccessibilityAccordionItemProps) {
|
|
||||||
const intl = useIntl()
|
|
||||||
const tracking = useTrackingContext()
|
|
||||||
|
|
||||||
if (!elevatorPitch) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AccordionItem
|
|
||||||
title={intl.formatMessage({
|
|
||||||
defaultMessage: "Accessibility",
|
|
||||||
})}
|
|
||||||
iconName={IconName.Accessibility}
|
|
||||||
className={styles.accordionItem}
|
|
||||||
variant="sidepeek"
|
|
||||||
onOpen={() => tracking.trackAccordionItemOpen("amenities:accessibility")}
|
|
||||||
>
|
|
||||||
<div className={styles.accessibilityContent}>
|
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
|
||||||
<p>{elevatorPitch}</p>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</AccordionItem>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
"use client"
|
|
||||||
import { useEffect } from "react"
|
|
||||||
|
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
|
|
||||||
import useSidePeekStore, { type SidePeekEnum } from "../../stores/sidepeek"
|
|
||||||
import { useTrackingContext } from "../../trackingContext"
|
|
||||||
|
|
||||||
interface OpenSidePeekButtonProps {
|
|
||||||
label: string
|
|
||||||
hotelId: string
|
|
||||||
showCTA: boolean
|
|
||||||
sidePeekKey: SidePeekEnum
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function OpenSidePeekButton({
|
|
||||||
label,
|
|
||||||
hotelId,
|
|
||||||
showCTA,
|
|
||||||
sidePeekKey,
|
|
||||||
}: OpenSidePeekButtonProps) {
|
|
||||||
const tracking = useTrackingContext()
|
|
||||||
const { openSidePeek, closeSidePeek } = useSidePeekStore((state) => ({
|
|
||||||
openSidePeek: state.openSidePeek,
|
|
||||||
closeSidePeek: state.closeSidePeek,
|
|
||||||
}))
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
closeSidePeek()
|
|
||||||
}
|
|
||||||
}, [closeSidePeek])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
onPress={() => {
|
|
||||||
openSidePeek({ key: sidePeekKey, hotelId, showCTA })
|
|
||||||
tracking.trackOpenSidePeek({
|
|
||||||
name: sidePeekKey,
|
|
||||||
hotelId,
|
|
||||||
includePathname: true,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
variant="Text"
|
|
||||||
typography="Body/Paragraph/mdBold"
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
<MaterialIcon icon="chevron_right" size={24} color="CurrentColor" />
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import SidePeek from "@scandic-hotels/design-system/SidePeek"
|
|
||||||
|
|
||||||
import { SidePeekEnum } from "../../stores/sidepeek"
|
|
||||||
import { RoomSidePeekContent } from "./RoomSidePeekContent"
|
|
||||||
|
|
||||||
import type { Room } from "@scandic-hotels/trpc/types/hotel"
|
|
||||||
|
|
||||||
export type RoomSidePeekProps = {
|
|
||||||
room: Room
|
|
||||||
activeSidePeek: SidePeekEnum | null
|
|
||||||
close: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function RoomSidePeek({
|
|
||||||
room,
|
|
||||||
activeSidePeek,
|
|
||||||
close,
|
|
||||||
}: RoomSidePeekProps) {
|
|
||||||
const intl = useIntl()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SidePeek
|
|
||||||
title={room.name}
|
|
||||||
isOpen={activeSidePeek === SidePeekEnum.roomDetails}
|
|
||||||
handleClose={close}
|
|
||||||
closeLabel={intl.formatMessage({
|
|
||||||
defaultMessage: "Close",
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<RoomSidePeekContent room={room} />
|
|
||||||
</SidePeek>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import { create } from "zustand"
|
|
||||||
|
|
||||||
export enum SidePeekEnum {
|
|
||||||
hotelDetails = "hotel-detail-side-peek",
|
|
||||||
roomDetails = "room-detail-side-peek",
|
|
||||||
bookedRoomDetails = "booked-room-detail-side-peek",
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SidePeekState {
|
|
||||||
activeSidePeek: SidePeekEnum | null
|
|
||||||
hotelId: string | null
|
|
||||||
roomTypeCode: string | null
|
|
||||||
showCTA: boolean
|
|
||||||
confirmationNumber: string
|
|
||||||
openSidePeek: ({
|
|
||||||
key,
|
|
||||||
hotelId,
|
|
||||||
roomTypeCode,
|
|
||||||
showCTA,
|
|
||||||
confirmationNumber,
|
|
||||||
}: {
|
|
||||||
key: SidePeekEnum | null
|
|
||||||
hotelId: string
|
|
||||||
roomTypeCode?: string
|
|
||||||
showCTA?: boolean
|
|
||||||
confirmationNumber?: string
|
|
||||||
}) => void
|
|
||||||
closeSidePeek: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const useSidePeekStore = create<SidePeekState>((set) => ({
|
|
||||||
activeSidePeek: null,
|
|
||||||
hotelId: null,
|
|
||||||
roomTypeCode: null,
|
|
||||||
showCTA: true,
|
|
||||||
user: null,
|
|
||||||
confirmationNumber: "",
|
|
||||||
openSidePeek: ({
|
|
||||||
key,
|
|
||||||
hotelId,
|
|
||||||
roomTypeCode,
|
|
||||||
showCTA,
|
|
||||||
confirmationNumber,
|
|
||||||
}) => {
|
|
||||||
set({
|
|
||||||
activeSidePeek: key,
|
|
||||||
hotelId,
|
|
||||||
roomTypeCode,
|
|
||||||
showCTA,
|
|
||||||
confirmationNumber,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
closeSidePeek: () =>
|
|
||||||
set({
|
|
||||||
activeSidePeek: null,
|
|
||||||
hotelId: null,
|
|
||||||
roomTypeCode: null,
|
|
||||||
confirmationNumber: "",
|
|
||||||
}),
|
|
||||||
}))
|
|
||||||
|
|
||||||
export default useSidePeekStore
|
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
"./searchType": "./lib/misc/searchType.ts",
|
"./searchType": "./lib/misc/searchType.ts",
|
||||||
"./bedTypeIcons": "./lib/misc/bedTypeIcons.ts",
|
"./bedTypeIcons": "./lib/misc/bedTypeIcons.ts",
|
||||||
"./stores/bookingCode-filter": "./lib/stores/bookingCode-filter.ts",
|
"./stores/bookingCode-filter": "./lib/stores/bookingCode-filter.ts",
|
||||||
"./stores/sidepeek": "./lib/stores/sidepeek.ts",
|
|
||||||
"./components/TripAdvisorChip": "./lib/components/TripAdvisorChip/index.tsx",
|
"./components/TripAdvisorChip": "./lib/components/TripAdvisorChip/index.tsx",
|
||||||
|
"./components/Contact": "./lib/components/Contact/index.tsx",
|
||||||
"./components/AdditionalAmenities": "./lib/components/AdditionalAmenities/index.tsx",
|
"./components/AdditionalAmenities": "./lib/components/AdditionalAmenities/index.tsx",
|
||||||
"./components/HotelReservationSidePeek": "./lib/components/HotelReservationSidePeek/index.tsx",
|
"./components/HotelReservationSidePeek": "./lib/components/HotelReservationSidePeek/index.tsx",
|
||||||
"./components/RoomSidePeekContent": "./lib/components/RoomSidePeek/RoomSidePeekContent/index.tsx",
|
"./components/RoomSidePeekContent": "./lib/components/RoomSidePeek/RoomSidePeekContent/index.tsx",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { BookingConfirmation } from "../../types/bookingConfirmation"
|
import type { BookingConfirmation } from "../../types/bookingConfirmation"
|
||||||
import type { Room } from "../../types/hotel"
|
import type { Room } from "../../types/hotel"
|
||||||
|
|
||||||
export function getBookedHotelRoom(
|
export function getHotelRoom(
|
||||||
rooms: Room[],
|
rooms: Room[],
|
||||||
roomTypeCode: BookingConfirmation["booking"]["roomTypeCode"]
|
roomTypeCode: BookingConfirmation["booking"]["roomTypeCode"]
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { getHotel } from "../../routers/hotels/utils"
|
|||||||
import { toApiLang } from "../../utils"
|
import { toApiLang } from "../../utils"
|
||||||
import { encrypt } from "../../utils/encryption"
|
import { encrypt } from "../../utils/encryption"
|
||||||
import { isValidSession } from "../../utils/session"
|
import { isValidSession } from "../../utils/session"
|
||||||
import { getBookedHotelRoom } from "./helpers"
|
import { getHotelRoom } from "./helpers"
|
||||||
import {
|
import {
|
||||||
createRefIdInput,
|
createRefIdInput,
|
||||||
findBookingInput,
|
findBookingInput,
|
||||||
@@ -85,10 +85,7 @@ export const bookingQueryRouter = router({
|
|||||||
return {
|
return {
|
||||||
...hotelData,
|
...hotelData,
|
||||||
booking,
|
booking,
|
||||||
room: getBookedHotelRoom(
|
room: getHotelRoom(hotelData.roomCategories, booking.roomTypeCode),
|
||||||
hotelData.roomCategories,
|
|
||||||
booking.roomTypeCode
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
findBooking: safeProtectedServiceProcedure
|
findBooking: safeProtectedServiceProcedure
|
||||||
@@ -158,10 +155,7 @@ export const bookingQueryRouter = router({
|
|||||||
return {
|
return {
|
||||||
...hotelData,
|
...hotelData,
|
||||||
booking,
|
booking,
|
||||||
room: getBookedHotelRoom(
|
room: getHotelRoom(hotelData.roomCategories, booking.roomTypeCode),
|
||||||
hotelData.roomCategories,
|
|
||||||
booking.roomTypeCode
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
linkedReservations: safeProtectedServiceProcedure
|
linkedReservations: safeProtectedServiceProcedure
|
||||||
|
|||||||
Reference in New Issue
Block a user