import { z } from "zod" import { dt } from "@scandic-hotels/common/dt" import { phoneValidator } from "@scandic-hotels/common/utils/zod/phoneValidator" import { specialRequestSchema } from "@/components/HotelReservation/EnterDetails/Details/SpecialRequests/schema" // stringMatcher regex is copied from current web as specified by requirements. const stringMatcher = /^[A-Za-z¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ0-9-\s]*$/ const isValidString = (key: string) => stringMatcher.test(key) export const roomOneErrors = { COUNTRY_REQUIRED: "COUNTRY_REQUIRED", FIRST_NAME_REQUIRED: "FIRST_NAME_REQUIRED", FIRST_NAME_SPECIAL_CHARACTERS: "FIRST_NAME_SPECIAL_CHARACTERS", LAST_NAME_REQUIRED: "LAST_NAME_REQUIRED", LAST_NAME_SPECIAL_CHARACTERS: "LAST_NAME_SPECIAL_CHARACTERS", PHONE_REQUIRED: "PHONE_REQUIRED", PHONE_REQUESTED: "PHONE_REQUESTED", EMAIL_REQUIRED: "EMAIL_REQUIRED", MEMBERSHIP_NO_ONLY_DIGITS: "MEMBERSHIP_NO_ONLY_DIGITS", MEMBERSHIP_NO_INVALID: "MEMBERSHIP_NO_INVALID", ZIP_CODE_REQUIRED: "ZIP_CODE_REQUIRED", ZIP_CODE_INVALID: "ZIP_CODE_INVALID", BIRTH_DATE_REQUIRED: "BIRTH_DATE_REQUIRED", BIRTH_DATE_AGE_18: "BIRTH_DATE_AGE_18", } as const export const baseDetailsSchema = z.object({ countryCode: z.string().min(1, roomOneErrors.COUNTRY_REQUIRED), email: z.string().email(roomOneErrors.EMAIL_REQUIRED), firstName: z .string() .min(1, roomOneErrors.FIRST_NAME_REQUIRED) .refine(isValidString, roomOneErrors.FIRST_NAME_SPECIAL_CHARACTERS), lastName: z .string() .min(1, roomOneErrors.LAST_NAME_REQUIRED) .refine(isValidString, roomOneErrors.LAST_NAME_SPECIAL_CHARACTERS), phoneNumber: phoneValidator( roomOneErrors.PHONE_REQUIRED, roomOneErrors.PHONE_REQUESTED ), phoneNumberCC: z.string(), specialRequest: specialRequestSchema, }) export const notJoinDetailsSchema = baseDetailsSchema.merge( z.object({ join: z.literal(false), zipCode: z.string().optional(), dateOfBirth: z.string().optional(), membershipNo: z .string() .optional() .refine((val) => { if (val) { return !val.match(/[^0-9]/g) } return true }, roomOneErrors.MEMBERSHIP_NO_ONLY_DIGITS) .refine((num) => { if (num) { return num.match(/^30812(?!(0|1|2))[0-9]{9}$/) } return true }, roomOneErrors.MEMBERSHIP_NO_INVALID), }) ) export const joinDetailsSchema = baseDetailsSchema.merge( z.object({ join: z.literal(true), zipCode: z .string() .min(1, roomOneErrors.ZIP_CODE_REQUIRED) .regex(/^[A-Za-z0-9-\s]{1,9}$/g, roomOneErrors.ZIP_CODE_INVALID), dateOfBirth: z .string() .min(1, roomOneErrors.BIRTH_DATE_REQUIRED) .refine((date) => { const today = dt() const dob = dt(date) const age = today.diff(dob, "year") return age >= 18 }, roomOneErrors.BIRTH_DATE_AGE_18), membershipNo: z.string().default(""), }) ) export const guestDetailsSchema = z.discriminatedUnion("join", [ notJoinDetailsSchema, joinDetailsSchema, ]) // For signed in users we accept partial or invalid data. Users cannot // change their info in this flow, so we don't want to validate it. export const signedInDetailsSchema = z.object({ countryCode: z.string().default(""), email: z.string().default(""), firstName: z.string().default(""), lastName: z.string().default(""), membershipNo: z.string().default(""), phoneNumber: z.string().default(""), phoneNumberCC: z.string().default(""), join: z .boolean() .optional() .transform((_) => false), dateOfBirth: z.string().default(""), zipCode: z.string().default(""), specialRequest: specialRequestSchema, })