Skip to main content

Phone Number Helpers

Phone number validation, formatting, and processing utilities for international phone numbers in the WorkPayCore frontend application.

Overview​

The phone number helpers provide utilities for validating, formatting, and processing phone numbers across different countries and regions, with support for international formats.

Core Functions​

validatePhoneNumber(phoneNumber, countryCode?)​

Validates a phone number format and returns validation status.

Parameters:

  • phoneNumber (string): Phone number to validate
  • countryCode (string, optional): ISO country code (e.g., 'US', 'KE', 'NG')

Returns:

  • object: Validation result with status and details

Example:

import { validatePhoneNumber } from '@/utils/helpers/phone-number';

// Validate US phone number
const usResult = validatePhoneNumber('+1-555-123-4567', 'US');
console.log(usResult);
// Returns: { isValid: true, country: 'US', format: 'international' }

// Validate Kenyan phone number
const keResult = validatePhoneNumber('+254712345678', 'KE');
console.log(keResult);
// Returns: { isValid: true, country: 'KE', format: 'international' }

// Invalid phone number
const invalidResult = validatePhoneNumber('123', 'US');
console.log(invalidResult);
// Returns: { isValid: false, error: 'Invalid phone number format' }

Use Cases:

  • Form validation
  • User registration
  • Contact information verification
  • International number validation

formatPhoneNumber(phoneNumber, format?, countryCode?)​

Formats a phone number according to specified format and country standards.

Parameters:

  • phoneNumber (string): Raw phone number to format
  • format (string, optional): Format type ('international', 'national', 'e164')
  • countryCode (string, optional): ISO country code

Returns:

  • string: Formatted phone number or original if formatting fails

Example:

import { formatPhoneNumber } from '@/utils/helpers/phone-number';

// Format to international standard
const international = formatPhoneNumber('5551234567', 'international', 'US');
console.log(international);
// Returns: '+1 555 123 4567'

// Format to national standard
const national = formatPhoneNumber('5551234567', 'national', 'US');
console.log(national);
// Returns: '(555) 123-4567'

// Format to E.164 standard
const e164 = formatPhoneNumber('555 123 4567', 'e164', 'US');
console.log(e164);
// Returns: '+15551234567'

// Kenyan number formatting
const kenyan = formatPhoneNumber('712345678', 'international', 'KE');
console.log(kenyan);
// Returns: '+254 712 345 678'

Use Cases:

  • Display formatting
  • API data preparation
  • Consistent number storage
  • User interface standardization

parsePhoneNumber(phoneNumber)​

Parses a phone number and extracts components like country code, area code, and number.

Parameters:

  • phoneNumber (string): Phone number to parse

Returns:

  • object: Parsed phone number components

Example:

import { parsePhoneNumber } from '@/utils/helpers/phone-number';

// Parse US number
const usNumber = parsePhoneNumber('+1-555-123-4567');
console.log(usNumber);
// Returns: {
// countryCode: '1',
// areaCode: '555',
// number: '1234567',
// extension: null,
// isValid: true
// }

// Parse international number
const intlNumber = parsePhoneNumber('+44 20 7946 0958');
console.log(intlNumber);
// Returns: {
// countryCode: '44',
// areaCode: '20',
// number: '79460958',
// extension: null,
// isValid: true
// }

Use Cases:

  • Number analysis
  • Database storage optimization
  • Search functionality
  • Number component extraction

getCountryFromPhoneNumber(phoneNumber)​

Determines the country of origin for a phone number based on country code.

Parameters:

  • phoneNumber (string): Phone number to analyze

Returns:

  • object: Country information or null if not found

Example:

import { getCountryFromPhoneNumber } from '@/utils/helpers/phone-number';

// US number
const usCountry = getCountryFromPhoneNumber('+1-555-123-4567');
console.log(usCountry);
// Returns: { code: 'US', name: 'United States', dialCode: '+1' }

// Kenyan number
const keCountry = getCountryFromPhoneNumber('+254712345678');
console.log(keCountry);
// Returns: { code: 'KE', name: 'Kenya', dialCode: '+254' }

// Unknown number
const unknown = getCountryFromPhoneNumber('123456');
console.log(unknown);
// Returns: null

Use Cases:

  • Automatic country detection
  • Billing region determination
  • Localization services
  • Fraud detection

Regional Support Functions​

getSupportedCountries()​

Returns list of supported countries for phone number operations.

Parameters:

  • None

Returns:

  • array: Array of supported country objects

Example:

import { getSupportedCountries } from '@/utils/helpers/phone-number';

