import { z } from "zod" import { Lang } from "@scandic-hotels/common/constants/language" import { langToApiLang } from "../../../../constants/apiLang" import { ChildBedTypeEnum } from "../../../../enums/childBedTypeEnum" import { calculateRefId } from "../../../../utils/refId" import { guestSchema } from "../../output" const roomsSchema = z .array( z.object({ adults: z.number().int().nonnegative(), bookingCode: z.string().nullish(), childrenAges: z .array( z.object({ age: z.number().int().nonnegative(), bedType: z.nativeEnum(ChildBedTypeEnum), }) ) .default([]), rateCode: z.string(), redemptionCode: z.string().optional(), roomTypeCode: z.coerce.string(), guest: z.object({ becomeMember: z.boolean(), countryCode: z.string(), dateOfBirth: z.string().nullish(), email: z.string().email(), firstName: z.string(), lastName: z.string(), membershipNumber: z.string().nullish(), postalCode: z.string().nullish(), phoneNumber: z.string(), partnerLoyaltyNumber: z.string().nullable(), }), smsConfirmationRequested: z.boolean(), specialRequest: z.object({ comment: z.string().optional(), }), packages: z.object({ breakfast: z.boolean(), allergyFriendly: z.boolean(), petFriendly: z.boolean(), accessibility: z.boolean(), }), roomPrice: z.object({ memberPrice: z.number().nullish(), publicPrice: z.number().nullish(), }), }) ) .superRefine((data, ctx) => { data.forEach((room, idx) => { if (idx === 0 && room.guest.becomeMember) { if (!room.guest.dateOfBirth) { ctx.addIssue({ code: z.ZodIssueCode.invalid_type, expected: "string", received: typeof room.guest.dateOfBirth, path: ["guest", "dateOfBirth"], }) } if (!room.guest.postalCode) { ctx.addIssue({ code: z.ZodIssueCode.invalid_type, expected: "string", received: typeof room.guest.postalCode, path: ["guest", "postalCode"], }) } } }) }) const paymentSchema = z.object({ paymentMethod: z.string(), card: z .object({ alias: z.string(), expiryDate: z.string(), cardType: z.string(), }) .optional(), cardHolder: z .object({ email: z.string().email(), name: z.string(), phoneCountryCode: z.string(), phoneSubscriber: z.string(), }) .optional(), success: z.string(), error: z.string(), cancel: z.string(), }) export type CreateBookingInput = z.input export const createBookingInput = z.object({ hotelId: z.string(), checkInDate: z.string(), checkOutDate: z.string(), rooms: roomsSchema, payment: paymentSchema.optional(), language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]), partnerSpecific: z .object({ eurobonusAccessToken: z.string(), }) .optional(), }) export const createBookingSchema = z .object({ data: z.object({ attributes: z.object({ reservationStatus: z.string(), guest: guestSchema.optional(), paymentUrl: z.string().nullable().optional(), paymentMethod: z.string().nullable().optional(), rooms: z .array( z.object({ confirmationNumber: z.string(), cancellationNumber: z.string().nullable(), priceChangedMetadata: z .object({ roomPrice: z.number(), totalPrice: z.number(), }) .nullable() .optional(), }) ) .default([]), errors: z .array( z.object({ confirmationNumber: z.string().nullable().optional(), errorCode: z.string(), description: z.string().nullable().optional(), meta: z .record(z.string(), z.union([z.string(), z.number()])) .nullable() .optional(), }) ) .default([]), }), type: z.string(), id: z.string(), links: z.object({ self: z.object({ href: z.string().url(), meta: z.object({ method: z.string(), }), }), }), }), }) .transform((d) => ({ id: d.data.id, links: d.data.links, type: d.data.type, reservationStatus: d.data.attributes.reservationStatus, paymentUrl: d.data.attributes.paymentUrl, paymentMethod: d.data.attributes.paymentMethod, rooms: d.data.attributes.rooms.map((room) => { const lastName = d.data.attributes.guest?.lastName ?? "" return { ...room, refId: calculateRefId(room.confirmationNumber, lastName), } }), errors: d.data.attributes.errors, guest: d.data.attributes.guest, })) export type CreateBookingSchema = z.infer