@blocklet/payment-react
Version:
Reusable react components for payment kit v2
109 lines (97 loc) • 3.55 kB
text/typescript
let phoneUtil: any = null;
export const getPhoneUtil = async () => {
if (!phoneUtil) {
const result = await import(/* webpackChunkName: "phone-util" */ 'google-libphonenumber');
const PhoneNumberUtil = (result.default || result)?.PhoneNumberUtil;
if (!PhoneNumberUtil) {
throw new Error('PhoneNumberUtil not found');
}
phoneUtil = PhoneNumberUtil.getInstance();
}
return phoneUtil;
};
export const validatePhoneNumber = async (phoneNumber: string) => {
if (!phoneNumber) return true;
try {
let util: any = null;
try {
util = await getPhoneUtil();
} catch (err) {
const pattern = /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/im;
return pattern.test(phoneNumber);
}
const parsed = util.parseAndKeepRawInput(phoneNumber);
return util.isValidNumber(parsed);
} catch (err) {
console.error('Phone validation error:', err);
return false;
}
};
/**
* Format a phone number to international format
* @param phoneNumber The original phone number
* @param defaultCountry Default country code (ISO 3166-1 alpha-2)
* @returns Formatted phone number
*/
export const formatPhone = (phoneNumber: string | undefined, defaultCountry = 'US') => {
if (!phoneNumber || phoneNumber.trim() === '') {
return '';
}
// Remove all non-digit characters (preserve plus sign)
const cleanedNumber = phoneNumber.replace(/[^\d+]/g, '');
// If already in international format (starting with +), return cleaned number
if (cleanedNumber.startsWith('+')) {
return cleanedNumber;
}
// Country code mapping
const COUNTRY_CODES: Record<string, string> = {
US: '1', // United States
CA: '1', // Canada
CN: '86', // China
HK: '852', // Hong Kong
IN: '91', // India
UK: '44', // United Kingdom
GB: '44', // United Kingdom
JP: '81', // Japan
KR: '82', // South Korea
AU: '61', // Australia
DE: '49', // Germany
FR: '33', // France
IT: '39', // Italy
ES: '34', // Spain
BR: '55', // Brazil
RU: '7', // Russia
MX: '52', // Mexico
SG: '65', // Singapore
AE: '971', // UAE
};
// Country-specific patterns
const COUNTRY_PATTERNS: [RegExp, string][] = [
[/^1[3-9]\d{9}$/, '86'], // China mobile: 11 digits, starts with 1
[/^\d{10}$/, '1'], // US/Canada: 10 digits
[/^[6-9]\d{9}$/, '91'], // India: 10 digits, starts with 6-9
[/^0[1-9]\d{8,9}$/, '81'], // Japan: 10-11 digits, starts with 0
[/^07\d{9}$/, '44'], // UK mobile: 11 digits, starts with 07
[/^04\d{8}$/, '61'], // Australia mobile: 10 digits, starts with 04
[/^01[0-9]\d{7,8}$/, '82'], // Korea mobile: 10-11 digits, starts with 01
[/^[0-9]\d{8}$/, '86'], // China landline: 9 digits
];
// Remove leading zero (common in many countries)
let numberToFormat = cleanedNumber;
if (numberToFormat.startsWith('0')) {
numberToFormat = numberToFormat.substring(1);
}
// Try to match with country-specific patterns
for (const [pattern, countryCode] of COUNTRY_PATTERNS) {
if (pattern.test(cleanedNumber)) {
// For numbers starting with 0 that need the zero removed
if (cleanedNumber.startsWith('0') && !['1', '86'].includes(countryCode)) {
return `+${countryCode}${cleanedNumber.substring(1)}`;
}
return `+${countryCode}${cleanedNumber}`;
}
}
// If no pattern matched, use default country code
const countryCode = COUNTRY_CODES[defaultCountry.toUpperCase()] || defaultCountry;
return `+${countryCode}${numberToFormat}`;
};