diff --git a/src/decorator/string/IsPhoneNumber.ts b/src/decorator/string/IsPhoneNumber.ts index 65744a99ab..ddb21b9314 100644 --- a/src/decorator/string/IsPhoneNumber.ts +++ b/src/decorator/string/IsPhoneNumber.ts @@ -1,6 +1,12 @@ +import { allPhoneNumberTypes, PhoneNumberType } from '../../utils/phone-number-type'; import { ValidationOptions } from '../ValidationOptions'; import { buildMessage, ValidateBy } from '../common/ValidateBy'; -import { parsePhoneNumber, CountryCode } from 'libphonenumber-js/max'; + +/* Changed import to /max for all metadata provided in the library in order to check phone number type + * since the (default = /min) always returns undefined in the .getType() + * reference https://www.npmjs.com/package/libphonenumber-js + */ +import { parsePhoneNumberFromString, CountryCode } from 'libphonenumber-js/max'; export const IS_PHONE_NUMBER = 'isPhoneNumber'; @@ -10,26 +16,30 @@ export const IS_PHONE_NUMBER = 'isPhoneNumber'; * * @param value the potential phone number string to test * @param region 2 characters uppercase country code (e.g. DE, US, CH) for country specific validation. + * @param acceptedNumbersTypes list of accepted number types (MOBILE, PAGER, etc...) if not provided then accept all valid numbers. * If text doesn't start with the international calling code (e.g. +41), then you must set this parameter. */ -export function isPhoneNumber(value: string, region?: CountryCode): boolean { - if (typeof value !== 'string' || value.trim() !== value) { - return false; - } - +export function isPhoneNumber( + value: string, + region?: CountryCode, + acceptedNumbersTypes?: Array +): boolean { try { - const phoneNumber = parsePhoneNumber(value, region); - - /** - * We fail the validation if the user provided a region code - * and it doesn't match with the country code of the parsed number. - **/ - if (region && phoneNumber.country !== region) { - return false; + // the list of all phone number types that are the output of .getType() method + let checkedNumberTypes: Array = allPhoneNumberTypes; + + // Checking if accepted types array is passed to override the default + if (acceptedNumbersTypes) { + checkedNumberTypes = acceptedNumbersTypes; } - return phoneNumber.isValid(); + const phoneNum = parsePhoneNumberFromString(value, region); + + // number must be valid and is one of the phone types the function accepts (ALL TYPES PROVIDED IN phone-number-types.ts) + const result: boolean = !!phoneNum?.isValid() && !!checkedNumberTypes.some(item => item === phoneNum?.getType()); + return result; } catch (error) { + // logging? return false; } } @@ -39,17 +49,33 @@ export function isPhoneNumber(value: string, region?: CountryCode): boolean { * the intl. calling code, if the calling code wont be provided then the region must be set. * * @param region 2 characters uppercase country code (e.g. DE, US, CH) for country specific validation. + * @param acceptedNumbersTypes list of accepted number types (MOBILE, PAGER, etc...) if not provided then accept all valid phone numbers * If text doesn't start with the international calling code (e.g. +41), then you must set this parameter. */ -export function IsPhoneNumber(region?: CountryCode, validationOptions?: ValidationOptions): PropertyDecorator { +export function IsPhoneNumber( + region?: CountryCode, + validationOptions?: ValidationOptions, + acceptedNumbersTypes?: Array +): PropertyDecorator { + // the list of all phone number types that are the output of .getType() method + let checkedNumberTypes: Array = allPhoneNumberTypes; + + // Checking if accepted types array is passed to override the default + if (acceptedNumbersTypes) { + checkedNumberTypes = acceptedNumbersTypes; + } + return ValidateBy( { name: IS_PHONE_NUMBER, constraints: [region], validator: { - validate: (value, args): boolean => isPhoneNumber(value, args?.constraints[0]), + validate: (value, args): boolean => isPhoneNumber(value, args?.constraints[0], checkedNumberTypes), defaultMessage: buildMessage( - eachPrefix => eachPrefix + '$property must be a valid phone number', + eachPrefix => + eachPrefix + + '$property must be a valid phone number and of the following types: ' + + checkedNumberTypes.toString(), validationOptions ), }, diff --git a/src/utils/phone-number-type.ts b/src/utils/phone-number-type.ts new file mode 100644 index 0000000000..30f64bad9b --- /dev/null +++ b/src/utils/phone-number-type.ts @@ -0,0 +1,29 @@ +/* + types of all possible return values of the .getType() in the phone number libphonenumber-js/max library +*/ +export type PhoneNumberType = + | 'FIXED_LINE_OR_MOBILE' + | 'MOBILE' + | 'FIXED_LINE' + | 'PREMIUM_RATE' + | 'TOLL_FREE' + | 'SHARED_COST' + | 'VOIP' + | 'PERSONAL_NUMBER' + | 'PAGER' + | 'UAN' + | 'VOICEMAIL'; + + export const allPhoneNumberTypes:Array = [ + 'FIXED_LINE_OR_MOBILE', + 'MOBILE', + 'FIXED_LINE', + 'PREMIUM_RATE', + 'TOLL_FREE', + 'SHARED_COST', + 'VOIP', + 'PERSONAL_NUMBER', + 'PAGER', + 'UAN', + 'VOICEMAIL', + ]; \ No newline at end of file