diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/index.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/index.module.css
new file mode 100644
index 000000000..490c64c24
--- /dev/null
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/index.module.css
@@ -0,0 +1,6 @@
+.errorContainer {
+ margin: 0 auto;
+ padding: var(--Spacing-x-one-and-half) 0;
+ width: 100%;
+ max-width: var(--max-width-page);
+}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/index.tsx
index 46fe36ec2..1c14d77ad 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/index.tsx
@@ -1,7 +1,10 @@
"use client"
+import { useIntl } from "react-intl"
+
import { trpc } from "@/lib/trpc/client"
+import Alert from "@/components/TempDesignSystem/Alert"
import useLang from "@/hooks/useLang"
import RatesProvider from "@/providers/RatesProvider"
@@ -9,7 +12,10 @@ import RateSummary from "./RateSummary"
import Rooms from "./Rooms"
import { RoomsContainerSkeleton } from "./RoomsContainerSkeleton"
+import styles from "./index.module.css"
+
import type { RoomsContainerProps } from "@/types/components/hotelReservation/selectRate/roomsContainer"
+import { AlertTypeEnum } from "@/types/enums/alert"
export function RoomsContainer({
booking,
@@ -18,25 +24,45 @@ export function RoomsContainer({
vat,
}: RoomsContainerProps) {
const lang = useLang()
+ const intl = useIntl()
- const roomsAvailability = trpc.hotel.availability.selectRate.rooms.useQuery({
- booking,
- lang,
- })
+ const { data, isFetching, isError, error } =
+ trpc.hotel.availability.selectRate.rooms.useQuery(
+ {
+ booking,
+ lang,
+ },
+ {
+ retry(failureCount, error) {
+ if (error.data?.code === "BAD_REQUEST") {
+ return false
+ }
- if (
- (roomsAvailability.isFetching || !roomsAvailability.data) &&
- !roomsAvailability.isFetched
- ) {
+ return failureCount <= 3
+ },
+ }
+ )
+
+ if (isFetching) {
return
}
+ if (isError) {
+ const errorMessage = getErrorMessage(error.data?.zodError?.formErrors, intl)
+
+ return (
+
+ )
+ }
+
return (
@@ -44,3 +70,25 @@ export function RoomsContainer({
)
}
+
+function getErrorMessage(
+ formErrors: string[] | undefined,
+ intl: ReturnType
+) {
+ const firstError = formErrors?.at(0)
+
+ switch (firstError) {
+ case "FROMDATE_INVALID":
+ case "TODATE_INVALID":
+ case "TODATE_MUST_BE_AFTER_FROMDATE":
+ case "FROMDATE_CANNOT_BE_IN_THE_PAST": {
+ return intl.formatMessage({
+ defaultMessage: "Invalid dates",
+ })
+ }
+ default:
+ return intl.formatMessage({
+ defaultMessage: "Something went wrong",
+ })
+ }
+}
diff --git a/apps/scandic-web/server/routers/hotels/input.ts b/apps/scandic-web/server/routers/hotels/input.ts
index ea0ec7031..dfb0e4497 100644
--- a/apps/scandic-web/server/routers/hotels/input.ts
+++ b/apps/scandic-web/server/routers/hotels/input.ts
@@ -1,3 +1,4 @@
+import dayjs from "dayjs"
import { z } from "zod"
import { Lang } from "@/constants/languages"
@@ -58,17 +59,60 @@ const baseBookingSchema = z.object({
toDate: z.string(),
})
-export const selectRateRoomsAvailabilityInputSchema = z.object({
- booking: baseBookingSchema.extend({
- rooms: z.array(
- baseRoomSchema.extend({
- rateCode: z.string().optional(),
- roomTypeCode: z.string().optional(),
- })
- ),
- }),
- lang: z.nativeEnum(Lang),
-})
+export const selectRateRoomsAvailabilityInputSchema = z
+ .object({
+ booking: baseBookingSchema.extend({
+ rooms: z.array(
+ baseRoomSchema.extend({
+ rateCode: z.string().optional(),
+ roomTypeCode: z.string().optional(),
+ })
+ ),
+ }),
+ lang: z.nativeEnum(Lang),
+ })
+ .refine(
+ (data) => {
+ const fromDate = dayjs(data.booking.fromDate)
+
+ return fromDate.isValid()
+ },
+ {
+ message: "FROMDATE_INVALID",
+ }
+ )
+ .refine(
+ (data) => {
+ const toDate = dayjs(data.booking.toDate)
+
+ return toDate.isValid()
+ },
+ {
+ message: "TODATE_INVALID",
+ }
+ )
+ .refine(
+ (data) => {
+ const fromDate = dayjs(data.booking.fromDate).startOf("day")
+ const toDate = dayjs(data.booking.toDate).startOf("day")
+
+ return fromDate.isBefore(toDate)
+ },
+ {
+ message: "FROMDATE_BEFORE_TODATE",
+ }
+ )
+ .refine(
+ (data) => {
+ const fromDate = dayjs(data.booking.fromDate)
+ const today = dayjs().startOf("day")
+
+ return fromDate.isSameOrAfter(today)
+ },
+ {
+ message: "FROMDATE_CANNOT_BE_IN_THE_PAST",
+ }
+ )
export const selectRateRoomAvailabilityInputSchema = z.object({
booking: baseBookingSchema.extend({