Skip to content

Commit

Permalink
fix(PhoneNumber): keep selected countryCode value on blur (#2869)
Browse files Browse the repository at this point in the history
The change: When the user changes the countryCode value – without making
a "selection" – and then the input blurs, it will show the current
selected value. This way, it will not be possible to "clear" a country
code or add a custom.

But that also requires us to deliver all possible available codes. The
error rate will be way lower for sure. Now, its more like a Dropdown,
but with fee text search ability.

Here's [a
demo](https://eufemia-git-feat-phone-number-keep-value-eufemia.vercel.app/uilib/extensions/forms/feature-fields/PhoneNumber/demos/).
  • Loading branch information
tujoworker authored Nov 13, 2023
1 parent de55ca8 commit 7e0f9c5
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ function PhoneNumber(props: Props) {
className,
countryCodeFieldClassName,
numberFieldClassName,
layout = 'vertical',
countryCodePlaceholder,
placeholder,
countryCodeLabel,
Expand All @@ -61,6 +60,10 @@ function PhoneNumber(props: Props) {
disabled,
width = 'large',
help,
required,
validateInitially,
continuousValidation,
validateUnchanged,
handleFocus,
handleBlur,
handleChange,
Expand All @@ -73,16 +76,11 @@ function PhoneNumber(props: Props) {
? value.match(/^(\+[^ ]+)? ?(.*)$/)
: [undefined, '', '']

const getCountryData = ({ filter = null } = {}) => {
const lang = sharedContext.locale?.split('-')[0]
return countries
.filter(({ cdc }) => !filter || `+${cdc}` === filter)
.sort(({ i18n: a }, { i18n: b }) => (a[lang] > b[lang] ? 1 : -1))
.map((country) => makeObject(country, lang))
}

const singleCountryCodeData = useMemo(() => {
return getCountryData({ filter: countryCode })
return getCountryData({
lang: sharedContext.locale?.split('-')[0],
filter: countryCode,
})
}, [])

const handleCountryCodeChange = useCallback(
Expand Down Expand Up @@ -118,7 +116,9 @@ function PhoneNumber(props: Props) {
const onFocusHandler = ({ dataList, updateData }) => {
// because there can be more than one country with same cdc
if (dataList.length < 10) {
updateData(getCountryData())
updateData(
getCountryData({ lang: sharedContext.locale?.split('-')[0] })
)
}
handleFocus()
}
Expand All @@ -139,12 +139,11 @@ function PhoneNumber(props: Props) {
countryCodeFieldClassName
)}
placeholder={countryCodePlaceholder ?? ' '}
label_direction={layout}
label_direction="vertical"
label={
countryCodeLabel ??
sharedContext?.translation.Forms.countryCodeLabel
}
mode="async"
data={singleCountryCodeData}
value={countryCode}
disabled={disabled}
Expand All @@ -153,6 +152,7 @@ function PhoneNumber(props: Props) {
on_change={handleCountryCodeChange}
independent_width
search_numbers
keep_value_and_selection
no_animation={props.noAnimation}
stretch={width === 'stretch'}
/>
Expand Down Expand Up @@ -192,6 +192,10 @@ function PhoneNumber(props: Props) {
disabled={disabled}
width="stretch"
help={help}
required={required}
validateInitially={validateInitially}
continuousValidation={continuousValidation}
validateUnchanged={validateUnchanged}
/>
</Flex.Horizontal>
</FieldBlock>
Expand All @@ -214,5 +218,12 @@ function makeObject(country: CountryType, lang: string) {
}
}

function getCountryData({ lang = 'en', filter = null } = {}) {
return countries
.filter(({ cdc }) => !filter || `+${cdc}` === filter)
.sort(({ i18n: a }, { i18n: b }) => (a[lang] > b[lang] ? 1 : -1))
.map((country) => makeObject(country, lang))
}

PhoneNumber._supportsSpacingProps = true
export default PhoneNumber
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,21 @@ describe('Field.PhoneNumber', () => {
expect(codeElement.value).toEqual('NO (+47)')

// open
fireEvent.focus(codeElement)
fireEvent.keyDown(codeElement, {
key: 'ArrowDown',
keyCode: 40,
key: 'Enter',
keyCode: 13,
})

expect(
document.querySelector('li.dnb-drawer-list__option--selected')
.textContent
).toBe('+47 Norge')

await userEvent.type(codeElement, '{Backspace}')

expect(codeElement.value).toEqual('NO (+47')

expect(
document.querySelectorAll('li.dnb-drawer-list__option')[0]
.textContent
Expand Down Expand Up @@ -168,4 +178,24 @@ describe('Field.PhoneNumber', () => {
'dnb-forms-field-block--width-large',
])
})

it('should require one number', async () => {
render(<PhoneNumber required />)

const inputElement = document.querySelector(
'.dnb-forms-field-phone-number__number input'
) as HTMLInputElement

await userEvent.type(inputElement, '1{Backspace}')
fireEvent.blur(inputElement)

expect(document.querySelector('[role="alert"]')).toBeInTheDocument()

await userEvent.type(inputElement, '1')
fireEvent.blur(inputElement)

expect(
document.querySelector('[role="alert"]')
).not.toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Field, Form } from '../../..'

export default {
title: 'Eufemia/Forms/PhoneNumber',
}

export function PhoneNumber() {
return (
<Form.Handler onSubmit={console.log}>
<Field.PhoneNumber required validateInitially path="/phoneNumber" />
<Form.SubmitButton top />
</Form.Handler>
)
}

0 comments on commit 7e0f9c5

Please sign in to comment.