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
This commit is contained in:
Niclas Edenvin
2025-05-02 13:59:23 +00:00
parent d49ecdae1f
commit fb44990777
5 changed files with 57 additions and 13 deletions

View File

@@ -24,7 +24,8 @@ const formID = "enter-details"
export default function Details() {
const intl = useIntl()
const { rooms } = useEnterDetailsStore((state) => ({
const { addPreSubmitCallback, rooms } = useEnterDetailsStore((state) => ({
addPreSubmitCallback: state.actions.addPreSubmitCallback,
rooms: state.rooms,
}))
@@ -71,13 +72,23 @@ export default function Details() {
},
})
const {
formState: { isValid },
handleSubmit,
trigger,
} = methods
useEffect(() => {
addPreSubmitCallback(`${idx}-details`, trigger)
}, [addPreSubmitCallback, idx, trigger])
const updateDetailsStore = useCallback(() => {
if (methods.formState.isValid) {
methods.handleSubmit(updateDetails)()
if (isValid) {
handleSubmit(updateDetails)()
} else {
setIncomplete()
}
}, [methods, setIncomplete, updateDetails])
}, [handleSubmit, isValid, setIncomplete, updateDetails])
useEffect(updateDetailsStore, [methods.formState.isValid, updateDetailsStore])

View File

@@ -4,6 +4,8 @@ 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"
@@ -27,10 +29,15 @@ 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
@@ -58,6 +65,16 @@ export default function Details({ user }: DetailsProps) {
},
})
const {
formState: { isValid },
handleSubmit,
trigger,
} = methods
useEffect(() => {
addPreSubmitCallback(`${idx}-details`, trigger)
}, [addPreSubmitCallback, idx, trigger])
const onSubmit = useCallback(
(values: DetailsSchema) => {
updateDetails(values)
@@ -66,12 +83,12 @@ export default function Details({ user }: DetailsProps) {
)
const updateDetailsStore = useCallback(() => {
if (methods.formState.isValid) {
methods.handleSubmit(onSubmit)()
if (isValid) {
handleSubmit(onSubmit)()
} else {
setIncomplete()
}
}, [methods, onSubmit, setIncomplete])
}, [handleSubmit, isValid, onSubmit, setIncomplete])
useEffect(updateDetailsStore, [methods.formState.isValid, updateDetailsStore])

View File

@@ -76,11 +76,13 @@ export default function PaymentClient({
const [showBookingAlert, setShowBookingAlert] = useState(false)
const { booking, rooms, totalPrice } = useEnterDetailsStore((state) => ({
booking: state.booking,
rooms: state.rooms,
totalPrice: state.totalPrice,
}))
const { booking, rooms, totalPrice, preSubmitCallbacks } =
useEnterDetailsStore((state) => ({
booking: state.booking,
rooms: state.rooms,
totalPrice: state.totalPrice,
preSubmitCallbacks: state.preSubmitCallbacks,
}))
const bookingMustBeGuaranteed = rooms.some(({ room }, idx) => {
if (idx === 0 && isUserLoggedIn && room.memberMustBeGuaranteed) {
@@ -282,6 +284,9 @@ export default function PaymentClient({
const handleSubmit = useCallback(
(data: PaymentFormData) => {
Object.values(preSubmitCallbacks).forEach((callback) => {
callback()
})
const firstIncompleteRoomIndex = rooms.findIndex(
(room) => !room.isComplete
)
@@ -445,10 +450,11 @@ export default function PaymentClient({
fromDate,
toDate,
rooms,
booking,
booking.rooms,
getPaymentMethod,
hasOnlyFlexRates,
bookingMustBeGuaranteed,
preSubmitCallbacks,
isUserLoggedIn,
getTopOffset,
]

View File

@@ -355,6 +355,7 @@ export function createDetailsStore(
searchParamString: searchParams,
totalPrice: initialTotalPrice,
vat: initialState.vat,
preSubmitCallbacks: {},
actions: {
setIsSubmittingDisabled(isSubmittingDisabled) {
@@ -386,6 +387,13 @@ export function createDetailsStore(
})
)
},
addPreSubmitCallback(name, callback) {
return set(
produce((state: DetailsState) => {
state.preSubmitCallbacks[name] = callback
})
)
},
},
}))
}

View File

@@ -87,6 +87,7 @@ export interface DetailsState {
setTotalPrice: (totalPrice: Price) => void
toggleSummaryOpen: () => void
updateSeachParamString: (searchParamString: string) => void
addPreSubmitCallback: (name: string, callback: () => void) => void
}
booking: SelectRateSearchParams
breakfastPackages: BreakfastPackages
@@ -98,6 +99,7 @@ export interface DetailsState {
searchParamString: string
totalPrice: Price
vat: number
preSubmitCallbacks: Record<string, () => void>
}
export type PersistedState = {