const countries = getSupportedCountries();
console.log(countries);
// Returns: [
// { code: 'US', name: 'United States', dialCode: '+1', flag: 'πŸ‡ΊπŸ‡Έ' },
// { code: 'KE', name: 'Kenya', dialCode: '+254', flag: 'πŸ‡°πŸ‡ͺ' },
// { code: 'NG', name: 'Nigeria', dialCode: '+234', flag: 'πŸ‡³πŸ‡¬' },
// // ... more countries
// ]

Use Cases:

  • Country selector components
  • Validation rule configuration
  • International calling features
  • Regional service availability

getDialCodeForCountry(countryCode)​

Gets the international dial code for a specific country.

Parameters:

  • countryCode (string): ISO country code

Returns:

  • string: Dial code or null if not found

Example:

import { getDialCodeForCountry } from '@/utils/helpers/phone-number';

getDialCodeForCountry('US'); // Returns: '+1'
getDialCodeForCountry('KE'); // Returns: '+254'
getDialCodeForCountry('GB'); // Returns: '+44'
getDialCodeForCountry('XX'); // Returns: null

Use Cases:

  • Phone input prefilling
  • Country selection handling
  • International calling setup
  • Number formatting preparation

Advanced Usage Examples​

Phone Input Component​

import {
validatePhoneNumber,
formatPhoneNumber,
getSupportedCountries,
} from '@/utils/helpers/phone-number';

const PhoneInput = ({ value, onChange, onValidation }) => {
const [selectedCountry, setSelectedCountry] = useState('US');
const [phoneNumber, setPhoneNumber] = useState(value || '');
const [isValid, setIsValid] = useState(false);

const countries = getSupportedCountries();

const handlePhoneChange = newNumber => {
setPhoneNumber(newNumber);

// Validate phone number
const validation = validatePhoneNumber(newNumber, selectedCountry);
setIsValid(validation.isValid);

// Format for display
const formatted = formatPhoneNumber(newNumber, 'national', selectedCountry);

// Notify parent component
onChange?.(formatted);
onValidation?.(validation);
};

const handleCountryChange = countryCode => {
setSelectedCountry(countryCode);

// Revalidate with new country
if (phoneNumber) {
handlePhoneChange(phoneNumber);
}
};

return (
<div className='phone-input'>
<select
value={selectedCountry}
onChange={e => handleCountryChange(e.target.value)}
className='country-selector'
>
{countries.map(country => (
<option key={country.code} value={country.code}>
{country.flag} {country.name} ({country.dialCode})
</option>
))}
</select>

<input
type='tel'
value={phoneNumber}
onChange={e => handlePhoneChange(e.target.value)}
placeholder='Phone number'
className={`phone-field ${isValid ? 'valid' : 'invalid'}`}
/>

{!isValid && phoneNumber && (
<span className='error'>Invalid phone number format</span>
)}
</div>
);
};

Phone Number Validation Hook​

import {
validatePhoneNumber,
formatPhoneNumber,
} from '@/utils/helpers/phone-number';

const usePhoneValidation = (initialCountry = 'US') => {
const [country, setCountry] = useState(initialCountry);
const [phoneNumber, setPhoneNumber] = useState('');
const [validation, setValidation] = useState({ isValid: false });

const validatePhone = useCallback(
(number, countryCode = country) => {
const result = validatePhoneNumber(number, countryCode);
setValidation(result);
return result;
},
[country],
);

const formatPhone = useCallback(
(number, format = 'national') => {
return formatPhoneNumber(number, format, country);
},
[country],
);

const updatePhone = number => {
setPhoneNumber(number);
validatePhone(number);
};

const updateCountry = newCountry => {
setCountry(newCountry);
if (phoneNumber) {
validatePhone(phoneNumber, newCountry);
}
};

return {
phoneNumber,
country,
validation,
updatePhone,
updateCountry,
formatPhone,
validatePhone,
};
};

// Usage in form
const ContactForm = () => {
const {
phoneNumber,
country,
validation,
updatePhone,
updateCountry,
formatPhone,
} = usePhoneValidation();

const handleSubmit = e => {
e.preventDefault();

if (!validation.isValid) {
alert('Please enter a valid phone number');
return;
}

const formattedPhone = formatPhone(phoneNumber, 'e164');

// Submit with formatted phone number
submitForm({ phone: formattedPhone, country });
};

return (
<form onSubmit={handleSubmit}>
<PhoneInput
value={phoneNumber}
country={country}
onChange={updatePhone}
onCountryChange={updateCountry}
/>

<button type='submit' disabled={!validation.isValid}>
Submit
</button>
</form>
);
};

Bulk Phone Processing​

