* feat(SW-3516): Include partnerLoyaltyNumber on bookings - Added user context to BookingFlowProviders for user state management. - Updated booking input and output schemas to accommodate new user data. - Refactored booking mutation logic to include user-related information. - Improved type definitions for better TypeScript support across booking components. Approved-by: Anton Gunnarsson
174 lines
4.8 KiB
TypeScript
174 lines
4.8 KiB
TypeScript
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<typeof createBookingInput>
|
|
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]),
|
|
})
|
|
|
|
export const createBookingSchema = z
|
|
.object({
|
|
data: z.object({
|
|
attributes: z.object({
|
|
reservationStatus: z.string(),
|
|
guest: guestSchema.optional(),
|
|
paymentUrl: 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,
|
|
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,
|
|
}))
|