react-phone-input-2 icon indicating copy to clipboard operation
react-phone-input-2 copied to clipboard

Validate Phone number

Open ajagadees opened this issue 4 years ago • 18 comments

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.

ajagadees avatar Apr 02 '20 08:04 ajagadees

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?

bl00mber avatar Apr 02 '20 11:04 bl00mber

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}$/,
};

hardy12994 avatar Apr 03 '20 11:04 hardy12994

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.

ajagadees avatar Apr 05 '20 07:04 ajagadees

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

Bouftini1992 avatar Apr 06 '20 16:04 Bouftini1992

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

ArnasSalokas avatar Apr 14 '20 10:04 ArnasSalokas

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

bl00mber avatar Apr 14 '20 15:04 bl00mber

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.

bl00mber avatar Apr 14 '20 16:04 bl00mber

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

codemewell avatar Jan 20 '21 14:01 codemewell

@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.

  • During render method, the isValid will be called at the same time, which will result to change the state in render method, which does not allow in React.

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
    });

Troy-Yang avatar Mar 18 '21 09:03 Troy-Yang

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 }

sbaz44 avatar Jan 11 '22 12:01 sbaz44

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.

yasharma2301 avatar Jun 29 '22 12:06 yasharma2301

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.

Dupflo avatar Jul 19 '22 19:07 Dupflo

@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>

zeel91297 avatar Aug 29 '22 11:08 zeel91297

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, "."));
};

belalahmad20 avatar Apr 02 '23 08:04 belalahmad20

@belalahmad20 @zeel91297

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

swastikpatro avatar Oct 11 '23 19:10 swastikpatro