Skip to content

Commit

Permalink
Merge pull request #85 from trinhthinh388/master
Browse files Browse the repository at this point in the history
fix: usePhoneInput result not in national format (#84)
  • Loading branch information
trinhthinh388 authored Mar 5, 2024
2 parents e65bbd8 + 8f6ea12 commit 1058df3
Show file tree
Hide file tree
Showing 11 changed files with 317 additions and 29 deletions.
2 changes: 1 addition & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"clean": "rimraf .turbo && rimraf node_modules && rimraf .next"
},
"dependencies": {
"@react-awesome/components": "1.0.14",
"@react-awesome/components": "1.0.15",
"classnames": "^2.5.1",
"lodash": "^4.17.21",
"lucide-react": "^0.315.0",
Expand Down
173 changes: 165 additions & 8 deletions apps/docs/src/pages/docs/phone-input/use-phone-input.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ npm i @react-awesome/phone-input
import { useState } from 'react'
import { Container } from '../../../components/Container'
import { usePhoneInput } from '@react-awesome/components'
import { Callout } from 'nextra/components'

export const Example = () => {
const [value, setValue] = useState({
Expand Down Expand Up @@ -83,13 +84,19 @@ const Example = () => {
}
```

## Local Phone Input
## Phone Input With National Format

By default **usePhoneInput** has `mode` is set to `international`.

When `mode` is `international` the value will be formatted as `e164`.

When `mode` is `national` the country code and the `+` sign will be ignored. Value is formatted as national format of the current selected country which provided via `country` property.
When `mode` is `national` the country code and the `+` sign will be ignored. Value is formatted as national format of the current selected country.

<Callout type="info" emoji="ℹ️">
Even though the phone number is formatted follow the current selected country
but phone input also automatically change the country when user paste a value
include a different country code.
</Callout>

export const LocalExample = () => {
const [value, setValue] = useState({
Expand All @@ -101,21 +108,23 @@ export const LocalExample = () => {
formattedValue: '',
isSupported: true,
});
const { register } = usePhoneInput({
const { register, phoneCode } = usePhoneInput({
onChange: (_, m) => {
setValue(m);
},
mode: 'local',
country: value.country
mode: 'national',
defaultCountry: 'VN'
});

return (

<div>
<div className="relative">
<div className="absolute left-2 top-1/2 -translate-y-1/2 z-10">+84</div>
<div className="absolute left-2 top-1/2 -translate-y-1/2 z-10">
+{phoneCode}
</div>
<input
className="w-full border rounded-md pl-10 pr-3 py-2"
className="w-full border rounded-md pl-12 pr-3 py-2"
placeholder="I am a local phone input"
{...register('use-phone-input')}
/>
Expand Down Expand Up @@ -149,7 +158,6 @@ import { usePhoneInput } from '@react-awesome/phone-input'
const Example = () => {
const { register } = usePhoneInput({
mode: 'national',
country: 'VN',
})

return (
Expand All @@ -161,6 +169,155 @@ const Example = () => {
}
```

## Phone Input With Fixed Country

**usePhoneInput** also accepts `country` prop.

When `country` is provided then the enterred value is formatted based on the provided country code and the country detection behaviour will be disabled.

export const FixedCountryExample = () => {
const [value, setValue] = useState({
isPossible: false,
isValid: false,
e164Value: '',
country: 'VN',
phoneCode: '84',
formattedValue: '',
isSupported: true,
});
const { register, phoneCode } = usePhoneInput({
onChange: (_, m) => {
setValue(m);
},
country: 'VN',
defaultCountry: 'VN'
});

return (

<div>
<div className="relative">
<input
className="w-full border rounded-md pl-3 pr-3 py-2"
placeholder="I only accept Vietnamese phone number"
{...register('use-phone-input')}
/>
</div>
<h3 className="mt-3 font-bold text-xl underline underline-offset-4">
onChange event
</h3>
<ul className="mt-2">
{Object.keys(value).map((key) => {
const v = value[key]
return (
<li key={key}>
<span className="font-medium">👉 {key}</span>
<code className="ml-2 nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10">
{v.toString()}
</code>
</li>
)
})}
</ul>
</div>
); };

<Container>
<FixedCountryExample />
</Container>

```jsx
import { usePhoneInput } from '@react-awesome/phone-input'

const Example = () => {
const { register } = usePhoneInput({
country: 'VN',
})

return (
<input
placeholder="I am a fixed country phone input"
{...register('use-phone-input')}
/>
)
}
```

`country` can also work with national format.

export const FixedCountryWithNationalExample = () => {
const [value, setValue] = useState({
isPossible: false,
isValid: false,
e164Value: '',
country: 'VN',
phoneCode: '84',
formattedValue: '',
isSupported: true,
});
const { register, phoneCode } = usePhoneInput({
onChange: (_, m) => {
setValue(m);
},
country: 'VN',
defaultCountry: 'VN',
mode: 'national'
});

return (

<div>
<div className="relative">
<div className="absolute left-2 top-1/2 -translate-y-1/2 z-10">
+{phoneCode}
</div>
<input
className="w-full border rounded-md pl-12 pr-3 py-2"
placeholder="I only accept Vietnamese phone number with national format"
{...register('use-phone-input')}
/>
</div>
<h3 className="mt-3 font-bold text-xl underline underline-offset-4">
onChange event
</h3>
<ul className="mt-2">
{Object.keys(value).map((key) => {
const v = value[key]
return (
<li key={key}>
<span className="font-medium">👉 {key}</span>
<code className="ml-2 nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10">
{v.toString()}
</code>
</li>
)
})}
</ul>
</div>
); };

<Container>
<FixedCountryWithNationalExample />
</Container>

```jsx
import { usePhoneInput } from '@react-awesome/phone-input'

const Example = () => {
const { register } = usePhoneInput({
country: 'VN',
mode: 'national',
})

return (
<input
placeholder="I only accept Vietnamese phone number with national format"
{...register('use-phone-input')}
/>
)
}
```

## Parameters

The `usePhoneInput` takes the following parameters:
Expand Down
7 changes: 7 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @react-awesome/components

## 1.0.15

### Patch Changes

- Updated dependencies
- @react-awesome/phone-input@1.1.3

## 1.0.14

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@react-awesome/components",
"version": "1.0.14",
"version": "1.0.15",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down Expand Up @@ -39,7 +39,7 @@
"access": "public"
},
"dependencies": {
"@react-awesome/phone-input": "1.1.2",
"@react-awesome/phone-input": "1.1.3",
"@react-awesome/use-click-outside": "0.0.3",
"@react-awesome/use-preserve-input-caret-position": "0.0.3",
"@react-awesome/use-selection-range": "0.0.3",
Expand Down
6 changes: 6 additions & 0 deletions packages/phone-input/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @react-awesome/phone-input

## 1.1.3

### Patch Changes

- Fix phone number is not in national format

## 1.1.2

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/phone-input/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@react-awesome/phone-input",
"version": "1.1.2",
"version": "1.1.3",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { formatWithFixedCountry } from './formatWithFixedCountry'

describe('formatWithFixedCountry', () => {
it('Should leave as-is when the value is already has valid country code.', () => {
expect(formatWithFixedCountry('+123456', 'US')).toBe('+123456')
})

it('Should format to the correct country code.', () => {
expect(formatWithFixedCountry('+123456', 'VN')).toBe('+84123456')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
CountryCode,
getCountryCallingCode,
parseIncompletePhoneNumber,
} from 'libphonenumber-js'

export const formatWithFixedCountry = (
phoneValue: string,
country: CountryCode,
) => {
if (!phoneValue) return ''

const prefix = `+${getCountryCallingCode(country)}`

if (phoneValue.startsWith(prefix))
return parseIncompletePhoneNumber(phoneValue)

if (phoneValue.startsWith('+'))
return `${prefix}${parseIncompletePhoneNumber(phoneValue.replace(/\+/g, ''))}`

if (phoneValue.startsWith('0'))
return `${prefix}${parseIncompletePhoneNumber(phoneValue.slice(1))}`

return `${prefix}${parseIncompletePhoneNumber(phoneValue)}`
}
1 change: 1 addition & 0 deletions packages/phone-input/src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './formatInternational/formatInternational'
export * from './getPossibleCountriesByCallingCode/getPossibleCountriesByCallingCode'
export * from './checkCountryValidity/checkCountryValidity'
export * from './formatNational/formatNational'
export * from './formatWithFixedCountry/formatWithFixedCountry'
4 changes: 3 additions & 1 deletion packages/phone-input/src/hooks/usePhoneInput.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ describe('usePhoneInput', () => {

it('Should only trigger change event when value is actually changed', async () => {
const onChange = vitest.fn()
const { container } = render(<Comp country="VN" onChange={onChange} />)
const { container } = render(
<Comp defaultCountry="VN" onChange={onChange} />,
)
const input = container.querySelector('input')

if (!input) {
Expand Down
Loading

0 comments on commit 1058df3

Please sign in to comment.