From fb449907773e1f6c5480c406f4da2698d9aaadf5 Mon Sep 17 00:00:00 2001 From: Niclas Edenvin Date: Fri, 2 May 2025 13:59:23 +0000 Subject: [PATCH] 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 --- .../EnterDetails/Details/Multiroom/index.tsx | 19 +++++++++++---- .../EnterDetails/Details/RoomOne/index.tsx | 23 ++++++++++++++++--- .../EnterDetails/Payment/PaymentClient.tsx | 18 ++++++++++----- .../scandic-web/stores/enter-details/index.ts | 8 +++++++ .../scandic-web/types/stores/enter-details.ts | 2 ++ 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Details/Multiroom/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Details/Multiroom/index.tsx index 6b678a1ea..2bf63ae08 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Details/Multiroom/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Details/Multiroom/index.tsx @@ -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]) diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Details/RoomOne/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Details/RoomOne/index.tsx index 4250f8186..9297e35ac 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Details/RoomOne/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Details/RoomOne/index.tsx @@ -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]) diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx index 8b8d3dea7..09eec17e0 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx @@ -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, ] diff --git a/apps/scandic-web/stores/enter-details/index.ts b/apps/scandic-web/stores/enter-details/index.ts index ff9d869e2..81a7e40fd 100644 --- a/apps/scandic-web/stores/enter-details/index.ts +++ b/apps/scandic-web/stores/enter-details/index.ts @@ -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 + }) + ) + }, }, })) } diff --git a/apps/scandic-web/types/stores/enter-details.ts b/apps/scandic-web/types/stores/enter-details.ts index 5fdd4e7fe..da801fa19 100644 --- a/apps/scandic-web/types/stores/enter-details.ts +++ b/apps/scandic-web/types/stores/enter-details.ts @@ -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 void> } export type PersistedState = {