bl00mber / react-phone-input-2

:telephone_receiver: Highly customizable phone input component with auto formatting
https://bl00mber.github.io/react-phone-input-2.html
MIT License
932 stars 529 forks source link

Validate Phone number #204

Open ajagadees opened 4 years ago

ajagadees commented 4 years ago

There is no validation for mobile number for specific countries. Example India has 10digits without dial code and if it user inputs less than this how to validate ? Even we tried to use 'isValid' seems not reflects the validation.

bl00mber commented 4 years ago

While I do not completely understand your problem, I think I can pass country object to validation callback in the future. Will it solve your issue?

hardy12994 commented 4 years ago

I think their should be onCountryChange function in your module, on that if anyone change the country from selector or write it down by own, it should be given respective regex of that country and after that you can check validity. That the written value is falling in given regex or not. Just a suggestion @bl00mber, b'coz i am also facing the same issue. I think could help many others.

In case if you need regex of all countries -

const phones = {
  'am-AM': /^(\+?374|0)((10|[9|7][0-9])\d{6}$|[2-4]\d{7}$)/,
  'ar-AE': /^((\+?971)|0)?5[024568]\d{7}$/,
  'ar-BH': /^(\+?973)?(3|6)\d{7}$/,
  'ar-DZ': /^(\+?213|0)(5|6|7)\d{8}$/,
  'ar-EG': /^((\+?20)|0)?1[0125]\d{8}$/,
  'ar-IQ': /^(\+?964|0)?7[0-9]\d{8}$/,
  'ar-JO': /^(\+?962|0)?7[789]\d{7}$/,
  'ar-KW': /^(\+?965)[569]\d{7}$/,
  'ar-SA': /^(!?(\+?966)|0)?5\d{8}$/,
  'ar-SY': /^(!?(\+?963)|0)?9\d{8}$/,
  'ar-TN': /^(\+?216)?[2459]\d{7}$/,
  'be-BY': /^(\+?375)?(24|25|29|33|44)\d{7}$/,
  'bg-BG': /^(\+?359|0)?8[789]\d{7}$/,
  'bn-BD': /^(\+?880|0)1[13456789][0-9]{8}$/,
  'cs-CZ': /^(\+?420)? ?[1-9][0-9]{2} ?[0-9]{3} ?[0-9]{3}$/,
  'da-DK': /^(\+?45)?\s?\d{2}\s?\d{2}\s?\d{2}\s?\d{2}$/,
  'de-DE': /^(\+49)?0?1(5[0-25-9]\d|6([23]|0\d?)|7([0-57-9]|6\d))\d{7}$/,
  'de-AT': /^(\+43|0)\d{1,4}\d{3,12}$/,
  'el-GR': /^(\+?30|0)?(69\d{8})$/,
  'en-AU': /^(\+?61|0)4\d{8}$/,
  'en-GB': /^(\+?44|0)7\d{9}$/,
  'en-GG': /^(\+?44|0)1481\d{6}$/,
  'en-GH': /^(\+233|0)(20|50|24|54|27|57|26|56|23|28)\d{7}$/,
  'en-HK': /^(\+?852[-\s]?)?[456789]\d{3}[-\s]?\d{4}$/,
  'en-MO': /^(\+?853[-\s]?)?[6]\d{3}[-\s]?\d{4}$/,
  'en-IE': /^(\+?353|0)8[356789]\d{7}$/,
  'en-IN': /^(\+?91|0)?[6789]\d{9}$/,
  'en-KE': /^(\+?254|0)(7|1)\d{8}$/,
  'en-MT': /^(\+?356|0)?(99|79|77|21|27|22|25)[0-9]{6}$/,
  'en-MU': /^(\+?230|0)?\d{8}$/,
  'en-NG': /^(\+?234|0)?[789]\d{9}$/,
  'en-NZ': /^(\+?64|0)[28]\d{7,9}$/,
  'en-PK': /^((\+92)|(0092))-{0,1}\d{3}-{0,1}\d{7}$|^\d{11}$|^\d{4}-\d{7}$/,
  'en-RW': /^(\+?250|0)?[7]\d{8}$/,
  'en-SG': /^(\+65)?[89]\d{7}$/,
  'en-SL': /^(?:0|94|\+94)?(7(0|1|2|5|6|7|8)( |-)?\d)\d{6}$/,
  'en-TZ': /^(\+?255|0)?[67]\d{8}$/,
  'en-UG': /^(\+?256|0)?[7]\d{8}$/,
  'en-US': /^((\+1|1)?( |-)?)?(\([2-9][0-9]{2}\)|[2-9][0-9]{2})( |-)?([2-9][0-9]{2}( |-)?[0-9]{4})$/,
  'en-ZA': /^(\+?27|0)\d{9}$/,
  'en-ZM': /^(\+?26)?09[567]\d{7}$/,
  'es-CL': /^(\+?56|0)[2-9]\d{1}\d{7}$/,
  'es-EC': /^(\+?593|0)([2-7]|9[2-9])\d{7}$/,
  'es-ES': /^(\+?34)?(6\d{1}|7[1234])\d{7}$/,
  'es-MX': /^(\+?52)?(1|01)?\d{10,11}$/,
  'es-PA': /^(\+?507)\d{7,8}$/,
  'es-PY': /^(\+?595|0)9[9876]\d{7}$/,
  'es-UY': /^(\+598|0)9[1-9][\d]{6}$/,
  'et-EE': /^(\+?372)?\s?(5|8[1-4])\s?([0-9]\s?){6,7}$/,
  'fa-IR': /^(\+?98[\-\s]?|0)9[0-39]\d[\-\s]?\d{3}[\-\s]?\d{4}$/,
  'fi-FI': /^(\+?358|0)\s?(4(0|1|2|4|5|6)?|50)\s?(\d\s?){4,8}\d$/,
  'fj-FJ': /^(\+?679)?\s?\d{3}\s?\d{4}$/,
  'fo-FO': /^(\+?298)?\s?\d{2}\s?\d{2}\s?\d{2}$/,
  'fr-FR': /^(\+?33|0)[67]\d{8}$/,
  'fr-GF': /^(\+?594|0|00594)[67]\d{8}$/,
  'fr-GP': /^(\+?590|0|00590)[67]\d{8}$/,
  'fr-MQ': /^(\+?596|0|00596)[67]\d{8}$/,
  'fr-RE': /^(\+?262|0|00262)[67]\d{8}$/,
  'he-IL': /^(\+972|0)([23489]|5[012345689]|77)[1-9]\d{6}$/,
  'hu-HU': /^(\+?36)(20|30|70)\d{7}$/,
  'id-ID': /^(\+?62|0)8(1[123456789]|2[1238]|3[1238]|5[12356789]|7[78]|9[56789]|8[123456789])([\s?|\d]{5,11})$/,
  'it-IT': /^(\+?39)?\s?3\d{2} ?\d{6,7}$/,
  'ja-JP': /^(\+81[ \-]?(\(0\))?|0)[6789]0[ \-]?\d{4}[ \-]?\d{4}$/,
  'kk-KZ': /^(\+?7|8)?7\d{9}$/,
  'kl-GL': /^(\+?299)?\s?\d{2}\s?\d{2}\s?\d{2}$/,
  'ko-KR': /^((\+?82)[ \-]?)?0?1([0|1|6|7|8|9]{1})[ \-]?\d{3,4}[ \-]?\d{4}$/,
  'lt-LT': /^(\+370|8)\d{8}$/,
  'ms-MY': /^(\+?6?01){1}(([0145]{1}(\-|\s)?\d{7,8})|([236789]{1}(\s|\-)?\d{7}))$/,
  'nb-NO': /^(\+?47)?[49]\d{7}$/,
  'ne-NP': /^(\+?977)?9[78]\d{8}$/,
  'nl-BE': /^(\+?32|0)4?\d{8}$/,
  'nl-NL': /^(\+?31|0)6?\d{8}$/,
  'nn-NO': /^(\+?47)?[49]\d{7}$/,
  'pl-PL': /^(\+?48)? ?[5-8]\d ?\d{3} ?\d{2} ?\d{2}$/,
  'pt-BR': /(?=^(\+?5{2}\-?|0)[1-9]{2}\-?\d{4}\-?\d{4}$)(^(\+?5{2}\-?|0)[1-9]{2}\-?[6-9]{1}\d{3}\-?\d{4}$)|(^(\+?5{2}\-?|0)[1-9]{2}\-?9[6-9]{1}\d{3}\-?\d{4}$)/,
  'pt-PT': /^(\+?351)?9[1236]\d{7}$/,
  'ro-RO': /^(\+?4?0)\s?7\d{2}(\/|\s|\.|\-)?\d{3}(\s|\.|\-)?\d{3}$/,
  'ru-RU': /^(\+?7|8)?9\d{9}$/,
  'sl-SI': /^(\+386\s?|0)(\d{1}\s?\d{3}\s?\d{2}\s?\d{2}|\d{2}\s?\d{3}\s?\d{3})$/,
  'sk-SK': /^(\+?421)? ?[1-9][0-9]{2} ?[0-9]{3} ?[0-9]{3}$/,
  'sr-RS': /^(\+3816|06)[- \d]{5,9}$/,
  'sv-SE': /^(\+?46|0)[\s\-]?7[\s\-]?[02369]([\s\-]?\d){7}$/,
  'th-TH': /^(\+66|66|0)\d{9}$/,
  'tr-TR': /^(\+?90|0)?5\d{9}$/,
  'uk-UA': /^(\+?38|8)?0\d{9}$/,
  'vi-VN': /^(\+?84|0)((3([2-9]))|(5([2689]))|(7([0|6-9]))|(8([1-6|89]))|(9([0-9])))([0-9]{7})$/,
  'zh-CN': /^((\+|00)86)?1([358][0-9]|4[579]|6[67]|7[01235678]|9[189])[0-9]{8}$/,
  'zh-TW': /^(\+?886\-?|0)?9\d{8}$/,
};
ajagadees commented 4 years ago

