Merged in chore/SW-3145-move-phone (pull request #2549)
chore/SW-3145 Moved Phone to design system * chore/SW-3145 Moved Phone to design system * chore: SW-3145 Moved phone and removed intl direct dependency Approved-by: Anton Gunnarsson
This commit is contained in:
@@ -4,24 +4,27 @@ import { useIntl } from "react-intl"
|
||||
|
||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||
import CountrySelect from "@scandic-hotels/design-system/Form/Country"
|
||||
import Phone from "@scandic-hotels/design-system/Form/Phone"
|
||||
import { Select } from "@scandic-hotels/design-system/Select"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { getLocalizedLanguageOptions } from "@/constants/languages"
|
||||
import {
|
||||
getDefaultCountryFromLang,
|
||||
getLocalizedLanguageOptions,
|
||||
} from "@/constants/languages"
|
||||
|
||||
import DateSelect from "@/components/TempDesignSystem/Form/Date"
|
||||
import Input from "@/components/TempDesignSystem/Form/Input"
|
||||
import PasswordInput from "@/components/TempDesignSystem/Form/PasswordInput"
|
||||
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
||||
import useLang from "@/hooks/useLang"
|
||||
import { getFormattedCountryList } from "@/utils/countries"
|
||||
import { getErrorMessage } from "@/utils/getErrorMessage"
|
||||
|
||||
import { editProfileErrors } from "../schema"
|
||||
|
||||
import styles from "./formContent.module.css"
|
||||
|
||||
export default function FormContent() {
|
||||
import type { FieldErrors } from "react-hook-form"
|
||||
|
||||
export default function FormContent({ errors }: { errors: FieldErrors }) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
const languageOptions = getLocalizedLanguageOptions(lang)
|
||||
@@ -66,7 +69,8 @@ export default function FormContent() {
|
||||
countries={getFormattedCountryList(intl)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
editProfileErrors.COUNTRY_REQUIRED
|
||||
// @ts-expect-error countryCode doesn't exist schema not available
|
||||
errors?.address?.countryCode?.message?.toString()
|
||||
)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Country",
|
||||
@@ -86,6 +90,15 @@ export default function FormContent() {
|
||||
data-hj-suppress
|
||||
/>
|
||||
<Phone
|
||||
countryLabel={intl.formatMessage({
|
||||
defaultMessage: "Country code",
|
||||
})}
|
||||
countriesWithTranslatedName={getFormattedCountryList(intl)}
|
||||
defaultCountryCode={getDefaultCountryFromLang(lang)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
errors?.phoneNumber?.message?.toString()
|
||||
)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Phone number",
|
||||
})}
|
||||
|
||||
@@ -185,7 +185,7 @@ export default function Form({ user }: EditFormProps) {
|
||||
onSubmit={methods.handleSubmit(handleSubmit)}
|
||||
>
|
||||
<FormProvider {...methods}>
|
||||
<FormContent />
|
||||
<FormContent errors={methods.formState.errors} />
|
||||
</FormProvider>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { logger } from "@scandic-hotels/common/logger"
|
||||
import { Button } from "@scandic-hotels/design-system/Button"
|
||||
import Checkbox from "@scandic-hotels/design-system/Form/Checkbox"
|
||||
import CountrySelect from "@scandic-hotels/design-system/Form/Country"
|
||||
import Phone from "@scandic-hotels/design-system/Form/Phone"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
import { trpc } from "@scandic-hotels/trpc/client"
|
||||
import {
|
||||
@@ -27,7 +28,6 @@ import {
|
||||
import DateSelect from "@/components/TempDesignSystem/Form/Date"
|
||||
import Input from "@/components/TempDesignSystem/Form/Input"
|
||||
import PasswordInput from "@/components/TempDesignSystem/Form/PasswordInput"
|
||||
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import { toast } from "@/components/TempDesignSystem/Toasts"
|
||||
import { useFormTracking } from "@/components/TrackingSDK/hooks"
|
||||
@@ -98,7 +98,11 @@ export default function SignupForm({ title }: SignUpFormProps) {
|
||||
shouldFocusError: true,
|
||||
})
|
||||
|
||||
const { control, subscribe } = methods
|
||||
const {
|
||||
control,
|
||||
subscribe,
|
||||
formState: { errors },
|
||||
} = methods
|
||||
|
||||
const { trackFormSubmit } = useFormTracking("signup", subscribe, control)
|
||||
|
||||
@@ -174,7 +178,7 @@ export default function SignupForm({ title }: SignUpFormProps) {
|
||||
countries={getFormattedCountryList(intl)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
signupErrors.COUNTRY_REQUIRED
|
||||
errors.address?.countryCode?.message
|
||||
)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Country",
|
||||
@@ -192,6 +196,15 @@ export default function SignupForm({ title }: SignUpFormProps) {
|
||||
type="email"
|
||||
/>
|
||||
<Phone
|
||||
countryLabel={intl.formatMessage({
|
||||
defaultMessage: "Country code",
|
||||
})}
|
||||
countriesWithTranslatedName={getFormattedCountryList(intl)}
|
||||
defaultCountryCode={getDefaultCountryFromLang(lang)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
errors.phoneNumber?.message
|
||||
)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Phone number",
|
||||
})}
|
||||
|
||||
@@ -6,12 +6,13 @@ import { useIntl } from "react-intl"
|
||||
|
||||
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 { getDefaultCountryFromLang } from "@/constants/languages"
|
||||
import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||
|
||||
import SpecialRequests from "@/components/HotelReservation/EnterDetails/Details/SpecialRequests"
|
||||
import Input from "@/components/TempDesignSystem/Form/Input"
|
||||
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
||||
import { useFormTracking } from "@/components/TrackingSDK/hooks"
|
||||
import { useRoomContext } from "@/contexts/Details/Room"
|
||||
import useLang from "@/hooks/useLang"
|
||||
@@ -21,7 +22,7 @@ import { getErrorMessage } from "@/utils/getErrorMessage"
|
||||
|
||||
import MemberPriceModal from "../MemberPriceModal"
|
||||
import JoinScandicFriendsCard from "./JoinScandicFriendsCard"
|
||||
import { getMultiroomDetailsSchema, multiroomErrors } from "./schema"
|
||||
import { getMultiroomDetailsSchema } from "./schema"
|
||||
|
||||
import styles from "./details.module.css"
|
||||
|
||||
@@ -89,7 +90,7 @@ export default function Details() {
|
||||
trigger,
|
||||
control,
|
||||
subscribe,
|
||||
formState: { isValid },
|
||||
formState: { isValid, errors },
|
||||
setValue,
|
||||
watch,
|
||||
} = methods
|
||||
@@ -192,10 +193,7 @@ export default function Details() {
|
||||
<CountrySelect
|
||||
className={styles.fullWidth}
|
||||
countries={getFormattedCountryList(intl)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
multiroomErrors.COUNTRY_REQUIRED
|
||||
)}
|
||||
errorMessage={getErrorMessage(intl, errors.countryCode?.message)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Country",
|
||||
})}
|
||||
@@ -212,6 +210,12 @@ export default function Details() {
|
||||
registerOptions={{ required: true, onBlur: updateDetailsStore }}
|
||||
/>
|
||||
<Phone
|
||||
countryLabel={intl.formatMessage({
|
||||
defaultMessage: "Country code",
|
||||
})}
|
||||
countriesWithTranslatedName={getFormattedCountryList(intl)}
|
||||
defaultCountryCode={getDefaultCountryFromLang(lang)}
|
||||
errorMessage={getErrorMessage(intl, errors.phoneNumber?.message)}
|
||||
className={styles.fullWidth}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Phone number",
|
||||
|
||||
@@ -6,12 +6,13 @@ import { useIntl } from "react-intl"
|
||||
|
||||
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 { getDefaultCountryFromLang } from "@/constants/languages"
|
||||
import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||
|
||||
import SpecialRequests from "@/components/HotelReservation/EnterDetails/Details/SpecialRequests"
|
||||
import Input from "@/components/TempDesignSystem/Form/Input"
|
||||
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
||||
import { useFormTracking } from "@/components/TrackingSDK/hooks"
|
||||
import { useRoomContext } from "@/contexts/Details/Room"
|
||||
import useLang from "@/hooks/useLang"
|
||||
@@ -21,11 +22,7 @@ import { getErrorMessage } from "@/utils/getErrorMessage"
|
||||
|
||||
import MemberPriceModal from "../MemberPriceModal"
|
||||
import JoinScandicFriendsCard from "./JoinScandicFriendsCard"
|
||||
import {
|
||||
guestDetailsSchema,
|
||||
roomOneErrors,
|
||||
signedInDetailsSchema,
|
||||
} from "./schema"
|
||||
import { guestDetailsSchema, signedInDetailsSchema } from "./schema"
|
||||
import Signup from "./Signup"
|
||||
|
||||
import styles from "./details.module.css"
|
||||
@@ -178,7 +175,10 @@ export default function Details({ user }: DetailsProps) {
|
||||
})}
|
||||
lang={lang}
|
||||
countries={getFormattedCountryList(intl)}
|
||||
errorMessage={getErrorMessage(intl, roomOneErrors.COUNTRY_REQUIRED)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
formState.errors.countryCode?.message
|
||||
)}
|
||||
name="countryCode"
|
||||
readOnly={!!user}
|
||||
registerOptions={{ required: true, onBlur: updateDetailsStore }}
|
||||
@@ -195,6 +195,15 @@ export default function Details({ user }: DetailsProps) {
|
||||
/>
|
||||
<Phone
|
||||
className={styles.fullWidth}
|
||||
countryLabel={intl.formatMessage({
|
||||
defaultMessage: "Country code",
|
||||
})}
|
||||
countriesWithTranslatedName={getFormattedCountryList(intl)}
|
||||
defaultCountryCode={getDefaultCountryFromLang(lang)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
formState.errors.phoneNumber?.message
|
||||
)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Phone number",
|
||||
})}
|
||||
|
||||
@@ -5,10 +5,11 @@ import { useIntl } from "react-intl"
|
||||
|
||||
import Body from "@scandic-hotels/design-system/Body"
|
||||
import CountrySelect from "@scandic-hotels/design-system/Form/Country"
|
||||
import { signupErrors } from "@scandic-hotels/trpc/routers/user/schemas"
|
||||
import Phone from "@scandic-hotels/design-system/Form/Phone"
|
||||
|
||||
import { getDefaultCountryFromLang } from "@/constants/languages"
|
||||
|
||||
import Input from "@/components/TempDesignSystem/Form/Input"
|
||||
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
||||
import useLang from "@/hooks/useLang"
|
||||
import { getFormattedCountryList } from "@/utils/countries"
|
||||
import { getErrorMessage } from "@/utils/getErrorMessage"
|
||||
@@ -28,7 +29,11 @@ export default function ModifyContact({
|
||||
}: ModifyContactProps) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
const { getValues, setValue } = useFormContext()
|
||||
const {
|
||||
getValues,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useFormContext()
|
||||
|
||||
useEffect(() => {
|
||||
setValue("firstName", guest.firstName ?? "")
|
||||
@@ -65,7 +70,7 @@ export default function ModifyContact({
|
||||
countries={getFormattedCountryList(intl)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
signupErrors.COUNTRY_REQUIRED
|
||||
errors.countryCode?.message?.toString()
|
||||
)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Country",
|
||||
@@ -86,6 +91,15 @@ export default function ModifyContact({
|
||||
</div>
|
||||
<div className={styles.row}>
|
||||
<Phone
|
||||
countryLabel={intl.formatMessage({
|
||||
defaultMessage: "Country code",
|
||||
})}
|
||||
countriesWithTranslatedName={getFormattedCountryList(intl)}
|
||||
defaultCountryCode={getDefaultCountryFromLang(lang)}
|
||||
errorMessage={getErrorMessage(
|
||||
intl,
|
||||
errors.phoneNumber?.message?.toString()
|
||||
)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Phone number",
|
||||
})}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||
import { ApiLang } from "@scandic-hotels/trpc/constants/apiLang"
|
||||
|
||||
import type { LowerCaseCountryCode } from "@/types/components/form/phone"
|
||||
import type { CountryCode } from "libphonenumber-js"
|
||||
|
||||
export const languages: Record<Lang, string> = {
|
||||
[Lang.da]: "Dansk",
|
||||
@@ -82,8 +82,8 @@ export function getLocalizedLanguageOptions(currentLang: Lang) {
|
||||
})
|
||||
}
|
||||
|
||||
export function getDefaultCountryFromLang(lang: Lang): LowerCaseCountryCode {
|
||||
const countryMap: Record<Lang, LowerCaseCountryCode> = {
|
||||
export function getDefaultCountryFromLang(lang: Lang): Lowercase<CountryCode> {
|
||||
const countryMap: Record<Lang, Lowercase<CountryCode>> = {
|
||||
sv: "se",
|
||||
da: "dk",
|
||||
fi: "fi",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use client"
|
||||
import "react-international-phone/style.css"
|
||||
'use client'
|
||||
import 'react-international-phone/style.css'
|
||||
|
||||
import { useEffect, useMemo } from "react"
|
||||
import { TextField } from "react-aria-components"
|
||||
import { useFormContext, useWatch } from "react-hook-form"
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import { TextField } from 'react-aria-components'
|
||||
import { useFormContext, useWatch } from 'react-hook-form'
|
||||
import {
|
||||
buildCountryData,
|
||||
CountrySelector,
|
||||
@@ -12,53 +12,48 @@ import {
|
||||
parseCountry,
|
||||
type ParsedCountry,
|
||||
usePhoneInput,
|
||||
} from "react-international-phone"
|
||||
import { useIntl } from "react-intl"
|
||||
} from 'react-international-phone'
|
||||
|
||||
import Body from "@scandic-hotels/design-system/Body"
|
||||
import { ErrorMessage } from "@scandic-hotels/design-system/Form/ErrorMessage"
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Input } from "@scandic-hotels/design-system/Input"
|
||||
import { Label } from "@scandic-hotels/design-system/Label"
|
||||
import Body from '../../Body'
|
||||
import { ErrorMessage } from '../ErrorMessage'
|
||||
import { MaterialIcon } from '../../Icons/MaterialIcon'
|
||||
import { Input } from '../../Input'
|
||||
import { Label } from '../../Label'
|
||||
|
||||
import { getDefaultCountryFromLang } from "@/constants/languages"
|
||||
import styles from './phone.module.css'
|
||||
|
||||
import useLang from "@/hooks/useLang"
|
||||
import { getErrorMessage } from "@/utils/getErrorMessage"
|
||||
|
||||
import styles from "./phone.module.css"
|
||||
|
||||
import type { PhoneProps } from "@/types/components/form/phone"
|
||||
import type { PhoneProps } from './phone'
|
||||
|
||||
export default function Phone({
|
||||
ariaLabel = "Phone number input",
|
||||
className = "",
|
||||
countrySelectorName = "phoneNumberCC",
|
||||
ariaLabel = 'Phone number input',
|
||||
className = '',
|
||||
countryLabel = 'Country code',
|
||||
countrySelectorName = 'phoneNumberCC',
|
||||
countriesWithTranslatedName,
|
||||
defaultCountryCode,
|
||||
disabled = false,
|
||||
errorMessage,
|
||||
label,
|
||||
name = "phoneNumber",
|
||||
name = 'phoneNumber',
|
||||
placeholder,
|
||||
readOnly = false,
|
||||
registerOptions = {
|
||||
required: true,
|
||||
},
|
||||
}: PhoneProps) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
|
||||
const countries = useMemo(() => {
|
||||
return defaultCountries.map((dc) => {
|
||||
const country = parseCountry(dc)
|
||||
const translatedCountryName = intl.formatDisplayName(
|
||||
country.iso2.toUpperCase(),
|
||||
{ type: "region" }
|
||||
const parsedCountry = parseCountry(dc)
|
||||
const country = countriesWithTranslatedName?.find(
|
||||
(country) => country.code === parsedCountry.iso2.toUpperCase()
|
||||
)
|
||||
const translatedCountryName = country?.displayName ?? country?.name
|
||||
if (translatedCountryName) {
|
||||
country.name = translatedCountryName
|
||||
parsedCountry.name = translatedCountryName
|
||||
}
|
||||
return buildCountryData(country)
|
||||
return buildCountryData(parsedCountry)
|
||||
})
|
||||
}, [intl])
|
||||
}, [countriesWithTranslatedName])
|
||||
|
||||
const { formState, getFieldState, register, setValue } = useFormContext()
|
||||
const fieldState = getFieldState(name)
|
||||
@@ -69,9 +64,7 @@ export default function Phone({
|
||||
|
||||
const { country, setCountry } = usePhoneInput({
|
||||
countries,
|
||||
defaultCountry: phoneNumberCC
|
||||
? phoneNumberCC
|
||||
: getDefaultCountryFromLang(lang),
|
||||
defaultCountry: phoneNumberCC ? phoneNumberCC : defaultCountryCode,
|
||||
})
|
||||
|
||||
function handleSelectCountry(value: ParsedCountry) {
|
||||
@@ -98,7 +91,7 @@ export default function Phone({
|
||||
dropdownArrowClassName={styles.arrow}
|
||||
flagClassName={styles.flag}
|
||||
onSelect={handleSelectCountry}
|
||||
preferredCountries={["de", "dk", "fi", "no", "se", "gb"]}
|
||||
preferredCountries={['de', 'dk', 'fi', 'no', 'se', 'gb']}
|
||||
selectedCountry={country.iso2}
|
||||
renderButtonWrapper={(props) => (
|
||||
<button
|
||||
@@ -109,9 +102,7 @@ export default function Phone({
|
||||
data-testid="country-selector"
|
||||
>
|
||||
<Label required={!!registerOptions.required} size="small">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Country code",
|
||||
})}
|
||||
{countryLabel}
|
||||
</Label>
|
||||
<span className={styles.selectContainer}>
|
||||
{props.children}
|
||||
@@ -153,10 +144,7 @@ export default function Phone({
|
||||
<ErrorMessage
|
||||
errors={formState.errors}
|
||||
name={name}
|
||||
messageLabel={getErrorMessage(
|
||||
intl,
|
||||
formState.errors[name]?.message?.toString()
|
||||
)}
|
||||
messageLabel={errorMessage}
|
||||
/>
|
||||
</TextField>
|
||||
</div>
|
||||
@@ -79,7 +79,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.select[aria-expanded="true"] .chevron {
|
||||
.select[aria-expanded='true'] .chevron {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import type { CountryCode } from "libphonenumber-js"
|
||||
import type { RegisterOptions } from "react-hook-form"
|
||||
|
||||
export type LowerCaseCountryCode = Lowercase<CountryCode>
|
||||
import type { RegisterOptions } from 'react-hook-form'
|
||||
|
||||
export interface PhoneProps {
|
||||
ariaLabel?: string
|
||||
className?: string
|
||||
countryLabel?: string
|
||||
countrySelectorName?: string
|
||||
countriesWithTranslatedName: {
|
||||
code: string
|
||||
displayName?: string
|
||||
name: string
|
||||
}[]
|
||||
disabled?: boolean
|
||||
errorMessage?: string
|
||||
label: string
|
||||
defaultCountryCode: string
|
||||
name?: string
|
||||
placeholder?: string
|
||||
readOnly?: boolean
|
||||
@@ -17,6 +17,7 @@
|
||||
"./Form/Checkbox": "./dist/components/Form/Checkbox/index.js",
|
||||
"./Form/Country": "./dist/components/Form/Country/index.js",
|
||||
"./Form/ErrorMessage": "./dist/components/Form/ErrorMessage/index.js",
|
||||
"./Form/Phone": "./dist/components/Form/Phone/index.js",
|
||||
"./Form/RadioCard": "./dist/components/Form/RadioCard/index.js",
|
||||
"./Input": "./dist/components/Input/index.js",
|
||||
"./Label": "./dist/components/Label/index.js",
|
||||
@@ -152,7 +153,8 @@
|
||||
"react": "^19.1.0",
|
||||
"react-aria-components": "^1.8.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-hook-form": "^7.56.2"
|
||||
"react-hook-form": "^7.56.2",
|
||||
"react-international-phone": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
|
||||
Reference in New Issue
Block a user