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()}
|
||||
user={user}
|
||||
vat={hotel.vat}
|
||||
roomCategories={hotelData.roomCategories}
|
||||
>
|
||||
<HotelHeader hotelData={hotelData} />
|
||||
<div className={styles.container}>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import SidePeek from "@scandic-hotels/booking-flow/components/HotelReservationSidePeek"
|
||||
|
||||
import styles from "./layout.module.css"
|
||||
|
||||
import type { LangParams, LayoutArgs } from "@/types/params"
|
||||
@@ -7,10 +5,5 @@ import type { LangParams, LayoutArgs } from "@/types/params"
|
||||
export default function StandardHotelReservationLayout({
|
||||
children,
|
||||
}: React.PropsWithChildren<LayoutArgs<LangParams>>) {
|
||||
return (
|
||||
<div className={styles.layout}>
|
||||
{children}
|
||||
<SidePeek />
|
||||
</div>
|
||||
)
|
||||
return <div className={styles.layout}>{children}</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 Image from "@scandic-hotels/design-system/Image"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
import { getHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
||||
|
||||
import { CancellationRuleEnum } from "@/constants/booking"
|
||||
import { useBookingConfirmationStore } from "@/stores/booking-confirmation"
|
||||
|
||||
import RoomDetailsSidePeek from "@/components/SidePeeks/RoomDetailsSidePeek"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import RoomDetailsSidePeek from "./RoomDetailsSidePeek"
|
||||
|
||||
import styles from "./room.module.css"
|
||||
|
||||
import type { RoomProps } from "@/types/components/hotelReservation/bookingConfirmation/rooms/room"
|
||||
@@ -31,6 +32,10 @@ export default function Room({
|
||||
}: RoomProps) {
|
||||
const intl = useIntl()
|
||||
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 fromDate = dt(booking.checkInDate).locale(lang)
|
||||
@@ -116,7 +121,18 @@ export default function Room({
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h2>{roomName}</h2>
|
||||
</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>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<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 { 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 type { HotelHeaderProps } from "@/types/components/hotelReservation/enterDetails/hotelHeader"
|
||||
|
||||
export default async function HotelHeader({
|
||||
hotelData: { hotel },
|
||||
hotelData: { hotel, url, restaurants, additionalData },
|
||||
}: HotelHeaderProps) {
|
||||
const image = hotel.hotelContent?.images
|
||||
|
||||
const intl = await getIntl()
|
||||
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
|
||||
|
||||
return (
|
||||
@@ -49,7 +50,16 @@ export default async function HotelHeader({
|
||||
<div className={styles.address}>{addressStr}</div>
|
||||
</Typography>
|
||||
</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>
|
||||
</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 { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import Subtitle from "@scandic-hotels/design-system/Subtitle"
|
||||
import { getHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
||||
|
||||
import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||
|
||||
import RoomDetailsSidePeek from "@/components/SidePeeks/RoomDetailsSidePeek"
|
||||
import { useRoomContext } from "@/contexts/Details/Room"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import ToggleSidePeek from "./ToggleSidePeek"
|
||||
|
||||
import styles from "./selectedRoom.module.css"
|
||||
|
||||
export default function SelectedRoom() {
|
||||
@@ -25,10 +25,13 @@ export default function SelectedRoom() {
|
||||
const router = useRouter()
|
||||
const [isPending, startTransition] = useTransition()
|
||||
const { room, idx } = useRoomContext()
|
||||
const { hotelId, searchParamsStr } = useEnterDetailsStore((state) => ({
|
||||
hotelId: state.booking.hotelId,
|
||||
searchParamsStr: state.searchParamString,
|
||||
}))
|
||||
const { hotelId, roomCategories, searchParamsStr } = useEnterDetailsStore(
|
||||
(state) => ({
|
||||
hotelId: state.booking.hotelId,
|
||||
roomCategories: state.roomCategories,
|
||||
searchParamsStr: state.searchParamString,
|
||||
})
|
||||
)
|
||||
|
||||
function changeRoom() {
|
||||
const searchParams = new URLSearchParams(searchParamsStr)
|
||||
@@ -39,6 +42,8 @@ export default function SelectedRoom() {
|
||||
})
|
||||
}
|
||||
|
||||
const selectedRoom = getHotelRoom(roomCategories, room.roomTypeCode)
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper} data-available={room.isAvailable}>
|
||||
<div className={styles.main}>
|
||||
@@ -79,6 +84,7 @@ export default function SelectedRoom() {
|
||||
size="Small"
|
||||
onPress={changeRoom}
|
||||
isDisabled={isPending}
|
||||
wrapping={false}
|
||||
typography="Body/Supporting text (caption)/smBold"
|
||||
>
|
||||
<MaterialIcon icon="edit_square" size={20} color="CurrentColor" />
|
||||
@@ -87,11 +93,17 @@ export default function SelectedRoom() {
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
{room.roomTypeCode && (
|
||||
{room.roomTypeCode && selectedRoom && (
|
||||
<div className={styles.details}>
|
||||
<ToggleSidePeek
|
||||
<RoomDetailsSidePeek
|
||||
hotelId={hotelId}
|
||||
roomTypeCode={room.roomTypeCode}
|
||||
room={selectedRoom}
|
||||
buttonVariant="primary"
|
||||
triggerLabel={intl.formatMessage({
|
||||
defaultMessage: "See room details",
|
||||
})}
|
||||
wrapping={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
.details {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: var(--Space-x05);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
|
||||
@@ -10,9 +10,7 @@ import {
|
||||
import { memo } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import OpenSidePeekButton from "@scandic-hotels/booking-flow/components/OpenSidePeekButton"
|
||||
import TripAdvisorChip from "@scandic-hotels/booking-flow/components/TripAdvisorChip"
|
||||
import { SidePeekEnum } from "@scandic-hotels/booking-flow/stores/sidepeek"
|
||||
import {
|
||||
alternativeHotelsMap,
|
||||
selectHotelMap,
|
||||
@@ -30,6 +28,7 @@ import { useHotelsMapStore } from "@/stores/hotels-map"
|
||||
|
||||
import BookingCodeChip from "@/components/BookingCodeChip"
|
||||
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||
import HotelDetailsSidePeek from "@/components/SidePeeks/HotelDetailsSidePeek"
|
||||
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||
|
||||
import HotelChequeCard from "./HotelChequeCard"
|
||||
@@ -47,7 +46,7 @@ import { HotelCardListingTypeEnum } from "@/types/components/hotelReservation/se
|
||||
import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps"
|
||||
|
||||
function HotelCard({
|
||||
hotelData: { availability, hotel },
|
||||
hotelData: { availability, hotel, additionalData, restaurants, url },
|
||||
isUserLoggedIn,
|
||||
state = "default",
|
||||
type = HotelCardListingTypeEnum.PageListing,
|
||||
@@ -184,13 +183,14 @@ function HotelCard({
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<OpenSidePeekButton
|
||||
label={intl.formatMessage({
|
||||
<HotelDetailsSidePeek
|
||||
hotel={{ ...hotel, url: url }}
|
||||
restaurants={restaurants}
|
||||
additionalHotelData={additionalData}
|
||||
triggerLabel={intl.formatMessage({
|
||||
defaultMessage: "See hotel details",
|
||||
})}
|
||||
hotelId={hotel.operaId}
|
||||
showCTA={true}
|
||||
sidePeekKey={SidePeekEnum.hotelDetails}
|
||||
buttonVariant="primary"
|
||||
/>
|
||||
</div>
|
||||
<PricesWrapper
|
||||
|
||||
@@ -4,9 +4,11 @@ import { Button as ButtonRAC, DialogTrigger } from "react-aria-components"
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
|
||||
import BookedRoomSidePeek from "@/components/SidePeeks/BookedRoomSidePeek"
|
||||
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
||||
|
||||
import styles from "./sidePeek.module.css"
|
||||
|
||||
import { SidePeekEnum } from "@/types/sidepeek"
|
||||
import type { Room as MyStayRoom } from "@/types/stores/my-stay"
|
||||
import type { SafeUser } from "@/types/user"
|
||||
|
||||
@@ -21,7 +23,16 @@ export default function RoomDetailsSidePeek({
|
||||
}: RoomDetailsSidePeekProps) {
|
||||
return (
|
||||
<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" />
|
||||
</ButtonRAC>
|
||||
<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 BookedRoomSidePeek from "@/components/SidePeeks/BookedRoomSidePeek"
|
||||
import { trackOpenSidePeekEvent } from "@/utils/tracking"
|
||||
|
||||
import { SidePeekEnum } from "@/types/sidepeek"
|
||||
import type { SafeUser } from "@/types/user"
|
||||
|
||||
interface RoomDetailsSidePeekProps {
|
||||
@@ -21,9 +23,23 @@ export default function RoomDetailsSidePeek({
|
||||
}: RoomDetailsSidePeekProps) {
|
||||
const intl = useIntl()
|
||||
const bookedRoom = useMyStayStore((state) => state.bookedRoom)
|
||||
|
||||
return (
|
||||
<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" })}
|
||||
<MaterialIcon icon="chevron_right" size={14} color="CurrentColor" />
|
||||
</Button>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { cookies } from "next/headers"
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
import SidePeek from "@scandic-hotels/booking-flow/components/HotelReservationSidePeek"
|
||||
import { dt } from "@scandic-hotels/common/dt"
|
||||
import { logger } from "@scandic-hotels/common/logger"
|
||||
import * as maskValue from "@scandic-hotels/common/utils/maskValue"
|
||||
@@ -268,7 +267,6 @@ export default async function MyStay(props: {
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
<SidePeek />
|
||||
</MyStayProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@ import { getLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { HotelsAvailabilityItem } from "@scandic-hotels/trpc/types/availability"
|
||||
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 {
|
||||
HotelLocation,
|
||||
Location,
|
||||
@@ -32,6 +36,8 @@ export interface HotelResponse {
|
||||
availability: HotelsAvailabilityItem
|
||||
hotel: Hotel
|
||||
additionalData: AdditionalData
|
||||
url: string | null
|
||||
restaurants: Restaurant[]
|
||||
}
|
||||
|
||||
type Result = AvailabilityResponse | null
|
||||
@@ -55,6 +61,8 @@ async function enhanceHotels(hotels: HotelsAvailabilityItem[]) {
|
||||
availability,
|
||||
hotel: hotelData.hotel,
|
||||
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 { 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 { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||
import HotelDetailsSidePeek from "@/components/SidePeeks/HotelDetailsSidePeek"
|
||||
import Alert from "@/components/TempDesignSystem/Alert"
|
||||
|
||||
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({
|
||||
description,
|
||||
hotel,
|
||||
sortedFacilities,
|
||||
restaurants,
|
||||
additionalData,
|
||||
}: {
|
||||
description?: string
|
||||
hotel: Hotel
|
||||
sortedFacilities: Hotel["detailedFacilities"]
|
||||
restaurants: Restaurant[]
|
||||
additionalData: AdditionalData | undefined
|
||||
}) {
|
||||
const intl = useIntl()
|
||||
|
||||
@@ -69,13 +76,14 @@ export default function HotelDescription({
|
||||
|
||||
{expanded && (
|
||||
<div className={styles.expandedContent}>
|
||||
<OpenSidePeekButton
|
||||
label={intl.formatMessage({
|
||||
<HotelDetailsSidePeek
|
||||
hotel={{ ...hotel, url: null }}
|
||||
restaurants={restaurants}
|
||||
additionalHotelData={additionalData}
|
||||
triggerLabel={intl.formatMessage({
|
||||
defaultMessage: "See all amenities",
|
||||
})}
|
||||
hotelId={hotel.operaId}
|
||||
showCTA={false}
|
||||
sidePeekKey={SidePeekEnum.hotelDetails}
|
||||
buttonVariant="primary"
|
||||
/>
|
||||
{hotel.specialAlerts.map((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 { SidePeekEnum } from "@scandic-hotels/booking-flow/stores/sidepeek"
|
||||
import { dt } from "@scandic-hotels/common/dt"
|
||||
import { getSingleDecimal } from "@scandic-hotels/common/utils/numberFormatting"
|
||||
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 { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||
import HotelDetailsSidePeek from "@/components/SidePeeks/HotelDetailsSidePeek"
|
||||
import Alert from "@/components/TempDesignSystem/Alert"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||
@@ -18,16 +17,27 @@ import HotelDescription from "./HotelDescription"
|
||||
|
||||
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"
|
||||
|
||||
export type HotelInfoCardProps = {
|
||||
booking: SelectRateBooking
|
||||
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 sortedFacilities = hotel.detailedFacilities
|
||||
@@ -85,6 +95,8 @@ export async function HotelInfoCard({ booking, hotel }: HotelInfoCardProps) {
|
||||
key={hotel.operaId}
|
||||
description={hotel.hotelContent.texts.descriptions?.medium}
|
||||
hotel={hotel}
|
||||
restaurants={restaurants}
|
||||
additionalData={additionalData}
|
||||
sortedFacilities={sortedFacilities}
|
||||
/>
|
||||
</div>
|
||||
@@ -101,13 +113,14 @@ export async function HotelInfoCard({ booking, hotel }: HotelInfoCardProps) {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<OpenSidePeekButton
|
||||
label={intl.formatMessage({
|
||||
<HotelDetailsSidePeek
|
||||
hotel={{ ...hotel, url: null }}
|
||||
restaurants={restaurants}
|
||||
additionalHotelData={additionalData}
|
||||
triggerLabel={intl.formatMessage({
|
||||
defaultMessage: "See all amenities",
|
||||
})}
|
||||
hotelId={hotel.operaId}
|
||||
showCTA={false}
|
||||
sidePeekKey={SidePeekEnum.hotelDetails}
|
||||
buttonVariant="primary"
|
||||
/>
|
||||
</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 { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
import { getHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
||||
|
||||
import { IconForFeatureCode } from "@/components/HotelReservation/utils"
|
||||
import RoomDetailsSidePeek from "@/components/SidePeeks/RoomDetailsSidePeek"
|
||||
import { useSelectRateContext } from "@/contexts/SelectRate/SelectRateContext"
|
||||
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||
|
||||
import ToggleSidePeek from "../Details/ToggleSidePeek"
|
||||
|
||||
import styles from "./image.module.css"
|
||||
|
||||
import type { ApiImage } from "@scandic-hotels/trpc/types/hotel"
|
||||
@@ -34,7 +35,9 @@ const RoomImage = memo(function RoomImage({
|
||||
hotelId,
|
||||
}: RoomListItemImageProps) {
|
||||
const galleryImages = mapApiImagesToGalleryImages(images || [])
|
||||
|
||||
const { hotel } = useSelectRateContext()
|
||||
const room = getHotelRoom(hotel?.data?.roomCategories ?? [], roomTypeCode)
|
||||
const intl = useIntl()
|
||||
return (
|
||||
<div className={styles.imageContainer}>
|
||||
<div className={styles.chipContainer}>
|
||||
@@ -53,8 +56,16 @@ const RoomImage = memo(function RoomImage({
|
||||
imageCountPosition="top"
|
||||
/>
|
||||
<div className={styles.toggleSidePeek}>
|
||||
{roomTypeCode && (
|
||||
<ToggleSidePeek hotelId={hotelId} roomTypeCode={roomTypeCode} />
|
||||
{roomTypeCode && room && (
|
||||
<RoomDetailsSidePeek
|
||||
hotelId={hotelId}
|
||||
room={room}
|
||||
roomTypeCode={roomTypeCode}
|
||||
triggerLabel={intl.formatMessage({
|
||||
defaultMessage: "View room details",
|
||||
})}
|
||||
buttonVariant="secondary"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,12 @@ export default async function SelectRatePage({
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<HotelInfoCard hotel={hotelData.hotel} booking={booking} />
|
||||
<HotelInfoCard
|
||||
hotel={hotelData.hotel}
|
||||
restaurants={hotelData.restaurants}
|
||||
additionalData={hotelData.additionalData}
|
||||
booking={booking}
|
||||
/>
|
||||
|
||||
{isInValidFNF ? (
|
||||
<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 {
|
||||
BED_TYPE_ICONS,
|
||||
type BedTypes,
|
||||
} from "@scandic-hotels/booking-flow/bedTypeIcons"
|
||||
import { FacilityIcon } from "@scandic-hotels/design-system/Icons/FacilityIcon"
|
||||
import ImageGallery from "@scandic-hotels/design-system/ImageGallery"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { BED_TYPE_ICONS, type BedTypes } from "../../../misc/bedTypeIcons"
|
||||
|
||||
import styles from "./roomSidePeekContent.module.css"
|
||||
|
||||
import type { ApiImage, Room } from "@scandic-hotels/trpc/types/hotel"
|
||||
@@ -79,7 +81,7 @@ export function RoomSidePeekContent({ room }: RoomSidePeekContentProps) {
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<ul className={styles.facilityList}>
|
||||
{room.roomFacilities
|
||||
{[...room.roomFacilities]
|
||||
.sort((a, b) => a.sortOrder - b.sortOrder)
|
||||
.map((facility) => {
|
||||
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 { useIntl } from "react-intl"
|
||||
|
||||
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
||||
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 useSetOverflowVisibleOnRA from "@/hooks/useSetOverflowVisibleOnRA"
|
||||
@@ -34,19 +34,20 @@ export default function SidePeekSelfControlled({
|
||||
<h2>{title}</h2>
|
||||
</Typography>
|
||||
) : null}
|
||||
<Button
|
||||
<IconButton
|
||||
theme="Black"
|
||||
style="Muted"
|
||||
onPress={close}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Close",
|
||||
})}
|
||||
className={styles.closeButton}
|
||||
intent="text"
|
||||
onPress={close}
|
||||
>
|
||||
<MaterialIcon
|
||||
icon="close"
|
||||
size={24}
|
||||
color="Icon/Interactive/Default"
|
||||
/>
|
||||
</Button>
|
||||
</IconButton>
|
||||
</header>
|
||||
<div className={styles.sidePeekContent}>{children}</div>
|
||||
<KeepBodyVisible />
|
||||
|
||||
@@ -72,10 +72,6 @@
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.heading {
|
||||
color: var(--Text-Heading);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ export default function EnterDetailsProvider({
|
||||
searchParamsStr,
|
||||
user,
|
||||
vat,
|
||||
roomCategories,
|
||||
}: DetailsProviderProps) {
|
||||
// This state is needed to be able to use defaultValues for
|
||||
// react-hook-form since values needs to be there on mount
|
||||
@@ -70,6 +71,7 @@ export default function EnterDetailsProvider({
|
||||
isFlexRate: room.isFlexRate,
|
||||
})),
|
||||
vat,
|
||||
roomCategories,
|
||||
}
|
||||
|
||||
storeRef.current = createDetailsStore(
|
||||
|
||||
@@ -97,6 +97,7 @@ export function createDetailsStore(
|
||||
return create<DetailsState>()((set) => ({
|
||||
availableBeds,
|
||||
booking: initialState.booking,
|
||||
roomCategories: initialState.roomCategories,
|
||||
breakfastPackages,
|
||||
canProceedToPayment: false,
|
||||
isSubmitting: false,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { produce } from "immer"
|
||||
import { useContext } from "react"
|
||||
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 { MyStayContext } from "@/contexts/MyStay"
|
||||
@@ -39,7 +39,7 @@ export function createMyStayStore({
|
||||
}
|
||||
|
||||
const mappedRooms = rooms.map((booking, idx) => {
|
||||
const room = getBookedHotelRoom(roomCategories, booking.roomTypeCode)
|
||||
const room = getHotelRoom(roomCategories, booking.roomTypeCode)
|
||||
return mapRoomDetails({
|
||||
booking,
|
||||
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"
|
||||
|
||||
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 { RoomCategories } from "@scandic-hotels/trpc/types/hotel"
|
||||
import type { Room } from "@scandic-hotels/trpc/types/room"
|
||||
|
||||
import type { SafeUser } from "@/types/user"
|
||||
@@ -13,4 +14,5 @@ export interface DetailsProviderProps extends React.PropsWithChildren {
|
||||
searchParamsStr: string
|
||||
user: SafeUser
|
||||
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 { BedTypeSelection } from "@scandic-hotels/trpc/types/bedTypeSelection"
|
||||
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 {
|
||||
@@ -80,6 +81,7 @@ export type InitialState = {
|
||||
booking: DetailsBooking
|
||||
rooms: InitialRoomData[]
|
||||
vat: number
|
||||
roomCategories: RoomCategories
|
||||
}
|
||||
|
||||
export interface DetailsState {
|
||||
@@ -100,6 +102,7 @@ export interface DetailsState {
|
||||
searchParamString: string
|
||||
totalPrice: Price
|
||||
vat: number
|
||||
roomCategories: RoomCategories
|
||||
defaultCurrency: CurrencyEnum
|
||||
preSubmitCallbacks: Record<string, () => void>
|
||||
}
|
||||
|
||||
@@ -59,9 +59,3 @@
|
||||
flex-direction: column;
|
||||
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 Body from "@scandic-hotels/design-system/Body"
|
||||
import FacebookIcon from "@scandic-hotels/design-system/Icons/FacebookIcon"
|
||||
import InstagramIcon from "@scandic-hotels/design-system/Icons/InstagramIcon"
|
||||
import Image from "@scandic-hotels/design-system/Image"
|
||||
@@ -13,6 +12,7 @@ import useLang from "../../hooks/useLang"
|
||||
import styles from "./contact.module.css"
|
||||
|
||||
import type { Hotel } from "@scandic-hotels/trpc/types/hotel"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
interface ContactProps {
|
||||
hotel: Hotel
|
||||
@@ -30,55 +30,67 @@ export default function Contact({ hotel }: ContactProps) {
|
||||
<address className={styles.address}>
|
||||
<ul className={styles.contactInfo}>
|
||||
<li>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Address",
|
||||
})}
|
||||
</Body>
|
||||
<Body>
|
||||
{addressStr}
|
||||
<br />
|
||||
{cityStr}
|
||||
</Body>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Address",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{addressStr}
|
||||
<br />
|
||||
{cityStr}
|
||||
</p>
|
||||
</Typography>
|
||||
</li>
|
||||
<li>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Driving directions",
|
||||
})}
|
||||
</Body>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Driving directions",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Link
|
||||
href={`https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(
|
||||
`${hotel.name}, ${hotel.address.streetAddress}, ${hotel.address.zipCode} ${hotel.address.city}`
|
||||
)}`}
|
||||
>
|
||||
<span className={styles.link}>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Google Maps",
|
||||
})}
|
||||
</span>
|
||||
<Typography variant="Body/Underline/md">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Google Maps",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Contact us",
|
||||
})}
|
||||
</Body>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Contact us",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Link href={`tel:${hotel.contactInformation.phoneNumber}`}>
|
||||
<span className={styles.link}>
|
||||
{hotel.contactInformation.phoneNumber}
|
||||
</span>
|
||||
<Typography variant="Body/Underline/md">
|
||||
<p>{hotel.contactInformation.phoneNumber}</p>
|
||||
</Typography>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
{(hotel.socialMedia.facebook || hotel.socialMedia.instagram) && (
|
||||
<>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Follow us",
|
||||
})}
|
||||
</Body>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Follow us",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<div className={styles.soMeIcons}>
|
||||
{hotel.socialMedia.instagram && (
|
||||
<Link href={hotel.socialMedia.instagram} target="_blank">
|
||||
@@ -95,15 +107,17 @@ export default function Contact({ hotel }: ContactProps) {
|
||||
)}
|
||||
</li>
|
||||
<li>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Email",
|
||||
})}
|
||||
</Body>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Email",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Link href={`mailto:${hotel.contactInformation.email}`}>
|
||||
<span className={styles.link}>
|
||||
{hotel.contactInformation.email}
|
||||
</span>
|
||||
<Typography variant="Body/Underline/md">
|
||||
<p>{hotel.contactInformation.email}</p>
|
||||
</Typography>
|
||||
</Link>
|
||||
</li>
|
||||
</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",
|
||||
"./bedTypeIcons": "./lib/misc/bedTypeIcons.ts",
|
||||
"./stores/bookingCode-filter": "./lib/stores/bookingCode-filter.ts",
|
||||
"./stores/sidepeek": "./lib/stores/sidepeek.ts",
|
||||
"./components/TripAdvisorChip": "./lib/components/TripAdvisorChip/index.tsx",
|
||||
"./components/Contact": "./lib/components/Contact/index.tsx",
|
||||
"./components/AdditionalAmenities": "./lib/components/AdditionalAmenities/index.tsx",
|
||||
"./components/HotelReservationSidePeek": "./lib/components/HotelReservationSidePeek/index.tsx",
|
||||
"./components/RoomSidePeekContent": "./lib/components/RoomSidePeek/RoomSidePeekContent/index.tsx",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { BookingConfirmation } from "../../types/bookingConfirmation"
|
||||
import type { Room } from "../../types/hotel"
|
||||
|
||||
export function getBookedHotelRoom(
|
||||
export function getHotelRoom(
|
||||
rooms: Room[],
|
||||
roomTypeCode: BookingConfirmation["booking"]["roomTypeCode"]
|
||||
) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { getHotel } from "../../routers/hotels/utils"
|
||||
import { toApiLang } from "../../utils"
|
||||
import { encrypt } from "../../utils/encryption"
|
||||
import { isValidSession } from "../../utils/session"
|
||||
import { getBookedHotelRoom } from "./helpers"
|
||||
import { getHotelRoom } from "./helpers"
|
||||
import {
|
||||
createRefIdInput,
|
||||
findBookingInput,
|
||||
@@ -85,10 +85,7 @@ export const bookingQueryRouter = router({
|
||||
return {
|
||||
...hotelData,
|
||||
booking,
|
||||
room: getBookedHotelRoom(
|
||||
hotelData.roomCategories,
|
||||
booking.roomTypeCode
|
||||
),
|
||||
room: getHotelRoom(hotelData.roomCategories, booking.roomTypeCode),
|
||||
}
|
||||
}),
|
||||
findBooking: safeProtectedServiceProcedure
|
||||
@@ -158,10 +155,7 @@ export const bookingQueryRouter = router({
|
||||
return {
|
||||
...hotelData,
|
||||
booking,
|
||||
room: getBookedHotelRoom(
|
||||
hotelData.roomCategories,
|
||||
booking.roomTypeCode
|
||||
),
|
||||
room: getHotelRoom(hotelData.roomCategories, booking.roomTypeCode),
|
||||
}
|
||||
}),
|
||||
linkedReservations: safeProtectedServiceProcedure
|
||||
|
||||
Reference in New Issue
Block a user