While I do not completely understand your problem, I think I can pass country object to validation callback in the future. Will it solve your issue?

Thanks your kind reply, Im looking the number length validation. Example in India phone number length is 10 digit like wise.

Bouftini1992 commented 4 years ago

Hi @ajagadees, I am facing the same problem, so I am wondering how to validate phone numbers and how to handle the msg errors. Did you find a solution ? Thank you in advance

ArnasSalokas commented 4 years ago

Hey, facing the same issue. Is there a way to validate lengths of each country code? P.S huge thanks for the module, it's really awesome

bl00mber commented 4 years ago

Can anyone publish regex from @hardy12994's or other list where iso2 country codes from this library used as keys?

bl00mber commented 4 years ago

I've never used validation I added some validation mechanics in the 90959fabe9ed08f0b3eac6e7e243ccd83ef0df8c If you have any suggestions - code blocks or PRs are welcomed. If linked commit fixes your validation problems, feedback would be good to see.

codemewell commented 3 years ago

For countries validation check this repository: https://github.com/Bunlong/libphonenumbers ( js port of Google's libphonenumber)

Troy-Yang commented 3 years ago

@bl00mber I tried pass isValid prop as function to do validation, and the callback function will change state, however, I think it's kind of tricky.

I found I can use onChange event to do the validation, thanks to pass the country config in this event. In this event, I use the country format to do a simple validation:

