import { z } from "zod" import { ChildBedMapEnum } from "@scandic-hotels/trpc/enums/childBedMapEnum" import { REDEMPTION } from "@/constants/booking" export const bookingWidgetErrors = { AGE_REQUIRED: "AGE_REQUIRED", BED_CHOICE_REQUIRED: "BED_CHOICE_REQUIRED", CHILDREN_EXCEEDS_ADULTS: "CHILDREN_EXCEEDS_ADULTS", BOOKING_CODE_INVALID: "BOOKING_CODE_INVALID", REQUIRED: "REQUIRED", DESTINATION_REQUIRED: "DESTINATION_REQUIRED", MULTIROOM_BOOKING_CODE_UNAVAILABLE: "MULTIROOM_BOOKING_CODE_UNAVAILABLE", MULTIROOM_REWARD_NIGHT_UNAVAILABLE: "MULTIROOM_REWARD_NIGHT_UNAVAILABLE", CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE: "CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE", } as const export const guestRoomSchema = z .object({ adults: z.number().default(1), childrenInRoom: z .array( z.object({ age: z.number().min(0, bookingWidgetErrors.AGE_REQUIRED), bed: z.number().min(0, bookingWidgetErrors.BED_CHOICE_REQUIRED), }) ) .default([]), }) .superRefine((value, ctx) => { const childrenInAdultsBed = value.childrenInRoom.filter( (c) => c.bed === ChildBedMapEnum.IN_ADULTS_BED ) if (value.adults < childrenInAdultsBed.length) { const lastAdultBedIndex = value.childrenInRoom .map((c) => c.bed) .lastIndexOf(ChildBedMapEnum.IN_ADULTS_BED) ctx.addIssue({ code: z.ZodIssueCode.custom, message: bookingWidgetErrors.CHILDREN_EXCEEDS_ADULTS, path: ["childrenInRoom", lastAdultBedIndex], }) } }) export const guestRoomsSchema = z.array(guestRoomSchema) export const bookingCodeSchema = z .object({ value: z .string() .refine( (value) => !value || /(^D\d*$)|(^DSH[0-9a-z]*$)|(^L\d*$)|(^LH[0-9a-z]*$)|(^B[a-z]{3}\d{6})|(^VO[0-9a-z]*$)|^[0-9a-z]*$/i.test( value ), { message: bookingWidgetErrors.BOOKING_CODE_INVALID } ) .default(""), remember: z.boolean().default(false), flag: z.boolean().default(false), }) .optional() export const bookingWidgetSchema = z .object({ bookingCode: bookingCodeSchema, date: z.object({ // Update this as required once started working with Date picker in Nights component fromDate: z.string(), toDate: z.string(), }), redemption: z.boolean().default(false), rooms: guestRoomsSchema, search: z.string({ coerce: true }).min(1, bookingWidgetErrors.REQUIRED), selectedSearch: z.string().optional(), hotel: z.number().optional(), city: z.string().optional(), }) .superRefine((value, ctx) => { if (!value.hotel && !value.city) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: bookingWidgetErrors.DESTINATION_REQUIRED, path: ["search"], }) } if (value.rooms.length > 1 && value.bookingCode?.value.startsWith("VO")) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: bookingWidgetErrors.MULTIROOM_BOOKING_CODE_UNAVAILABLE, path: ["bookingCode.value"], }) ctx.addIssue({ code: z.ZodIssueCode.custom, message: bookingWidgetErrors.MULTIROOM_BOOKING_CODE_UNAVAILABLE, path: ["rooms"], }) } if (value.rooms.length > 1 && value.redemption) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: bookingWidgetErrors.MULTIROOM_REWARD_NIGHT_UNAVAILABLE, path: [REDEMPTION], }) ctx.addIssue({ code: z.ZodIssueCode.custom, message: bookingWidgetErrors.MULTIROOM_REWARD_NIGHT_UNAVAILABLE, path: ["rooms"], }) } if (value.bookingCode?.value && value.redemption) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: bookingWidgetErrors.CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE, path: [REDEMPTION], }) ctx.addIssue({ code: z.ZodIssueCode.custom, message: bookingWidgetErrors.CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE, path: ["bookingCode.value"], }) } })