Files
web/packages/booking-flow/lib/components/EnterDetails/Details/RoomOne/Signup/index.tsx
Bianca Widstam c473bbc8b0 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
2025-10-24 11:30:56 +00:00

120 lines
3.2 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import {
type FieldErrors,
type RegisterOptions,
useWatch,
} from "react-hook-form"
import { useIntl } from "react-intl"
import Caption from "@scandic-hotels/design-system/Caption"
import DateSelect from "@scandic-hotels/design-system/Form/Date"
import { useBookingFlowConfig } from "../../../../../bookingFlowConfig/bookingFlowConfigContext"
import useLang from "../../../../../hooks/useLang"
import BookingFlowInput from "../../../../BookingFlowInput"
import { getErrorMessage } from "../../../../BookingFlowInput/errors"
import { MembershipNumberInput } from "./MembershipNumberInput"
import styles from "./signup.module.css"
export default function Signup({
errors,
name,
registerOptions,
refs,
}: {
errors: FieldErrors
name: string
registerOptions?: RegisterOptions
refs: React.RefObject<Record<string, HTMLElement | null>>
}) {
const intl = useIntl()
const lang = useLang()
const config = useBookingFlowConfig()
const [isJoinChecked, setIsJoinChecked] = useState(false)
const joinValue = useWatch({ name })
useEffect(() => {
// In order to avoid hydration errors the state needs to be set as side effect,
// since the join value can come from search params
setIsJoinChecked(joinValue)
}, [joinValue])
if (isJoinChecked)
return (
<div className={styles.additionalFormData}>
<div
ref={(el) => {
refs.current.zipCode = el
}}
>
<BookingFlowInput
name="zipCode"
label={intl.formatMessage({
id: "common.zipCode",
defaultMessage: "Zip code",
})}
registerOptions={{ required: true, ...registerOptions }}
/>
</div>
<div
className={styles.dateField}
ref={(el) => {
refs.current.dateOfBirth = el
}}
>
<header>
<Caption type="bold">
<span className={styles.required}>
{intl.formatMessage({
id: "common.birthDate",
defaultMessage: "Birth date",
})}
</span>
</Caption>
</header>
<DateSelect
labels={{
day: intl.formatMessage({
id: "common.day",
defaultMessage: "Day",
}),
month: intl.formatMessage({
id: "common.month",
defaultMessage: "Month",
}),
year: intl.formatMessage({
id: "common.year",
defaultMessage: "Year",
}),
errorMessage: getErrorMessage(
intl,
config.variant,
errors["dateOfBirth"]?.message?.toString()
),
}}
lang={lang}
name="dateOfBirth"
registerOptions={{ required: true, ...registerOptions }}
/>
</div>
</div>
)
if (config.enterDetailsMembershipIdInputLocation === "join-card") return null
return (
<div
ref={(el) => {
refs.current.membershipNo = el
}}
>
<MembershipNumberInput registerOptions={registerOptions} />
</div>
)
}