import parsePhoneNumberFromString, { getCountryCallingCode, type CountryCode } from 'libphonenumber-js/mobile/es6' import { getPhoneMaskForCountry } from './phoneMask' const nationalDigitsForMask = (parsed: NonNullable>): string => parsed.formatNational().replace(/\D/g, '') const tryParseForCountry = (candidate: string, country: CountryCode): ReturnType => { const parsed = parsePhoneNumberFromString(candidate, country) ?? parsePhoneNumberFromString(candidate) if (!parsed?.isValid() || parsed.country !== country) { return undefined } return parsed } /** Whether the value likely contains a country calling code or international formatting. */ export const shouldNormalizePhoneInput = (value: string, countryIso2: string): boolean => { const trimmed = value.trim() if (!trimmed) { return false } if (trimmed.includes('+') || trimmed.startsWith('00')) { return true } const digits = trimmed.replace(/\D/g, '') const mask = getPhoneMaskForCountry(countryIso2) if (!mask) { return false } const maxDigits = (mask.match(/0/g) ?? []).length if (digits.length > maxDigits) { return true } try { const callingCode = getCountryCallingCode(countryIso2 as CountryCode) if (digits.startsWith(callingCode) && digits.length > maxDigits - 1) { return true } } catch { return false } return false } /** * Converts international/autocomplete values to national digits for the IMask field. * IMask reapplies spacing from the country mask. */ export const normalizeNationalPhoneInput = (value: string, countryIso2: string): string => { const trimmed = value.trim() if (!trimmed) { return '' } const country = countryIso2.trim().toUpperCase() as CountryCode const digits = trimmed.replace(/\D/g, '') const candidates = new Set([trimmed]) if (digits) { candidates.add(digits) candidates.add(`+${digits}`) } for (const candidate of candidates) { const parsed = tryParseForCountry(candidate, country) if (parsed) { return nationalDigitsForMask(parsed) } } try { const callingCode = getCountryCallingCode(country) if (digits.startsWith(callingCode) && digits.length > callingCode.length) { const withoutCode = digits.slice(callingCode.length) const parsed = tryParseForCountry(withoutCode, country) ?? tryParseForCountry(`0${withoutCode}`, country) if (parsed) { return nationalDigitsForMask(parsed) } } } catch { return trimmed } return trimmed }