diff --git a/apps/scandic-web/components/Forms/Edit/Profile/index.tsx b/apps/scandic-web/components/Forms/Edit/Profile/index.tsx index a36267ffa..ca2f63262 100644 --- a/apps/scandic-web/components/Forms/Edit/Profile/index.tsx +++ b/apps/scandic-web/components/Forms/Edit/Profile/index.tsx @@ -1,13 +1,8 @@ "use client" import { zodResolver } from "@hookform/resolvers/zod" -import { - isValidPhoneNumber, - parsePhoneNumberWithError, -} from "libphonenumber-js" import { useParams, useRouter } from "next/navigation" import { useEffect, useState } from "react" import { FormProvider, useForm } from "react-hook-form" -import { usePhoneInput } from "react-international-phone" import { useIntl } from "react-intl" import { type Lang, langToApiLang } from "@/constants/languages" @@ -21,6 +16,7 @@ import ChangeNameDisclaimer from "@/components/MyPages/Profile/ChangeNameDisclai import Button from "@/components/TempDesignSystem/Button" import Title from "@/components/TempDesignSystem/Text/Title" import { toast } from "@/components/TempDesignSystem/Toasts" +import usePhoneNumberParsing from "@/hooks/usePhoneNumberParsing" import FormContent from "./FormContent" import { type EditProfileSchema, editProfileSchema } from "./schema" @@ -47,14 +43,7 @@ export default function Form({ user }: EditFormProps) { */ const [isValid, setIsValid] = useState(true) - const { inputValue: phoneInput } = usePhoneInput({ - defaultCountry: - user.phoneNumber && isValidPhoneNumber(user.phoneNumber) - ? parsePhoneNumberWithError(user.phoneNumber).country?.toLowerCase() - : "se", - forceDialCode: true, - value: user.phoneNumber, - }) + const { phoneNumber, phoneNumberCC } = usePhoneNumberParsing(user.phoneNumber) const methods = useForm({ defaultValues: { @@ -67,7 +56,8 @@ export default function Form({ user }: EditFormProps) { dateOfBirth: user.dateOfBirth, email: user.email, language: user.language ?? langToApiLang[lang], - phoneNumber: phoneInput, + phoneNumber: phoneNumber, + phoneNumberCC: phoneNumberCC, password: "", newPassword: "", retypeNewPassword: "", diff --git a/apps/scandic-web/components/Forms/Edit/Profile/schema.ts b/apps/scandic-web/components/Forms/Edit/Profile/schema.ts index 249c0e9bc..cb377e1fd 100644 --- a/apps/scandic-web/components/Forms/Edit/Profile/schema.ts +++ b/apps/scandic-web/components/Forms/Edit/Profile/schema.ts @@ -34,6 +34,7 @@ export const editProfileSchema = z editProfileErrors.PHONE_REQUIRED, editProfileErrors.PHONE_REQUESTED ), + phoneNumberCC: z.string(), password: z.string().optional(), newPassword: z.literal("").optional().or(passwordValidator()), diff --git a/apps/scandic-web/components/Forms/Signup/index.tsx b/apps/scandic-web/components/Forms/Signup/index.tsx index 651e3a8aa..53422dded 100644 --- a/apps/scandic-web/components/Forms/Signup/index.tsx +++ b/apps/scandic-web/components/Forms/Signup/index.tsx @@ -73,6 +73,7 @@ export default function SignupForm({ title }: SignUpFormProps) { lastName: "", email: "", phoneNumber: "", + phoneNumberCC: "", dateOfBirth: "", address: { countryCode: "", diff --git a/apps/scandic-web/components/Forms/Signup/schema.ts b/apps/scandic-web/components/Forms/Signup/schema.ts index b8296861c..1225a59c2 100644 --- a/apps/scandic-web/components/Forms/Signup/schema.ts +++ b/apps/scandic-web/components/Forms/Signup/schema.ts @@ -33,6 +33,7 @@ export const signUpSchema = z.object({ signupErrors.PHONE_REQUIRED, signupErrors.PHONE_REQUESTED ), + phoneNumberCC: z.string(), dateOfBirth: z.string().min(1, { message: signupErrors.BIRTH_DATE_REQUIRED, }), 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 5562088ec..b290d6a88 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Details/Multiroom/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Details/Multiroom/index.tsx @@ -1,6 +1,5 @@ "use client" import { zodResolver } from "@hookform/resolvers/zod" -import { parsePhoneNumberFromString } from "libphonenumber-js" import { useCallback, useEffect, useMemo } from "react" import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" @@ -14,6 +13,7 @@ import Phone from "@/components/TempDesignSystem/Form/Phone" import Footnote from "@/components/TempDesignSystem/Text/Footnote" import { useFormTracking } from "@/components/TrackingSDK/hooks" import { useRoomContext } from "@/contexts/Details/Room" +import usePhoneNumberParsing from "@/hooks/usePhoneNumberParsing" import MemberPriceModal from "../MemberPriceModal" import JoinScandicFriendsCard from "./JoinScandicFriendsCard" @@ -54,14 +54,11 @@ export default function Details() { [idx, rooms] ) - const initialPhoneNumber = initialData.phoneNumber - const parsedInitialPhoneNumber = initialPhoneNumber - ? parsePhoneNumberFromString(initialPhoneNumber) - : undefined - let initialPhoneNumberCC = initialData.phoneNumberCC - if (parsedInitialPhoneNumber && !initialPhoneNumberCC) { - initialPhoneNumberCC = parsedInitialPhoneNumber.country ?? "" - } + const { phoneNumber, phoneNumberCC } = usePhoneNumberParsing( + initialData.phoneNumber, + initialData.phoneNumberCC + ) + const methods = useForm({ defaultValues: { countryCode: initialData.countryCode, @@ -70,10 +67,8 @@ export default function Details() { join: initialData.join, lastName: initialData.lastName, membershipNo: initialData.membershipNo, - phoneNumber: parsedInitialPhoneNumber?.isValid() - ? parsedInitialPhoneNumber.nationalNumber - : initialPhoneNumber, - phoneNumberCC: initialPhoneNumberCC, + phoneNumber, + phoneNumberCC, specialRequest: { comment: room.specialRequest.comment, }, 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 753180455..6944509ec 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Details/RoomOne/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Details/RoomOne/index.tsx @@ -1,6 +1,5 @@ "use client" import { zodResolver } from "@hookform/resolvers/zod" -import { parsePhoneNumberFromString } from "libphonenumber-js" import { useCallback, useEffect } from "react" import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" @@ -14,6 +13,7 @@ import Phone from "@/components/TempDesignSystem/Form/Phone" import Footnote from "@/components/TempDesignSystem/Text/Footnote" import { useFormTracking } from "@/components/TrackingSDK/hooks" import { useRoomContext } from "@/contexts/Details/Room" +import usePhoneNumberParsing from "@/hooks/usePhoneNumberParsing" import MemberPriceModal from "../MemberPriceModal" import JoinScandicFriendsCard from "./JoinScandicFriendsCard" @@ -46,14 +46,11 @@ export default function Details({ user }: DetailsProps) { const memberRate = "member" in room.roomRate ? room.roomRate.member : null - const initialPhoneNumber = user?.phoneNumber || initialData.phoneNumber - const parsedInitialPhoneNumber = initialPhoneNumber - ? parsePhoneNumberFromString(initialPhoneNumber) - : undefined - let initialPhoneNumberCC = initialData.phoneNumberCC - if (parsedInitialPhoneNumber && !initialPhoneNumberCC) { - initialPhoneNumberCC = parsedInitialPhoneNumber.country ?? "" - } + const { phoneNumber, phoneNumberCC } = usePhoneNumberParsing( + user?.phoneNumber || initialData.phoneNumber, + initialData.phoneNumberCC + ) + const methods = useForm({ defaultValues: { countryCode: user?.address?.countryCode || initialData.countryCode, @@ -64,10 +61,8 @@ export default function Details({ user }: DetailsProps) { join: initialData.join, lastName: user?.lastName || initialData.lastName, membershipNo: initialData.membershipNo, - phoneNumber: parsedInitialPhoneNumber?.isValid() - ? parsedInitialPhoneNumber.nationalNumber - : initialPhoneNumber, - phoneNumberCC: initialPhoneNumberCC, + phoneNumber, + phoneNumberCC, zipCode: "zipCode" in initialData ? initialData.zipCode : undefined, specialRequest: { comment: room.specialRequest.comment, diff --git a/apps/scandic-web/components/TempDesignSystem/Form/Input/errors.ts b/apps/scandic-web/components/TempDesignSystem/Form/Input/errors.ts index 489ee091b..54aae4b62 100644 --- a/apps/scandic-web/components/TempDesignSystem/Form/Input/errors.ts +++ b/apps/scandic-web/components/TempDesignSystem/Form/Input/errors.ts @@ -4,6 +4,7 @@ import { signupErrors } from "@/components/Forms/Signup/schema" import { multiroomErrors } from "@/components/HotelReservation/EnterDetails/Details/Multiroom/schema" import { roomOneErrors } from "@/components/HotelReservation/EnterDetails/Details/RoomOne/schema" import { findMyBookingErrors } from "@/components/HotelReservation/FindMyBooking/schema" +import { phoneErrors } from "@/utils/zod/phoneValidator" import type { IntlShape } from "react-intl" @@ -75,6 +76,11 @@ export function getErrorMessage(intl: IntlShape, errorCode?: string) { return intl.formatMessage({ defaultMessage: "Phone is required", }) + case phoneErrors.PHONE_NUMBER_TOO_SHORT: + return intl.formatMessage({ + defaultMessage: "The number you have entered is too short", + }) + case phoneErrors.PHONE_REQUESTED: case signupErrors.PHONE_REQUESTED: case multiroomErrors.PHONE_REQUESTED: case roomOneErrors.PHONE_REQUESTED: diff --git a/apps/scandic-web/components/TempDesignSystem/Form/Phone/index.tsx b/apps/scandic-web/components/TempDesignSystem/Form/Phone/index.tsx index 969458d73..ac10a241b 100644 --- a/apps/scandic-web/components/TempDesignSystem/Form/Phone/index.tsx +++ b/apps/scandic-web/components/TempDesignSystem/Form/Phone/index.tsx @@ -42,9 +42,9 @@ export default function Phone({ const lang = useLang() const { formState, getFieldState, register, setValue } = useFormContext() const fieldState = getFieldState(name) - const [phoneNumber, phoneNumberCC] = useWatch({ + const [phoneNumber, phoneNumberCC]: [string, string] = useWatch({ name: [name, countrySelectorName], - }) as [string, string] + }) const { country, setCountry } = usePhoneInput({ defaultCountry: phoneNumberCC diff --git a/apps/scandic-web/hooks/usePhoneNumberParsing.ts b/apps/scandic-web/hooks/usePhoneNumberParsing.ts new file mode 100644 index 000000000..2d2eaa566 --- /dev/null +++ b/apps/scandic-web/hooks/usePhoneNumberParsing.ts @@ -0,0 +1,23 @@ +"use client" + +import parsePhoneNumberFromString from "libphonenumber-js" + +export default function usePhoneNumberParsing( + initialPhoneNumber?: string, + initialPhoneNumberCC?: string +) { + const parsedInitialPhoneNumber = initialPhoneNumber + ? parsePhoneNumberFromString(initialPhoneNumber) + : undefined + + let phoneNumberCC = initialPhoneNumberCC + if (parsedInitialPhoneNumber && !phoneNumberCC) { + phoneNumberCC = parsedInitialPhoneNumber.country ?? "" + } + + const phoneNumber = parsedInitialPhoneNumber?.isValid() + ? parsedInitialPhoneNumber.nationalNumber + : initialPhoneNumber + + return { phoneNumber, phoneNumberCC: phoneNumberCC?.toLowerCase() } +} diff --git a/apps/scandic-web/types/components/form/phone.ts b/apps/scandic-web/types/components/form/phone.ts index 332741cb2..264cbfd49 100644 --- a/apps/scandic-web/types/components/form/phone.ts +++ b/apps/scandic-web/types/components/form/phone.ts @@ -1,4 +1,4 @@ -import type { CountryCode } from "libphonenumber-js/min" +import type { CountryCode } from "libphonenumber-js" import type { RegisterOptions } from "react-hook-form" export type LowerCaseCountryCode = Lowercase diff --git a/apps/scandic-web/utils/zod/phoneValidator.ts b/apps/scandic-web/utils/zod/phoneValidator.ts index 80e697806..60955e303 100644 --- a/apps/scandic-web/utils/zod/phoneValidator.ts +++ b/apps/scandic-web/utils/zod/phoneValidator.ts @@ -1,19 +1,24 @@ import { z } from "zod" +export const phoneErrors = { + PHONE_NUMBER_TOO_SHORT: "PHONE_NUMBER_TOO_SHORT", + PHONE_REQUESTED: "PHONE_REQUESTED", +} as const + export function phoneValidator( msg = "Required field", invalidMsg = "Invalid type" ) { return z .string({ invalid_type_error: invalidMsg, required_error: msg }) - .min(5, { message: "The number you have entered is too short" }) + .min(5, phoneErrors.PHONE_NUMBER_TOO_SHORT) .superRefine((value, ctx) => { if (value) { const containsAlphabeticChars = /[a-z]/gi.test(value) if (containsAlphabeticChars) { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: "Please enter a valid phone number", + message: phoneErrors.PHONE_REQUESTED, }) } }