import {
validatePhoneNumber,
formatPhoneNumber,
parsePhoneNumber,
} from '@/utils/helpers/phone-number';

const processBulkPhoneNumbers = (phoneList, defaultCountry = 'US') => {
return phoneList.map(item => {
const { phone, country = defaultCountry, ...rest } = item;

// Parse and validate
const parsed = parsePhoneNumber(phone);
const validation = validatePhoneNumber(phone, country);

// Format for different uses
const formatted = {
display: formatPhoneNumber(phone, 'national', country),
storage: formatPhoneNumber(phone, 'e164', country),
international: formatPhoneNumber(phone, 'international', country),
};

return {
...rest,
originalPhone: phone,
country,
parsed,
validation,
formatted,
isProcessed: true,
};
});
};

// Usage for employee data processing
const processEmployeePhones = async employees => {
const processed = processBulkPhoneNumbers(employees);

// Filter valid phone numbers
const validPhones = processed.filter(emp => emp.validation.isValid);

// Group by country
const byCountry = validPhones.reduce((acc, emp) => {
const country = emp.country;
if (!acc[country]) acc[country] = [];
acc[country].push(emp);
return acc;
}, {});

return {
total: processed.length,
valid: validPhones.length,
invalid: processed.length - validPhones.length,
byCountry,
processed,
};
};

International Calling Features​

import {
getCountryFromPhoneNumber,
getDialCodeForCountry,
formatPhoneNumber,
} from '@/utils/helpers/phone-number';

const useInternationalCalling = () => {
const [currentCountry, setCurrentCountry] = useState('US');

const calculateCallCost = (phoneNumber, duration) => {
const targetCountry = getCountryFromPhoneNumber(phoneNumber);

if (!targetCountry) {
return { error: 'Unknown destination country' };
}

// Mock rate calculation
const rates = {
US: 0.02,
KE: 0.15,
NG: 0.18,
GB: 0.05,
};

const rate = rates[targetCountry.code] || 0.25;
const cost = (duration / 60) * rate;

return {
targetCountry,
rate,
duration,
cost: cost.toFixed(2),
formattedNumber: formatPhoneNumber(phoneNumber, 'international'),
};
};

const prepareInternationalCall = phoneNumber => {
const country = getCountryFromPhoneNumber(phoneNumber);
const dialCode = getDialCodeForCountry(currentCountry);

if (country && country.code !== currentCountry) {
return {
isInternational: true,
targetCountry: country,
dialCode,
formattedNumber: formatPhoneNumber(phoneNumber, 'international'),
estimatedRate: calculateCallCost(phoneNumber, 60).rate,
};
}

return {
isInternational: false,
targetCountry: null,
dialCode,
formattedNumber: formatPhoneNumber(
phoneNumber,
'national',
currentCountry,
),
};
};

return {
currentCountry,
setCurrentCountry,
calculateCallCost,
prepareInternationalCall,
};
};

Best Practices​

  1. Always Validate: Validate phone numbers before processing or storage
  2. Consistent Formatting: Use E.164 format for storage, national for display
  3. Country Context: Always provide country context when possible
  4. Error Handling: Handle invalid numbers gracefully
  5. Performance: Cache country lists and validation rules

Common Patterns​

Phone Number Storage​

// Store in E.164 format
const phoneForStorage = formatPhoneNumber(userInput, 'e164', country);

// Display in national format
const phoneForDisplay = formatPhoneNumber(storedPhone, 'national', country);

Form Validation​

const isPhoneValid = (phone, country) => {
const validation = validatePhoneNumber(phone, country);
return validation.isValid;
};


TypeScript Definitions​

interface PhoneValidation {
isValid: boolean;
country?: string;
format?: string;
error?: string;
}

interface ParsedPhoneNumber {
countryCode: string;
areaCode: string;
number: string;
extension: string | null;
isValid: boolean;
}

interface CountryInfo {
code: string;
name: string;
dialCode: string;
flag?: string;
}

export function validatePhoneNumber(
phoneNumber: string,
countryCode?: string,
): PhoneValidation;

export function formatPhoneNumber(
phoneNumber: string,
format?: string,
countryCode?: string,
): string;

export function parsePhoneNumber(phoneNumber: string): ParsedPhoneNumber;
export function getCountryFromPhoneNumber(
phoneNumber: string,
): CountryInfo | null;
export function getSupportedCountries(): CountryInfo[];
export function getDialCodeForCountry(countryCode: string): string | null;

Dependencies​

  • libphonenumber-js: For phone number parsing and validation
  • Country data: For country codes and dial codes
  • Regex patterns: For format validation