Skip to content

Commit

Permalink
fix: numbers with specials chars (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorisre authored Mar 17, 2022
1 parent 80678af commit 61ca818
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dist
dist-ssr
*.local
.history
coverage

# Editor directories and files
.vscode/*
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"@typescript-eslint/eslint-plugin": "^5.15.0",
"@typescript-eslint/parser": "^5.15.0",
"@vitejs/plugin-react": "^1.0.7",
"c8": "^7.11.0",
"eslint": "^8.10.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-react": "^7.29.3",
Expand Down
35 changes: 35 additions & 0 deletions src/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,38 @@ test('should empty the field', async () => {

expect(screen.getByPlaceholderText('3 33 33 33 33')).toBeEmptyDOMElement();
});

test('should empty the field with phone number that contains `-` or `()`', async () => {
const handleChange = vi.fn<[React.ChangeEvent<HTMLInputElement>], void>();
const placeholder = '(33) 33-33-33';

render(
<Phone onChange={handleChange} defaultCountry="md">
<Phone.Country />
<Phone.Number placeholder={placeholder} />
</Phone>
);

expect(handleChange).not.toHaveBeenCalled();

user.type(screen.getByPlaceholderText(placeholder), '334455667');
user.type(screen.getByPlaceholderText(placeholder), '{Backspace}');
user.type(screen.getByPlaceholderText(placeholder), '{Backspace}');
user.type(screen.getByPlaceholderText(placeholder), '{Backspace}');

expect(screen.getByPlaceholderText(placeholder)).toHaveValue('(33) 44-5');

user.type(screen.getByPlaceholderText(placeholder), '{Backspace}');
user.type(screen.getByPlaceholderText(placeholder), '{Backspace}');

expect(screen.getByPlaceholderText(placeholder)).toHaveValue('(33) 4');

user.type(screen.getByPlaceholderText(placeholder), '{Backspace}');

expect(screen.getByPlaceholderText(placeholder)).toHaveValue('(33');

user.type(screen.getByPlaceholderText(placeholder), '{Backspace}');
user.type(screen.getByPlaceholderText(placeholder), '{Backspace}');

expect(screen.getByPlaceholderText(placeholder)).toBeEmptyDOMElement();
});
17 changes: 8 additions & 9 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ export const _Phone = forwardRef<HTMLInputElement, PhoneProps>(
({ className, style, children, defaultCountry, value, ...props }, ref) => {
const _ref = useRef<HTMLInputElement | null>(null);
const _defaultValue = props.defaultValue || value;
const defaultPhoneNumber = _defaultValue
? splitPhoneNumber(_defaultValue)
: defaultCountry
? {
raw: '',
formatted: '',
country: getCountryByIso(defaultCountry),
}
: DEFAULT_PHONE_NUMBER;
const defaultPhoneNumber =
(_defaultValue
? splitPhoneNumber(_defaultValue)
: defaultCountry && {
raw: '',
formatted: '',
country: getCountryByIso(defaultCountry),
}) || DEFAULT_PHONE_NUMBER;

const [_value, setValue] = useState<PhoneNumber>(defaultPhoneNumber);

Expand Down
13 changes: 12 additions & 1 deletion src/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from './utils';

import countries from './countries';
import { vi } from 'vitest';

describe('isE164Compliant', () => {
const fakeNumber = ('' + Date.now()).substring(0, 11);
Expand Down Expand Up @@ -100,6 +101,16 @@ describe('splitPhoneNumber', () => {
},
],
])('unpackRawPhone(%s)', (p, e) => expect(splitPhoneNumber(p)).toEqual(e));

test('should return undefined and log an error', () => {
const log = vi.spyOn(console, 'log');

expect(splitPhoneNumber('fake')).toBeUndefined();
expect(log).toHaveBeenCalledTimes(1);
expect(log.mock.calls[0][0]).toMatchInlineSnapshot(
'"[react-telephone] phone number should follow E.164"'
);
});
});

test.each([
Expand All @@ -123,7 +134,7 @@ test.each([
['12 34', '.. ..', '12 34'],
['123456', '.. ...', '12 345'], // Ignore excess digits
['123456', '.... ....', '1234 56'], // Fill as much as possible
['123456', '.... ..-..', '1234 56-'], // Stop at first missing digit
['123456', '.... ..-..', '1234 56'], // Stop at first missing digit
['123456', '.... ....-..', '1234 56'], // Stop at first missing digit
['6 12 34 56 78', '. .. .. .. ..', '6 12 34 56 78'],
['+33234567890', undefined, '+33234567890'],
Expand Down
10 changes: 6 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const removeMask = (value: string) => value.replace(/\D/g, '');
export const applyMask = (value = '', mask?: string) => {
if (!mask || !value) return value;
const flatValue = removeMask(value).split('');
return mask.replace(/\./g, () => flatValue.shift() || '.').split('.')[0].trim();
return /^.*\d/.exec(mask.replace(/\./g, () => flatValue.shift() || ''))?.[0] || '';
};

export const isE164Compliant = (value: string) =>
Expand All @@ -22,9 +22,11 @@ export interface PhoneNumber {
country: Country;
}

export const splitPhoneNumber = (value: string): PhoneNumber => {
if (!isE164Compliant(value))
throw new Error('[react-telephone] phone number should follow E.164');
export const splitPhoneNumber = (value: string): PhoneNumber | undefined => {
if (!isE164Compliant(value)) {
console.log('[react-telephone] phone number should follow E.164');
return;
}

const dial = removeMask(value).substring(0, 6);

Expand Down
Loading

0 comments on commit 61ca818

Please sign in to comment.