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:
Bianca Widstam
2025-10-24 11:30:56 +00:00
parent 6543ca5dc3
commit c473bbc8b0
27 changed files with 692 additions and 288 deletions

View File

@@ -10,3 +10,7 @@
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
width: min(696px, 100%);
}
.errorContainer {
width: min(696px, 100%);
}

View File

@@ -1,7 +1,7 @@
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useCallback, useEffect } from "react"
import { useCallback, useEffect, useRef } from "react"
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"
@@ -10,6 +10,7 @@ import Body from "@scandic-hotels/design-system/Body"
import RadioCard from "@scandic-hotels/design-system/Form/RadioCard"
import BreakfastBuffetIcon from "@scandic-hotels/design-system/Icons/BreakfastBuffetIcon"
import NoBreakfastBuffetIcon from "@scandic-hotels/design-system/Icons/NoBreakfastBuffetIcon"
import { MessageBanner } from "@scandic-hotels/design-system/MessageBanner"
import { trackBreakfastSelection } from "@scandic-hotels/tracking/booking"
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
@@ -21,11 +22,16 @@ import styles from "./breakfast.module.css"
export default function Breakfast() {
const intl = useIntl()
const formRef = useRef<HTMLDivElement>(null)
const packages = useEnterDetailsStore((state) => state.breakfastPackages)
const hotelId = useEnterDetailsStore((state) => state.booking.hotelId)
const { addPreSubmitCallback } = useEnterDetailsStore((state) => ({
addPreSubmitCallback: state.actions.addPreSubmitCallback,
}))
const {
actions: { updateBreakfast },
room,
idx,
} = useRoomContext()
const hasChildrenInRoom = !!room.childrenInRoom?.length
@@ -65,6 +71,19 @@ export default function Breakfast() {
[packages, hotelId, room.adults, updateBreakfast]
)
useEffect(() => {
async function callback() {
const isValid = await methods.trigger()
if (!isValid && methods.formState.errors.breakfast) {
return formRef.current ?? undefined
}
return
}
addPreSubmitCallback(`${idx}-breakfast`, callback)
}, [addPreSubmitCallback, methods, idx])
const selectedBreakfast = methods.watch("breakfast")
const handleSubmit = methods.handleSubmit
useEffect(() => {
@@ -75,7 +94,7 @@ export default function Breakfast() {
return (
<FormProvider {...methods}>
<div className={styles.container}>
<div className={styles.container} ref={formRef}>
{hasChildrenInRoom ? (
<Body>
{intl.formatMessage({
@@ -85,6 +104,19 @@ export default function Breakfast() {
})}
</Body>
) : null}
{methods.formState.errors.breakfast && (
<div className={styles.errorContainer}>
<MessageBanner
text={intl.formatMessage({
id: "enterDetails.breakfast.error.required",
defaultMessage: "Breakfast option is required",
})}
type="error"
textColor="error"
/>
</div>
)}
<form className={styles.form} onSubmit={methods.handleSubmit(onSubmit)}>
{packages?.map((pkg) => (
<RadioCard