Merged in fix/BOOK-323-enter-details-scroll-error (pull request #2986)
Fix/BOOK-323 enter details scroll error * fix(BOOK-323): scroll to invalid element on submit on enter details * fix(BOOK-323): update error message design * fix(BOOK-323): clean up * fix(BOOK-323): scroll to fields in room in right order * fix(BOOK-323): add id to translations * fix(BOOK-323): remove undefined * fix(BOOK-323): fix submitting state * fix(BOOK-323): use ref in multiroom for scrolling to right element, add membershipNo * fix(BOOK-323): fix invalid border country * fix(BOOK-323): use error message component * fix(BOOK-323): fix invalid focused styling on mobile * fix(BOOK-323): remove redundant dependency in callback Approved-by: Erik Tiekstra
This commit is contained in:
@@ -95,15 +95,15 @@ export default function PaymentClient({
|
||||
rooms,
|
||||
totalPrice,
|
||||
isSubmitting,
|
||||
preSubmitCallbacks,
|
||||
setIsSubmitting,
|
||||
runPreSubmitCallbacks,
|
||||
} = useEnterDetailsStore((state) => ({
|
||||
booking: state.booking,
|
||||
rooms: state.rooms,
|
||||
totalPrice: state.totalPrice,
|
||||
preSubmitCallbacks: state.preSubmitCallbacks,
|
||||
isSubmitting: state.isSubmitting,
|
||||
setIsSubmitting: state.actions.setIsSubmitting,
|
||||
runPreSubmitCallbacks: state.actions.runPreSubmitCallbacks,
|
||||
}))
|
||||
|
||||
const bookingMustBeGuaranteed = rooms.some(({ room }, idx) => {
|
||||
@@ -312,35 +312,39 @@ export default function PaymentClient({
|
||||
[hasFlexRates]
|
||||
)
|
||||
|
||||
const scrollToInvalidField = useCallback(async (): Promise<boolean> => {
|
||||
// If any room is not complete/valid, scroll to the first invalid field, this is needed as rooms and other fields are in separate forms
|
||||
|
||||
const invalidField = await runPreSubmitCallbacks()
|
||||
const errorNames = Object.keys(methods.formState.errors)
|
||||
const firstIncompleteRoomIndex = rooms.findIndex((room) => !room.isComplete)
|
||||
|
||||
const scrollToElement = (el: HTMLElement) => {
|
||||
const offset = getTopOffset()
|
||||
const top = el.getBoundingClientRect().top + window.scrollY - offset - 20
|
||||
window.scrollTo({ top, behavior: "smooth" })
|
||||
const input = el.querySelector<HTMLElement>("input")
|
||||
input?.focus({ preventScroll: true })
|
||||
}
|
||||
|
||||
if (invalidField) {
|
||||
scrollToElement(invalidField)
|
||||
} else if (errorNames.length > 0) {
|
||||
const firstErrorEl = document.querySelector(`[name="${errorNames[0]}"]`)
|
||||
if (firstErrorEl) {
|
||||
scrollToElement(firstErrorEl as HTMLElement)
|
||||
}
|
||||
}
|
||||
|
||||
return firstIncompleteRoomIndex !== -1
|
||||
}, [runPreSubmitCallbacks, rooms, methods.formState.errors, getTopOffset])
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(data: PaymentFormData) => {
|
||||
async (data: PaymentFormData) => {
|
||||
setIsSubmitting(true)
|
||||
|
||||
Object.values(preSubmitCallbacks).forEach((callback) => {
|
||||
callback()
|
||||
})
|
||||
const firstIncompleteRoomIndex = rooms.findIndex(
|
||||
(room) => !room.isComplete
|
||||
)
|
||||
|
||||
// If any room is not complete/valid, scroll to it
|
||||
if (firstIncompleteRoomIndex !== -1) {
|
||||
const roomElement = document.getElementById(
|
||||
`room-${firstIncompleteRoomIndex + 1}`
|
||||
)
|
||||
|
||||
if (!roomElement) {
|
||||
setIsSubmitting(false)
|
||||
return
|
||||
}
|
||||
const roomElementTop =
|
||||
roomElement.getBoundingClientRect().top + window.scrollY
|
||||
|
||||
window.scrollTo({
|
||||
top: roomElementTop - getTopOffset() - 20,
|
||||
behavior: "smooth",
|
||||
})
|
||||
|
||||
const isRoomInvalid = await scrollToInvalidField()
|
||||
if (isRoomInvalid) {
|
||||
setIsSubmitting(false)
|
||||
return
|
||||
}
|
||||
@@ -502,13 +506,11 @@ export default function PaymentClient({
|
||||
}
|
||||
),
|
||||
}
|
||||
|
||||
initiateBooking.mutate(payload)
|
||||
},
|
||||
[
|
||||
setIsSubmitting,
|
||||
preSubmitCallbacks,
|
||||
rooms,
|
||||
scrollToInvalidField,
|
||||
getPaymentMethod,
|
||||
savedCreditCards,
|
||||
lang,
|
||||
@@ -517,8 +519,8 @@ export default function PaymentClient({
|
||||
fromDate,
|
||||
toDate,
|
||||
hotelId,
|
||||
rooms,
|
||||
initiateBooking,
|
||||
getTopOffset,
|
||||
isUserLoggedIn,
|
||||
booking.rooms,
|
||||
user?.data?.partnerLoyaltyNumber,
|
||||
@@ -534,6 +536,13 @@ export default function PaymentClient({
|
||||
defaultMessage: "Select payment method",
|
||||
})
|
||||
|
||||
const handleInvalidSubmit = async () => {
|
||||
const valid = await methods.trigger()
|
||||
if (!valid) {
|
||||
await scrollToInvalidField()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section
|
||||
className={cx(styles.paymentSection, {
|
||||
@@ -549,7 +558,7 @@ export default function PaymentClient({
|
||||
<FormProvider {...methods}>
|
||||
<form
|
||||
className={styles.paymentContainer}
|
||||
onSubmit={methods.handleSubmit(handleSubmit)}
|
||||
onSubmit={methods.handleSubmit(handleSubmit, handleInvalidSubmit)}
|
||||
id={formId}
|
||||
>
|
||||
{booking.searchType === SEARCH_TYPE_REDEMPTION ? (
|
||||
|
||||
Reference in New Issue
Block a user