Files
web/apps/scandic-web/components/HotelReservation/EnterDetails/Details/RoomOne/index.tsx
Niclas Edenvin fb44990777 Merged in fix/SW-2501-validation-trigger (pull request #1924)
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
2025-05-02 13:59:23 +00:00

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>
)
}