Merged in fix/phone-country-code-fix (pull request #2357)

fix: remove country code from prefilled phone input

Approved-by: Simon.Emanuelsson
This commit is contained in:
Christian Andolf
2025-06-13 11:01:40 +00:00
11 changed files with 62 additions and 45 deletions

View File

@@ -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<EditProfileSchema>({
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: "",

View File

@@ -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()),

View File

@@ -73,6 +73,7 @@ export default function SignupForm({ title }: SignUpFormProps) {
lastName: "",
email: "",
phoneNumber: "",
phoneNumberCC: "",
dateOfBirth: "",
address: {
countryCode: "",

View File

@@ -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,
}),

View File

@@ -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,
},

View File

@@ -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,

View File

@@ -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:

View File

@@ -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

View File

@@ -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() }
}

View File

@@ -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<CountryCode>

View File

@@ -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,
})
}
}