From 7c233ab8463e635c8608edfbbbead889a2a57dd4 Mon Sep 17 00:00:00 2001 From: Tobias Johansson Date: Mon, 10 Mar 2025 12:13:15 +0000 Subject: [PATCH] Merged in feat/SW-1076-no-room-availability (pull request #1467) Feat/SW-1076 no room availability * fix: update booking error codes * feat(SW-1076): handle no room availabilty on enter-details * fix: parse to json in api mutation instead of expecting json * fix: remove 'isComplete' state from sectionAccordion because it was not needed Approved-by: Simon.Emanuelsson --- .../payment-callback/page.tsx | 8 ++--- .../(standard)/details/page.tsx | 30 +++++++++++++++++-- .../EnterDetails/Payment/PaymentClient.tsx | 10 +++++++ .../EnterDetails/SectionAccordion/index.tsx | 24 ++++++--------- .../EnterDetails/SelectedRoom/index.tsx | 9 ++++-- .../SelectedRoom/selectedRoom.module.css | 11 +++++++ .../EnterDetails/Summary/UI/index.tsx | 4 +-- .../EnterDetails/Summary/summary.test.tsx | 2 ++ apps/scandic-web/constants/booking.ts | 14 ++++++--- .../hooks/booking/usePaymentFailedToast.ts | 13 ++++---- apps/scandic-web/i18n/dictionaries/da.json | 2 ++ apps/scandic-web/i18n/dictionaries/de.json | 2 ++ apps/scandic-web/i18n/dictionaries/en.json | 2 ++ apps/scandic-web/i18n/dictionaries/fi.json | 2 ++ apps/scandic-web/i18n/dictionaries/sv.json | 2 ++ apps/scandic-web/package.json | 1 + .../providers/EnterDetailsProvider.tsx | 9 +++++- .../server/routers/booking/mutation.ts | 12 ++++++-- .../server/routers/hotels/query.ts | 27 +++++------------ .../stores/enter-details/helpers.ts | 8 ++--- .../types/providers/details/room.ts | 1 + .../scandic-web/types/stores/enter-details.ts | 1 + yarn.lock | 8 +++++ 23 files changed, 139 insertions(+), 63 deletions(-) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx index 1a24d6c11..db5229d5e 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx @@ -2,8 +2,8 @@ import { redirect } from "next/navigation" import { BOOKING_CONFIRMATION_NUMBER, + BookingErrorCodeEnum, MEMBERSHIP_FAILED_ERROR, - PaymentErrorCodeEnum, } from "@/constants/booking" import { bookingConfirmation, @@ -70,17 +70,17 @@ export default async function PaymentCallbackPage({ "errorCode", error ? error.errorCode.toString() - : PaymentErrorCodeEnum.Failed.toString() + : BookingErrorCodeEnum.TransactionFailed ) } catch { console.error( `[payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}` ) if (status === "cancel") { - searchObject.set("errorCode", PaymentErrorCodeEnum.Cancelled.toString()) + searchObject.set("errorCode", BookingErrorCodeEnum.TransactionCancelled) } if (status === "error") { - searchObject.set("errorCode", PaymentErrorCodeEnum.Failed.toString()) + searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed) errorMessage = `Failed to get booking status for ${confirmationNumber}, status: ${status}` } } diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx index 49e7c6222..23651a7cc 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx @@ -1,6 +1,7 @@ -import { notFound } from "next/navigation" +import { notFound, redirect } from "next/navigation" import { Suspense } from "react" +import { selectRate } from "@/constants/routes/hotelReservation" import { getBreakfastPackages, getHotel, @@ -16,13 +17,17 @@ import RoomOne from "@/components/HotelReservation/EnterDetails/Room/One" import DesktopSummary from "@/components/HotelReservation/EnterDetails/Summary/Desktop" import MobileSummary from "@/components/HotelReservation/EnterDetails/Summary/Mobile" import { generateChildrenString } from "@/components/HotelReservation/utils" +import Alert from "@/components/TempDesignSystem/Alert" +import { getIntl } from "@/i18n" import RoomProvider from "@/providers/Details/RoomProvider" import EnterDetailsProvider from "@/providers/EnterDetailsProvider" import { convertSearchParamsToObj } from "@/utils/url" import styles from "./page.module.css" +import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel" import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate" +import { AlertTypeEnum } from "@/types/enums/alert" import type { LangParams, PageArgs } from "@/types/params" import type { Room } from "@/types/providers/details/room" @@ -81,7 +86,8 @@ export default async function DetailsPage({ ) if (!roomAvailability) { - continue // TODO: handle no room availability + // redirect back to select-rate if availability call fails + redirect(`${selectRate(lang)}?${selectRoomParams.toString()}`) } rooms.push({ @@ -98,6 +104,8 @@ export default async function DetailsPage({ memberRate: roomAvailability?.memberRate, publicRate: roomAvailability.publicRate, }, + isAvailable: + roomAvailability.selectedRoom.status === AvailabilityEnum.Available, }) } @@ -139,8 +147,11 @@ export default async function DetailsPage({ // region: hotel?.address.city, // } + const intl = await getIntl() + const firstRoom = rooms[0] const multirooms = rooms.slice(1) + const isRoomNotAvailable = rooms.some((room) => !room.isAvailable) return (
+ {isRoomNotAvailable && ( + + )}
diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx index 486b1334c..28318c110 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx @@ -7,6 +7,7 @@ import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" import { + BookingErrorCodeEnum, BookingStatusEnum, PAYMENT_METHOD_TITLES, PaymentMethodEnum, @@ -107,6 +108,15 @@ export default function PaymentClient({ const initiateBooking = trpc.booking.create.useMutation({ onSuccess: (result) => { if (result) { + if ("error" in result) { + if (result.cause === BookingErrorCodeEnum.AvailabilityError) { + window.location.reload() // reload to refetch room data because we dont know which room is unavailable + } else { + handlePaymentError(result.cause) + } + return + } + setBookingNumber(result.id) const priceChange = result.rooms.find( diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx index b4ed21591..166c756f7 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx @@ -25,14 +25,12 @@ export default function SectionAccordion({ actions: { setStep }, currentStep, isActiveRoom, - room: { bedType, breakfast }, + room: { bedType, breakfast, isAvailable }, steps, } = useRoomContext() - const [isComplete, setIsComplete] = useState(false) + const isStepComplete = !!(steps[step]?.isValid && isAvailable) const [isOpen, setIsOpen] = useState(false) - const isValid = steps[step]?.isValid ?? false - const [title, setTitle] = useState(label) const noBreakfastTitle = intl.formatMessage({ id: "No breakfast" }) @@ -54,14 +52,10 @@ export default function SectionAccordion({ } }, [bedType, breakfast, setTitle, step, breakfastTitle, noBreakfastTitle]) - useEffect(() => { - setIsComplete(isValid) - }, [isValid, setIsComplete]) - const accordionRef = useRef(null) useEffect(() => { - const shouldBeOpen = currentStep === step && isActiveRoom + const shouldBeOpen = currentStep === step && isActiveRoom && isAvailable setIsOpen(shouldBeOpen) // Scroll to this section when it is opened, @@ -91,7 +85,7 @@ export default function SectionAccordion({ } } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currentStep, isActiveRoom, setIsOpen, step]) + }, [currentStep, isActiveRoom, isAvailable, setIsOpen, step]) function goToStep() { setStep(step) @@ -103,7 +97,7 @@ export default function SectionAccordion({ } const textColor = - isComplete || isOpen ? "uiTextHighContrast" : "baseTextDisabled" + isStepComplete || isOpen ? "uiTextHighContrast" : "baseTextDisabled" return (
-
- {isComplete ? ( +
+ {isStepComplete ? ( ) : null}
@@ -121,7 +115,7 @@ export default function SectionAccordion({
{room.roomTypeCode && ( diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/SelectedRoom/selectedRoom.module.css b/apps/scandic-web/components/HotelReservation/EnterDetails/SelectedRoom/selectedRoom.module.css index 654cb24c0..18d14d709 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/SelectedRoom/selectedRoom.module.css +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/SelectedRoom/selectedRoom.module.css @@ -5,6 +5,13 @@ gap: var(--Spacing-x-one-and-half); } +.wrapper[data-available="false"] .title, +.wrapper[data-available="false"] .description, +.wrapper[data-available="false"] .details { + opacity: 0.5; + pointer-events: none; +} + .main { width: 100%; border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle); @@ -52,6 +59,10 @@ background-color: var(--UI-Input-Controls-Fill-Selected); } +.wrapper[data-available="false"] .circle { + background-color: var(--Base-Surface-Subtle-Hover); +} + .rate { color: var(--UI-Text-Placeholder); display: block; diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx index 77a822280..2ffa5aec2 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx @@ -381,7 +381,7 @@ export default function SummaryUI({ totalPrice.local.currency )} - {totalPrice.local.regularPrice && ( + {totalPrice.local.regularPrice ? ( {formatPrice( intl, @@ -389,7 +389,7 @@ export default function SummaryUI({ totalPrice.local.currency )} - )} + ) : null} {totalPrice.requested && ( {intl.formatMessage( diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/summary.test.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/summary.test.tsx index c01a18721..65515f3d8 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/summary.test.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/summary.test.tsx @@ -63,6 +63,7 @@ const rooms: RoomState[] = [ roomRate: roomRate, roomType: "Standard", roomTypeCode: "QS", + isAvailable: true, }, steps: { [StepEnum.selectBed]: { @@ -100,6 +101,7 @@ const rooms: RoomState[] = [ roomRate: roomRate, roomType: "Standard", roomTypeCode: "QS", + isAvailable: true, }, steps: { [StepEnum.selectBed]: { diff --git a/apps/scandic-web/constants/booking.ts b/apps/scandic-web/constants/booking.ts index 581fb3349..49592e722 100644 --- a/apps/scandic-web/constants/booking.ts +++ b/apps/scandic-web/constants/booking.ts @@ -64,10 +64,16 @@ export enum PaymentMethodEnum { discover = "discover", } -export enum PaymentErrorCodeEnum { - Abandoned = 5, - Cancelled = 6, - Failed = 7, +export enum BookingErrorCodeEnum { + InternalError = "InternalError", + ReservationError = "ReservationError", + AvailabilityError = "AvailabilityError", + BookingStatusNotFound = "BookingStatusNotFound", + TransactionAbandoned = "TransactionAbandoned", + TransactionCancelled = "TransactionCancelled", + TransactionFailed = "TransactionFailed", + BookingStateError = "BookingStateError", + MembershipFailedError = "MembershipFailedError", } export const PAYMENT_METHOD_TITLES: Record< diff --git a/apps/scandic-web/hooks/booking/usePaymentFailedToast.ts b/apps/scandic-web/hooks/booking/usePaymentFailedToast.ts index a5b87a235..eb5f0b481 100644 --- a/apps/scandic-web/hooks/booking/usePaymentFailedToast.ts +++ b/apps/scandic-web/hooks/booking/usePaymentFailedToast.ts @@ -4,7 +4,7 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation" import { useCallback, useEffect } from "react" import { useIntl } from "react-intl" -import { PaymentErrorCodeEnum } from "@/constants/booking" +import { BookingErrorCodeEnum } from "@/constants/booking" import { useEnterDetailsStore } from "@/stores/enter-details" import { toast } from "@/components/TempDesignSystem/Toasts" @@ -19,9 +19,9 @@ export function usePaymentFailedToast() { const router = useRouter() const getErrorMessage = useCallback( - (errorCode: PaymentErrorCodeEnum) => { + (errorCode: string | null) => { switch (errorCode) { - case PaymentErrorCodeEnum.Cancelled: + case BookingErrorCodeEnum.TransactionCancelled: return intl.formatMessage({ id: "You have now cancelled your payment.", }) @@ -34,8 +34,7 @@ export function usePaymentFailedToast() { [intl] ) - const errorCodeString = searchParams.get("errorCode") - const errorCode = Number(errorCodeString) as PaymentErrorCodeEnum + const errorCode = searchParams.get("errorCode") const errorMessage = getErrorMessage(errorCode) useEffect(() => { @@ -44,7 +43,9 @@ export function usePaymentFailedToast() { // setTimeout is needed to show toasts on page load: https://sonner.emilkowal.ski/toast#render-toast-on-page-load setTimeout(() => { const toastType = - errorCode === PaymentErrorCodeEnum.Cancelled ? "warning" : "error" + errorCode === BookingErrorCodeEnum.TransactionCancelled + ? "warning" + : "error" toast[toastType](errorMessage) }) diff --git a/apps/scandic-web/i18n/dictionaries/da.json b/apps/scandic-web/i18n/dictionaries/da.json index 629b3df24..1df89dda9 100644 --- a/apps/scandic-web/i18n/dictionaries/da.json +++ b/apps/scandic-web/i18n/dictionaries/da.json @@ -575,6 +575,7 @@ "Room charge": "Værelsesafgift", "Room details": "Room details", "Room facilities": "Værelsesfaciliteter", + "Room sold out": "Værelse solgt ud", "Room total": "Værelse total", "Room {roomIndex}": "Værelse {roomIndex}", "Rooms": "Værelser", @@ -686,6 +687,7 @@ "Type of bed": "Sengtype", "Type of room": "Værelsestype", "U-shape": "U-form", + "Unfortunately, one of the rooms you selected is sold out. Please choose another room to proceed.": "Desværre er et af de værelser, du har valgt, solgt ud. Vælg et andet værelse for at fortsætte.", "Unlink accounts": "Unlink accounts", "Unpaid": "Ikke betalt", "Until {time}, {date}": "Indtil {time} den {date}", diff --git a/apps/scandic-web/i18n/dictionaries/de.json b/apps/scandic-web/i18n/dictionaries/de.json index 3224fb94c..fffc829f1 100644 --- a/apps/scandic-web/i18n/dictionaries/de.json +++ b/apps/scandic-web/i18n/dictionaries/de.json @@ -574,6 +574,7 @@ "Room charge": "Zimmerpreis", "Room details": "Room details", "Room facilities": "Zimmerausstattung", + "Room sold out": "Zimmer verkauft", "Room total": "Zimmer total", "Room {roomIndex}": "Zimmer {roomIndex}", "Rooms": "Räume", @@ -684,6 +685,7 @@ "Type of bed": "Bettentyp", "Type of room": "Zimmerart", "U-shape": "U-shape", + "Unfortunately, one of the rooms you selected is sold out. Please choose another room to proceed.": "Leider ist eines der von Ihnen ausgewählten Zimmer verkauft. Bitte wählen Sie ein anderes Zimmer, um fortzufahren.", "Unlink accounts": "Unlink accounts", "Unpaid": "Nicht bezahlt", "Until {time}, {date}": "Bis {time} am {date}", diff --git a/apps/scandic-web/i18n/dictionaries/en.json b/apps/scandic-web/i18n/dictionaries/en.json index 19e17b2bd..0a2a88ada 100644 --- a/apps/scandic-web/i18n/dictionaries/en.json +++ b/apps/scandic-web/i18n/dictionaries/en.json @@ -581,6 +581,7 @@ "Room charge": "Room charge", "Room details": "Room details", "Room facilities": "Room facilities", + "Room sold out": "Room sold out", "Room total": "Room total", "Room {roomIndex}": "Room {roomIndex}", "Rooms": "Rooms", @@ -692,6 +693,7 @@ "Type of bed": "Type of bed", "Type of room": "Type of room", "U-shape": "U-shape", + "Unfortunately, one of the rooms you selected is sold out. Please choose another room to proceed.": "Unfortunately, one of the rooms you selected is sold out. Please choose another room to proceed.", "Unlink accounts": "Unlink accounts", "Unpaid": "Unpaid", "Until {time}, {date}": "Until {time}, {date}", diff --git a/apps/scandic-web/i18n/dictionaries/fi.json b/apps/scandic-web/i18n/dictionaries/fi.json index 2a7252f8c..c426e960c 100644 --- a/apps/scandic-web/i18n/dictionaries/fi.json +++ b/apps/scandic-web/i18n/dictionaries/fi.json @@ -573,6 +573,7 @@ "Room charge": "Huonemaksu", "Room details": "Room details", "Room facilities": "Huoneen varustelu", + "Room sold out": "Huone slutsattu", "Room total": "Huoneen kokonaishinta", "Room {roomIndex}": "Huone {roomIndex}", "Rooms": "Huoneet", @@ -684,6 +685,7 @@ "Type of bed": "Vuodetyyppi", "Type of room": "Huonetyyppi", "U-shape": "U-muoto", + "Unfortunately, one of the rooms you selected is sold out. Please choose another room to proceed.": "Valitettavasti valitsemasi huone on loppuunmyyty. Valitse toinen huone jatkaaksesi.", "Unlink accounts": "Unlink accounts", "Unpaid": "Maksettaa", "Until {time}, {date}": "Asti {time}, {date}", diff --git a/apps/scandic-web/i18n/dictionaries/sv.json b/apps/scandic-web/i18n/dictionaries/sv.json index d9a9447e4..4d41a6097 100644 --- a/apps/scandic-web/i18n/dictionaries/sv.json +++ b/apps/scandic-web/i18n/dictionaries/sv.json @@ -572,6 +572,7 @@ "Room charge": "Rumspris", "Room details": "Room details", "Room facilities": "Rumfaciliteter", + "Room sold out": "Rum slutsålt", "Room total": "Rum total", "Room {roomIndex}": "Rum {roomIndex}", "Rooms": "Rum", @@ -682,6 +683,7 @@ "Type of bed": "Sängtyp", "Type of room": "Rumstyp", "U-shape": "U-form", + "Unfortunately, one of the rooms you selected is sold out. Please choose another room to proceed.": "Tyvärr, ett av de rum du valde är slutsålt. Vänligen välj ett annat rum för att fortsätta.", "Unlink accounts": "Unlink accounts", "Unpaid": "Ej betalt", "Until {time}, {date}": "Tills {time} den {date}", diff --git a/apps/scandic-web/package.json b/apps/scandic-web/package.json index cabcc18fb..1358f6f0a 100644 --- a/apps/scandic-web/package.json +++ b/apps/scandic-web/package.json @@ -90,6 +90,7 @@ "react-international-phone": "^4.2.6", "react-intl": "^6.6.8", "react-to-print": "^3.0.2", + "secure-json-parse": "^4.0.0", "server-only": "^0.0.1", "slugify": "^1.6.6", "sonner": "^1.7.0", diff --git a/apps/scandic-web/providers/EnterDetailsProvider.tsx b/apps/scandic-web/providers/EnterDetailsProvider.tsx index 87a466dc4..958201ca4 100644 --- a/apps/scandic-web/providers/EnterDetailsProvider.tsx +++ b/apps/scandic-web/providers/EnterDetailsProvider.tsx @@ -37,6 +37,7 @@ export default function EnterDetailsProvider({ rooms: rooms .filter((r) => r.bedTypes?.length) // TODO: how to handle room without bedtypes? .map((room) => ({ + isAvailable: room.isAvailable, breakfastIncluded: !!room.breakfastIncluded, cancellationText: room.cancellationText, rateDetails: room.rateDetails, @@ -86,6 +87,10 @@ export default function EnterDetailsProvider({ // since store is readonly const currentRoom = deepmerge({}, store.rooms[idx]) + if (!currentRoom.room.isAvailable) { + return currentRoom + } + if (!currentRoom.room.bedType && storedRoom.room.bedType) { const sameBed = currentRoom.room.bedTypes.find( (bedType) => bedType.value === storedRoom.room.bedType?.roomTypeCode @@ -134,7 +139,9 @@ export default function EnterDetailsProvider({ return currentRoom }) - const canProceedToPayment = updatedRooms.every((room) => room.isComplete) + const canProceedToPayment = updatedRooms.every( + (room) => room.isComplete && room.room.isAvailable + ) const nights = dt(booking.toDate).diff(booking.fromDate, "days") const currency = (updatedRooms[0].room.roomRate.publicRate?.localPrice diff --git a/apps/scandic-web/server/routers/booking/mutation.ts b/apps/scandic-web/server/routers/booking/mutation.ts index d9145e348..9e61bb72d 100644 --- a/apps/scandic-web/server/routers/booking/mutation.ts +++ b/apps/scandic-web/server/routers/booking/mutation.ts @@ -1,4 +1,5 @@ import { metrics } from "@opentelemetry/api" +import sjson from "secure-json-parse" import * as api from "@/lib/api" import { getVerifiedUser } from "@/server/routers/user/query" @@ -11,8 +12,8 @@ import { cancelBookingInput, createBookingInput, priceChangeInput, - updateBookingInput, removePackageInput, + updateBookingInput, } from "./input" import { createBookingSchema } from "./output" @@ -135,10 +136,17 @@ export const bookingMutationRouter = router({ error: { status: apiResponse.status, statusText: apiResponse.statusText, - error: text, + text, }, }) ) + + const apiJson = sjson.safeParse(text) + if ("errors" in apiJson && apiJson.errors.length) { + const error = apiJson.errors[0] + return { error: true, cause: error.code } as const + } + return null } diff --git a/apps/scandic-web/server/routers/hotels/query.ts b/apps/scandic-web/server/routers/hotels/query.ts index e07057cc8..feed76797 100644 --- a/apps/scandic-web/server/routers/hotels/query.ts +++ b/apps/scandic-web/server/routers/hotels/query.ts @@ -64,7 +64,6 @@ import { } from "./utils" import type { BedTypeSelection } from "@/types/components/hotelReservation/enterDetails/bedType" -import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel" import { BreakfastPackageEnum } from "@/types/enums/breakfast" import { HotelTypeEnum } from "@/types/enums/hotelType" import { RateTypeEnum } from "@/types/enums/rateType" @@ -595,7 +594,6 @@ export const hotelQueryRouter = router({ bookingCode, rateCode, roomTypeCode, - packageCodes, } = input const params: Record = { @@ -691,27 +689,11 @@ export const hotelQueryRouter = router({ ctx.serviceToken ) - const availableRooms = - validateAvailabilityData.data.roomConfigurations.filter((room) => { - if (packageCodes) { - return ( - room.status === AvailabilityEnum.Available && - room.features.some( - (feature) => - packageCodes.includes(feature.code) && feature.inventory > 0 - ) - ) - } - return room.status === AvailabilityEnum.Available - }) - - const selectedRoom = availableRooms.find( + const rooms = validateAvailabilityData.data.roomConfigurations + const selectedRoom = rooms.find( (room) => room.roomTypeCode === roomTypeCode ) - const availableRoomsInCategory = availableRooms.filter( - (room) => room.roomType === selectedRoom?.roomType - ) if (!selectedRoom) { metrics.selectedRoomAvailability.fail.add(1, { hotelId, @@ -720,6 +702,7 @@ export const hotelQueryRouter = router({ adults, children, bookingCode, + roomTypeCode, error_type: "not_found", error: `Couldn't find selected room with input: ${roomTypeCode}`, }) @@ -727,6 +710,10 @@ export const hotelQueryRouter = router({ return null } + const availableRoomsInCategory = rooms.filter( + (room) => room.roomType === selectedRoom?.roomType + ) + const rateTypes = selectedRoom.products.find( (rate) => rate.public?.rateCode === rateCode || diff --git a/apps/scandic-web/stores/enter-details/helpers.ts b/apps/scandic-web/stores/enter-details/helpers.ts index 899aa6516..4956112c8 100644 --- a/apps/scandic-web/stores/enter-details/helpers.ts +++ b/apps/scandic-web/stores/enter-details/helpers.ts @@ -26,15 +26,15 @@ export function extractGuestFromUser(user: NonNullable) { } export function checkIsSameBooking( - prev: SelectRateSearchParams, - next: SelectRateSearchParams + prev: SelectRateSearchParams & { errorCode?: string }, + next: SelectRateSearchParams & { errorCode?: string } ) { - const { rooms: prevRooms, ...prevBooking } = prev + const { rooms: prevRooms, errorCode: prevErrorCode, ...prevBooking } = prev const prevRoomsWithoutRateCodes = prevRooms.map( ({ rateCode, counterRateCode, roomTypeCode, ...room }) => room ) - const { rooms: nextRooms, ...nextBooking } = next + const { rooms: nextRooms, errorCode: nextErrorCode, ...nextBooking } = next const nextRoomsWithoutRateCodes = nextRooms.map( ({ rateCode, counterRateCode, roomTypeCode, ...room }) => room diff --git a/apps/scandic-web/types/providers/details/room.ts b/apps/scandic-web/types/providers/details/room.ts index 51d5d2021..3af385d00 100644 --- a/apps/scandic-web/types/providers/details/room.ts +++ b/apps/scandic-web/types/providers/details/room.ts @@ -13,6 +13,7 @@ export interface Room { roomRate: RoomRate roomType: string roomTypeCode: string + isAvailable: boolean } export interface RoomProviderProps extends React.PropsWithChildren { diff --git a/apps/scandic-web/types/stores/enter-details.ts b/apps/scandic-web/types/stores/enter-details.ts index 7d06028b1..c77e19042 100644 --- a/apps/scandic-web/types/stores/enter-details.ts +++ b/apps/scandic-web/types/stores/enter-details.ts @@ -22,6 +22,7 @@ import type { import type { Packages } from "../requests/packages" export interface InitialRoomData { + isAvailable: boolean bedType?: BedTypeSchema // used when there is only one bedtype to preselect it bedTypes: BedTypeSelection[] breakfastIncluded: boolean diff --git a/yarn.lock b/yarn.lock index 38c74e8ab..4e3793f9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6147,6 +6147,7 @@ __metadata: react-intl: "npm:^6.6.8" react-to-print: "npm:^3.0.2" schema-dts: "npm:^1.1.2" + secure-json-parse: "npm:^4.0.0" server-only: "npm:^0.0.1" slugify: "npm:^1.6.6" sonner: "npm:^1.7.0" @@ -18487,6 +18488,13 @@ __metadata: languageName: node linkType: hard +"secure-json-parse@npm:^4.0.0": + version: 4.0.0 + resolution: "secure-json-parse@npm:4.0.0" + checksum: 10c0/1a298cf00e1de91e833cee5eb406d6e77fb2f7eca9bef3902047d49e7f5d3e6c21b5de61ff73466c831e716430bfe87d732a6e645a7dabb5f1e8a8e4d3e15eb4 + languageName: node + linkType: hard + "semver@npm:^5.6.0": version: 5.7.2 resolution: "semver@npm:5.7.2"