fix(SW-2501): validation trigger * fix(SW-2501): validation trigger On enter details, when submitting we want to trigger the validation for the details forms for each room. This will display error messages for the form fields with errors if they are not already displayed, so the user knows which fields has errors. Approved-by: Tobias Johansson
176 lines
5.4 KiB
TypeScript
176 lines
5.4 KiB
TypeScript
"use client"
|
|
import { zodResolver } from "@hookform/resolvers/zod"
|
|
import { useCallback, useEffect } from "react"
|
|
import { FormProvider, useForm } from "react-hook-form"
|
|
import { useIntl } from "react-intl"
|
|
|
|
import { useEnterDetailsStore } from "@/stores/enter-details"
|
|
|
|
import SpecialRequests from "@/components/HotelReservation/EnterDetails/Details/SpecialRequests"
|
|
import CountrySelect from "@/components/TempDesignSystem/Form/Country"
|
|
import Input from "@/components/TempDesignSystem/Form/Input"
|
|
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
|
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
|
|
import { useRoomContext } from "@/contexts/Details/Room"
|
|
|
|
import AutoFillDetector from "./AutoFillDetector"
|
|
import JoinScandicFriendsCard from "./JoinScandicFriendsCard"
|
|
import { guestDetailsSchema, signedInDetailsSchema } from "./schema"
|
|
import Signup from "./Signup"
|
|
|
|
import styles from "./details.module.css"
|
|
|
|
import type {
|
|
DetailsProps,
|
|
DetailsSchema,
|
|
} from "@/types/components/hotelReservation/enterDetails/details"
|
|
|
|
const formID = "enter-details"
|
|
export default function Details({ user }: DetailsProps) {
|
|
const intl = useIntl()
|
|
|
|
const { addPreSubmitCallback } = useEnterDetailsStore((state) => ({
|
|
addPreSubmitCallback: state.actions.addPreSubmitCallback,
|
|
}))
|
|
|
|
const {
|
|
actions: { updateDetails, setIncomplete },
|
|
room,
|
|
roomNr,
|
|
idx,
|
|
} = useRoomContext()
|
|
const initialData = room.guest
|
|
|
|
const memberRate = "member" in room.roomRate ? room.roomRate.member : null
|
|
|
|
const methods = useForm<DetailsSchema>({
|
|
criteriaMode: "all",
|
|
mode: "all",
|
|
resolver: zodResolver(user ? signedInDetailsSchema : guestDetailsSchema),
|
|
reValidateMode: "onChange",
|
|
values: {
|
|
countryCode: user?.address?.countryCode ?? initialData.countryCode,
|
|
dateOfBirth:
|
|
"dateOfBirth" in initialData ? initialData.dateOfBirth : undefined,
|
|
email: user?.email ?? initialData.email,
|
|
firstName: user?.firstName ?? initialData.firstName,
|
|
join: initialData.join,
|
|
lastName: user?.lastName ?? initialData.lastName,
|
|
membershipNo: initialData.membershipNo,
|
|
phoneNumber: user?.phoneNumber ?? initialData.phoneNumber,
|
|
zipCode: "zipCode" in initialData ? initialData.zipCode : undefined,
|
|
specialRequest: {
|
|
comment: room.specialRequest.comment,
|
|
},
|
|
},
|
|
})
|
|
|
|
const {
|
|
formState: { isValid },
|
|
handleSubmit,
|
|
trigger,
|
|
} = methods
|
|
|
|
useEffect(() => {
|
|
addPreSubmitCallback(`${idx}-details`, trigger)
|
|
}, [addPreSubmitCallback, idx, trigger])
|
|
|
|
const onSubmit = useCallback(
|
|
(values: DetailsSchema) => {
|
|
updateDetails(values)
|
|
},
|
|
[updateDetails]
|
|
)
|
|
|
|
const updateDetailsStore = useCallback(() => {
|
|
if (isValid) {
|
|
handleSubmit(onSubmit)()
|
|
} else {
|
|
setIncomplete()
|
|
}
|
|
}, [handleSubmit, isValid, onSubmit, setIncomplete])
|
|
|
|
useEffect(updateDetailsStore, [methods.formState.isValid, updateDetailsStore])
|
|
|
|
return (
|
|
<FormProvider {...methods}>
|
|
<form
|
|
className={styles.form}
|
|
id={`${formID}-room-${roomNr}`}
|
|
onSubmit={methods.handleSubmit(onSubmit)}
|
|
>
|
|
{user || !memberRate ? null : <JoinScandicFriendsCard />}
|
|
<div className={styles.container}>
|
|
<Footnote
|
|
color="uiTextHighContrast"
|
|
textTransform="uppercase"
|
|
type="label"
|
|
className={styles.fullWidth}
|
|
>
|
|
{intl.formatMessage({
|
|
defaultMessage: "Guest information",
|
|
})}
|
|
</Footnote>
|
|
<Input
|
|
label={intl.formatMessage({
|
|
defaultMessage: "First name",
|
|
})}
|
|
maxLength={30}
|
|
name="firstName"
|
|
readOnly={!!user}
|
|
registerOptions={{ required: true, onBlur: updateDetailsStore }}
|
|
/>
|
|
<Input
|
|
label={intl.formatMessage({
|
|
defaultMessage: "Last name",
|
|
})}
|
|
maxLength={30}
|
|
name="lastName"
|
|
readOnly={!!user}
|
|
registerOptions={{ required: true, onBlur: updateDetailsStore }}
|
|
/>
|
|
<CountrySelect
|
|
className={styles.fullWidth}
|
|
label={intl.formatMessage({
|
|
defaultMessage: "Country",
|
|
})}
|
|
name="countryCode"
|
|
readOnly={!!user}
|
|
registerOptions={{ required: true, onBlur: updateDetailsStore }}
|
|
/>
|
|
<Input
|
|
className={styles.fullWidth}
|
|
label={intl.formatMessage({
|
|
defaultMessage: "Email address",
|
|
})}
|
|
name="email"
|
|
readOnly={!!user}
|
|
registerOptions={{ required: true, onBlur: updateDetailsStore }}
|
|
/>
|
|
<Phone
|
|
className={styles.fullWidth}
|
|
label={intl.formatMessage({
|
|
defaultMessage: "Phone number",
|
|
})}
|
|
name="phoneNumber"
|
|
readOnly={!!user}
|
|
registerOptions={{ required: true, onBlur: updateDetailsStore }}
|
|
/>
|
|
{user ? null : (
|
|
<div className={styles.fullWidth}>
|
|
<Signup
|
|
name="join"
|
|
registerOptions={{ onBlur: updateDetailsStore }}
|
|
/>
|
|
</div>
|
|
)}
|
|
<SpecialRequests
|
|
registerOptions={{ required: true, onBlur: updateDetailsStore }}
|
|
/>
|
|
</div>
|
|
<AutoFillDetector />
|
|
</form>
|
|
</FormProvider>
|
|
)
|
|
}
|