const validNumberCount = (selectedCountry.format.match(/\./g) || []).length;
    this.setState({
      phoneNumberError: formattedNumber.length !== validNumberCount
    });
sbaz44 commented 2 years ago

I validated my number by saving the length of dots that I get in my onChange method.

<PhoneInputBox id="mobile" onChange={(value, country, e) => { setMobileNoLength( country.format.split(".").length - 1); setMobile(value); }} onBlur={(e, country) => { let _length = country.format.split(".").length - 1; if (Mobile.length !== _length) { let _error = { ...errors }; _error.isMobileEmpty = true; setErrors({ ..._error }); } }} value={Mobile} />

and while submitting, I validated my data like this

if (Mobile === "" || Mobile.length !== MobileNoLength){ //error handling }

yasharma2301 commented 2 years ago

In my use case, I am using yup for form validation in conjunction with react-phone-input-2. This is how my schema looks like:

const formSchema= yup.object({
  name: yup.string().required('Name is a required field'),
  phone: yup
    .string()
    .required('Phone is a required field')
    .test('Check Indian Number', function () {
      let contact = this.parent['phone'];
      const indianRegex = new RegExp('^[6-9][0-9]{9}$');

      if (contact && contact.startsWith('91')) {
        let contactWithoutCountryCode = contact.substring(2, contact.length);
        return indianRegex.test(contactWithoutCountryCode);
      }
      return true;
    }),
  profile: yup.string().required('Profile is a required field'),
  whatsAppUpdates: yup.boolean().required(),
});

Current implementation only supports Indian phone numbers, but you can always make the validation dynamic using above mentioned regex codes.

Dupflo commented 1 year ago

Using @hardy12994 phones values, I rewrite the object to fit an array with some complementary information about the countries.

export const PHONE_COUNTRIES = [ { locale: 'am-AM', iso2: 'AM', validation: /^(\+?374|0)((10|[9|7][0-9])\d{6}$|[2-4]\d{7}$)/ }, { locale: 'ar-AE', iso2: 'AE', validation: /^((\+?971)|0)?5[024568]\d{7}$/ }, { locale: 'ar-BH', iso2: 'BH', validation: /^(\+?973)?(3|6)\d{7}$/ }, { locale: 'ar-DZ', iso2: 'DZ', validation: /^(\+?213|0)(5|6|7)\d{8}$/ }, { locale: 'ar-EG', iso2: 'EG', validation: /^((\+?20)|0)?1[0125]\d{8}$/ }, { locale: 'ar-IQ', iso2: 'IQ', validation: /^(\+?964|0)?7[0-9]\d{8}$/ }, { locale: 'ar-JO', iso2: 'JO', validation: /^(\+?962|0)?7[789]\d{7}$/ }, { locale: 'ar-KW', iso2: 'KW', validation: /^(\+?965)[569]\d{7}$/ }, { locale: 'ar-SA', iso2: 'SA', validation: /^(!?(\+?966)|0)?5\d{8}$/ }, { locale: 'ar-SY', iso2: 'SY', validation: /^(!?(\+?963)|0)?9\d{8}$/ }, { locale: 'ar-TN', iso2: 'TN', validation: /^(\+?216)?[2459]\d{7}$/ }, { locale: 'be-BY', iso2: 'BY', validation: /^(\+?375)?(24|25|29|33|44)\d{7}$/ }, { locale: 'bg-BG', iso2: 'BG', validation: /^(\+?359|0)?8[789]\d{7}$/ }, { locale: 'bn-BD', iso2: 'BD', validation: /^(\+?880|0)1[13456789][0-9]{8}$/ }, { locale: 'cs-CZ', iso2: 'CZ', validation: /^(\+?420)? ?[1-9][0-9]{2} ?[0-9]{3} ?[0-9]{3}$/ }, { locale: 'da-DK', iso2: 'DK', validation: /^(\+?45)?\s?\d{2}\s?\d{2}\s?\d{2}\s?\d{2}$/ }, { locale: 'de-DE', iso2: 'DE', validation: /^(\+49)?0?1(5[0-25-9]\d|6([23]|0\d?)|7([0-57-9]|6\d))\d{7}$/ }, { locale: 'de-AT', iso2: 'AT', validation: /^(\+43|0)\d{1,4}\d{3,12}$/ }, { locale: 'el-GR', iso2: 'GR', validation: /^(\+?30|0)?(69\d{8})$/ }, { locale: 'en-AU', iso2: 'AU', validation: /^(\+?61|0)4\d{8}$/ }, { locale: 'en-GB', iso2: 'GB', validation: /^(\+?44|0)7\d{9}$/ }, { locale: 'en-GG', iso2: 'GG', validation: /^(\+?44|0)1481\d{6}$/ }, { locale: 'en-GH', iso2: 'GH', validation: /^(\+233|0)(20|50|24|54|27|57|26|56|23|28)\d{7}$/ }, { locale: 'en-HK', iso2: 'HK', validation: /^(\+?852[-\s]?)?[456789]\d{3}[-\s]?\d{4}$/ }, { locale: 'en-MO', iso2: 'MO', validation: /^(\+?853[-\s]?)?[6]\d{3}[-\s]?\d{4}$/ }, { locale: 'en-IE', iso2: 'IE', validation: /^(\+?353|0)8[356789]\d{7}$/ }, { locale: 'en-IN', iso2: 'IN', validation: /^(\+?91|0)?[6789]\d{9}$/ }, { locale: 'en-KE', iso2: 'KE', validation: /^(\+?254|0)(7|1)\d{8}$/ }, { locale: 'en-MT', iso2: 'MT', validation: /^(\+?356|0)?(99|79|77|21|27|22|25)[0-9]{6}$/ }, { locale: 'en-MU', iso2: 'MU', validation: /^(\+?230|0)?\d{8}$/ }, { locale: 'en-NG', iso2: 'NG', validation: /^(\+?234|0)?[789]\d{9}$/ }, { locale: 'en-NZ', iso2: 'NZ', validation: /^(\+?64|0)[28]\d{7,9}$/ }, { locale: 'en-PK', iso2: 'PK', validation: /^((\+92)|(0092))-{0,1}\d{3}-{0,1}\d{7}$|^\d{11}$|^\d{4}-\d{7}$/ }, { locale: 'en-RW', iso2: 'RW', validation: /^(\+?250|0)?[7]\d{8}$/ }, { locale: 'en-SG', iso2: 'SG', validation: /^(\+65)?[89]\d{7}$/ }, { locale: 'en-SL', iso2: 'SL', validation: /^(?:0|94|\+94)?(7(0|1|2|5|6|7|8)( |-)?\d)\d{6}$/ }, { locale: 'en-TZ', iso2: 'TZ', validation: /^(\+?255|0)?[67]\d{8}$/ }, { locale: 'en-UG', iso2: 'UG', validation: /^(\+?256|0)?[7]\d{8}$/ }, { locale: 'en-US', iso2: 'US', validation: /^((\+1|1)?( |-)?)?(\([2-9][0-9]{2}\)|[2-9][0-9]{2})( |-)?([2-9][0-9]{2}( |-)?[0-9]{4})$/ }, { locale: 'en-ZA', iso2: 'ZA', validation: /^(\+?27|0)\d{9}$/ }, { locale: 'en-ZM', iso2: 'ZM', validation: /^(\+?26)?09[567]\d{7}$/ }, { locale: 'es-CL', iso2: 'CL', validation: /^(\+?56|0)[2-9]\d{1}\d{7}$/ }, { locale: 'es-EC', iso2: 'EC', validation: /^(\+?593|0)([2-7]|9[2-9])\d{7}$/ }, { locale: 'es-ES', iso2: 'ES', validation: /^(\+?34)?(6\d{1}|7[1234])\d{7}$/ }, { locale: 'es-MX', iso2: 'MX', validation: /^(\+?52)?(1|01)?\d{10,11}$/ }, { locale: 'es-PA', iso2: 'PA', validation: /^(\+?507)\d{7,8}$/ }, { locale: 'es-PY', iso2: 'PY', validation: /^(\+?595|0)9[9876]\d{7}$/ }, { locale: 'es-UY', iso2: 'UY', validation: /^(\+598|0)9[1-9][\d]{6}$/ }, { locale: 'et-EE', iso2: 'EE', validation: /^(\+?372)?\s?(5|8[1-4])\s?([0-9]\s?){6,7}$/ }, { locale: 'fa-IR', iso2: 'IR', validation: /^(\+?98[\-\s]?|0)9[0-39]\d[\-\s]?\d{3}[\-\s]?\d{4}$/ }, { locale: 'fi-FI', iso2: 'FI', validation: /^(\+?358|0)\s?(4(0|1|2|4|5|6)?|50)\s?(\d\s?){4,8}\d$/ }, { locale: 'fj-FJ', iso2: 'FJ', validation: /^(\+?679)?\s?\d{3}\s?\d{4}$/ }, { locale: 'fo-FO', iso2: 'FO', validation: /^(\+?298)?\s?\d{2}\s?\d{2}\s?\d{2}$/ }, { locale: 'fr-FR', iso2: 'FR', validation: /^(\+?33|0)[67]\d{8}$/ }, { locale: 'fr-GF', iso2: 'GF', validation: /^(\+?594|0|00594)[67]\d{8}$/ }, { locale: 'fr-GP', iso2: 'GP', validation: /^(\+?590|0|00590)[67]\d{8}$/ }, { locale: 'fr-MQ', iso2: 'MQ', validation: /^(\+?596|0|00596)[67]\d{8}$/ }, { locale: 'fr-RE', iso2: 'RE', validation: /^(\+?262|0|00262)[67]\d{8}$/ }, { locale: 'he-IL', iso2: 'IL', validation: /^(\+972|0)([23489]|5[012345689]|77)[1-9]\d{6}$/ }, { locale: 'hu-HU', iso2: 'HU', validation: /^(\+?36)(20|30|70)\d{7}$/ }, { locale: 'id-ID', iso2: 'ID', validation: /^(\+?62|0)8(1[123456789]|2[1238]|3[1238]|5[12356789]|7[78]|9[56789]|8[123456789])([\s?|\d]{5,11})$/ }, { locale: 'it-IT', iso2: 'IT', validation: /^(\+?39)?\s?3\d{2} ?\d{6,7}$/ }, { locale: 'ja-JP', iso2: 'JP', validation: /^(\+81[ \-]?(\(0\))?|0)[6789]0[ \-]?\d{4}[ \-]?\d{4}$/ }, { locale: 'kk-KZ', iso2: 'KZ', validation: /^(\+?7|8)?7\d{9}$/ }, { locale: 'kl-GL', iso2: 'GL', validation: /^(\+?299)?\s?\d{2}\s?\d{2}\s?\d{2}$/ }, { locale: 'ko-KR', iso2: 'KR', validation: /^((\+?82)[ \-]?)?0?1([0|1|6|7|8|9]{1})[ \-]?\d{3,4}[ \-]?\d{4}$/ }, { locale: 'lt-LT', iso2: 'LT', validation: /^(\+370|8)\d{8}$/ }, { locale: 'ms-MY', iso2: 'MY', validation: /^(\+?6?01){1}(([0145]{1}(\-|\s)?\d{7,8})|([236789]{1}(\s|\-)?\d{7}))$/ }, { locale: 'nb-NO', iso2: 'NO', validation: /^(\+?47)?[49]\d{7}$/ }, { locale: 'ne-NP', iso2: 'NP', validation: /^(\+?977)?9[78]\d{8}$/ }, { locale: 'nl-BE', iso2: 'BE', validation: /^(\+?32|0)4?\d{8}$/ }, { locale: 'nl-NL', iso2: 'NL', validation: /^(\+?31|0)6?\d{8}$/ }, { locale: 'nn-NO', iso2: 'NO', validation: /^(\+?47)?[49]\d{7}$/ }, { locale: 'pl-PL', iso2: 'PL', validation: /^(\+?48)? ?[5-8]\d ?\d{3} ?\d{2} ?\d{2}$/ }, { locale: 'pt-BR', isoBR2: '', phoneCodes: [], validation: /(?=^(\+?5{2}\-?|0)[1-9]{2}\-?\d{4}\-?\d{4}$)(^(\+?5{2}\-?|0)[1-9]{2}\-?[6-9]{1}\d{3}\-?\d{4}$)|(^(\+?5{2}\-?|0)[1-9]{2}\-?9[6-9]{1}\d{3}\-?\d{4}$)/, }, { locale: 'pt-PT', iso2: 'PT', validation: /^(\+?351)?9[1236]\d{7}$/ }, { locale: 'ro-RO', iso2: 'RO', validation: /^(\+?4?0)\s?7\d{2}(\/|\s|\.|\-)?\d{3}(\s|\.|\-)?\d{3}$/ }, { locale: 'ru-RU', iso2: 'RU', validation: /^(\+?7|8)?9\d{9}$/ }, { locale: 'sl-SI', iso2: 'SI', validation: /^(\+386\s?|0)(\d{1}\s?\d{3}\s?\d{2}\s?\d{2}|\d{2}\s?\d{3}\s?\d{3})$/ }, { locale: 'sk-SK', iso2: 'SK', validation: /^(\+?421)? ?[1-9][0-9]{2} ?[0-9]{3} ?[0-9]{3}$/ }, { locale: 'sr-RS', iso2: 'RS', validation: /^(\+3816|06)[- \d]{5,9}$/ }, { locale: 'sv-SE', iso2: 'SE', validation: /^(\+?46|0)[\s\-]?7[\s\-]?[02369]([\s\-]?\d){7}$/ }, { locale: 'th-TH', iso2: 'TH', validation: /^(\+66|66|0)\d{9}$/ }, { locale: 'tr-TR', iso2: 'TR', validation: /^(\+?90|0)?5\d{9}$/ }, { locale: 'uk-UA', iso2: 'UA', validation: /^(\+?38|8)?0\d{9}$/ }, { locale: 'vi-VN', iso2: 'VN', validation: /^(\+?84|0)((3([2-9]))|(5([2689]))|(7([0|6-9]))|(8([1-6|89]))|(9([0-9])))([0-9]{7})$/ }, { locale: 'zh-CN', iso2: 'CN', validation: /^((\+|00)86)?1([358][0-9]|4[579]|6[67]|7[01235678]|9[189])[0-9]{8}$/ }, { locale: 'zh-TW', iso2: 'TW', validation: /^(\+?886\-?|0)?9\d{8}$/ }, ]

I saved the selected country inside a state on my input phone and then passed it to the validation schema function

`import validateSchema from './validateSchema'

function InputPhone({ label, name, country, setCountry, mandatory, value, onChange, errors, submit, setSubmit }: Props) { const [country, setCountry] = useState('fr)

const validate = validateSchema(country)

return (
   ...
   <PhoneInput
      ...
      country={country}
      onChange={(_, options: any, event) => {
        ...
        setCountry(options.countryCode)
        onChange(event)
      }} />
   ...
)

}`

The schema validation for the input will look like this

` import * as Yup from 'yup' import { PHONE_COUNTRIES } from '@utils/constants'

const emailRegex = /^(([^>()[\]\\.,;:\s@"]+(\.[^<()[]\.,;:\s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,},))$/

const validateSchema = (countryCode: string) => Yup.object({ civility: Yup.string().required('Obligatoire'), phoneNumber: Yup.string() .required('Obligatoire') .test('len', 'Format de numéro de téléphone incorrect', (val) => { const correspondingCountry = PHONE_COUNTRIES.find((country) => country.iso2 === countryCode.toUpperCase()) let valide = false if (correspondingCountry && val) { valide = new RegExp(correspondingCountry.validation).test(val?.replace(/ /g, '')) } else if (val) { valide = /(([+][(]?[0-9]{1,3}[)]?)|([(]?[0-9]{4}[)]?))\s*[)]?[-\s.]?[(]?[0-9]{1,3}[)]?([-\s.]?[0-9]{3})([-\s.]?[0-9]{3,4})/.test(val?.replace(/ /g, '')) }

    return valide
  }),

... })

export default validateSchema`

If the country is not inside the constants file (example: Canada) I set a default validation to still try to passe the number with a general phone regex

That will also help me to configure a preselected input phone country based on the selected locale with I18N.

zeel91297 commented 1 year ago

@bl00mber You can also make use of onChange event like following: const [isPhoneValid, setPhoneValid] = useState(false)

<PhoneInput inputClass="ant-input phoneInput" country={'de'} enableSearch onChange={(value, country: any, e, formattedValue) => { const {format, dialCode} = country if (format?.length === formattedValue?.length && (value.startsWith(dialCode) || dialCode.startsWith(value))) { setPhoneValid(true) } else { setPhoneValid(false) } }} />

And for the submit button you make it enable/disable based on the flag isPhoneValid

<Button type="primary" className='modalbtn filledbtn' disabled={!isPhoneValid} htmlType="submit">Continue</Button>

belalahmad20 commented 1 year ago

There's another way to validate formatted phone numbers -

React State -

const [phoneInvalid, setPhoneInvalid] = useState(false);
<PhoneInput
  ...
  onChange={(v, c, e, f) => _validatePhone(e.target.value, c.format)}
  ...
/>

The _validatePhone function -

const _validatePhone = (number: string, format: string) => {
  // Example -
  // number - +1 (123) 456-7890
  // format - +. (...) ...-....

  setPhoneInvalid(format !== String(number).replace(/[0-9]/g, "."));
};
swastikpatro commented 9 months ago

@belalahmad20 @zeel91297

The package provides wrong country formats (for example Peru's country.format is not similar to phone number you type).

Rajeshkanth commented 4 months ago

how to check the starting number is match with their respective country code in input box for getting mobile number, i.e- if india then +91 and starting number should be in the range between 6-9 how to validate that for all countries , in react

nik32 commented 1 month ago

@bl00mber Thanks for this fantastic library!

Here's our solution using libphonenumber-js library (it's the smallest among all popular ports of Google libphonenumber) -

import parsePhoneNumber, { CountryCode } from 'libphonenumber-js';
import { CountryData } from 'react-phone-input-2';

type IsPhoneValidParams = {
  phone: string;
  country: CountryData | {};
};

export const isPhoneValid = ({ phone, country }: IsPhoneValidParams) => {
  const { countryCode: countryCodePhoneInput, dialCode } = country;
  if (!countryCodePhoneInput || !dialCode) return true; //returned true - AS We don't want to stop user from entering his number just coz we don't have country data

  const countryCode = countryCodePhoneInput.toUpperCase() as CountryCode;
  const phoneWithoutDialCode = phone.replace(dialCode, '');
  const phoneNumber = parsePhoneNumber(phoneWithoutDialCode, countryCode);
  return phoneNumber?.isValid();
};