"use client" import { zodResolver } from "@hookform/resolvers/zod" import { useCallback, useEffect, useRef } from "react" import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" import { usePhoneNumberParsing } from "@scandic-hotels/common/hooks/usePhoneNumberParsing" import { getDefaultCountryFromLang } from "@scandic-hotels/common/utils/phone" import Footnote from "@scandic-hotels/design-system/Footnote" import CountrySelect from "@scandic-hotels/design-system/Form/Country" import Phone from "@scandic-hotels/design-system/Form/Phone" import { useFormTracking } from "@scandic-hotels/tracking/useFormTracking" import { useBookingFlowConfig } from "../../../../bookingFlowConfig/bookingFlowConfigContext" import { useRoomContext } from "../../../../contexts/EnterDetails/RoomContext" import useLang from "../../../../hooks/useLang" import { getFormattedCountryList } from "../../../../misc/getFormatedCountryList" import { useEnterDetailsStore } from "../../../../stores/enter-details" import BookingFlowInput from "../../../BookingFlowInput" import { getErrorMessage } from "../../../BookingFlowInput/errors" import MemberPriceModal from "../MemberPriceModal" import { SpecialRequests } from "../SpecialRequests" import { JoinScandicFriendsCard } from "./JoinScandicFriendsCard" import { PartnerSASJoinScandicFriendsCard } from "./PartnerSASJoinScandicFriendsCard" import { type GuestDetailsSchema, guestDetailsSchema, signedInDetailsSchema, } from "./schema" import Signup from "./Signup" import styles from "./details.module.css" import type { User } from "@scandic-hotels/trpc/types/user" type DetailsProps = { user: User | null } const formID = "enter-details" export default function Details({ user }: DetailsProps) { const refs = useRef>({}) const intl = useIntl() const lang = useLang() const config = useBookingFlowConfig() const { lastRoom, addPreSubmitCallback } = useEnterDetailsStore((state) => ({ lastRoom: state.lastRoom, addPreSubmitCallback: state.actions.addPreSubmitCallback, })) const { actions: { updateDetails, updatePartialGuestData, setIncomplete }, room, roomNr, idx, } = useRoomContext() const initialData = room.guest const memberRate = "member" in room.roomRate ? room.roomRate.member : null const { phoneNumber, phoneNumberCC } = usePhoneNumberParsing( user?.phoneNumber || initialData.phoneNumber, initialData.phoneNumberCC ) const methods = useForm({ defaultValues: { countryCode: user?.address?.countryCode || initialData.countryCode, dateOfBirth: "dateOfBirth" in initialData ? initialData.dateOfBirth : undefined, email: user?.email || initialData.email, firstName: user?.firstName || initialData.firstName, join: initialData.join, lastName: user?.lastName || initialData.lastName, membershipNo: initialData.membershipNo, phoneNumber, phoneNumberCC, zipCode: "zipCode" in initialData ? initialData.zipCode : undefined, specialRequest: { comment: room.specialRequest.comment, }, }, criteriaMode: "all", mode: "onBlur", resolver: zodResolver(user ? signedInDetailsSchema : guestDetailsSchema), reValidateMode: "onChange", }) const { formState, handleSubmit, trigger, control, subscribe, setValue, watch, getValues, } = methods const { trackFormSubmit } = useFormTracking( "checkout", subscribe, control, lastRoom === idx ? "" : " - room 1" ) useEffect(() => { async function callback() { await trigger() trackFormSubmit() const baseFieldOrder = [ "firstName", "lastName", "countryCode", "email", "phoneNumber", "membershipNo", ] const joinChecked = methods.watch("join") const fieldOrder = joinChecked ? [...baseFieldOrder, "zipCode", "dateOfBirth"] : baseFieldOrder for (const name of fieldOrder) { const fieldError = methods.formState.errors[ name as keyof typeof methods.formState.errors ] if (fieldError && refs.current[name]) { return refs.current[name] ?? undefined } } return } addPreSubmitCallback(`${idx}-details`, callback) }, [addPreSubmitCallback, idx, trigger, trackFormSubmit, methods]) const onSubmit = useCallback( (values: GuestDetailsSchema) => { updateDetails(values) }, [updateDetails] ) const updateDetailsStore = useCallback(() => { if (formState.isValid) { handleSubmit(onSubmit)() } else { updatePartialGuestData({ firstName: getValues("firstName")?.toString(), lastName: getValues("lastName")?.toString(), membershipNo: getValues("membershipNo")?.toString(), }) setIncomplete() } }, [ formState.isValid, handleSubmit, onSubmit, updatePartialGuestData, getValues, setIncomplete, ]) useEffect(updateDetailsStore, [updateDetailsStore]) const countryCode = watch("countryCode") useEffect(() => { if (countryCode) { setValue("phoneNumberCC", countryCode.toLowerCase()) } }, [countryCode, setValue]) const showJoinCard = memberRate && !user return (
{showJoinCard ? ( ) : null}
{intl.formatMessage({ id: "enterDetails.roomInfo.title", defaultMessage: "Guest information", })}
{ refs.current.firstName = el }} >
{ refs.current.lastName = el }} >
{ refs.current.countryCode = el }} className={styles.fullWidth} >
{ refs.current.email = el }} className={styles.fullWidth} >
{ refs.current.phoneNumber = el }} className={styles.fullWidth} >
{user ? null : (
)}
) } function JoinScandicCard({ updateDetailsStore, }: { updateDetailsStore: () => void }) { const config = useBookingFlowConfig() switch (config.enterDetailsMembershipIdInputLocation) { case "form": return case "join-card": return ( ) default: const _exhaustiveCheck: never = config.enterDetailsMembershipIdInputLocation return null } }