saveinmed/saveinmed-frontend/src/lib/masks.ts
Tiago Yamamoto b39caf0fd0 first commit
2025-12-17 13:58:26 -03:00

227 lines
No EOL
6.8 KiB
TypeScript

/**
* Biblioteca de máscaras compartilhada para formatação de dados
* Contém funções para formatação de CPF, CNPJ, telefone e outras máscaras comuns
*/
/**
* Formata um CPF com a máscara XXX.XXX.XXX-XX
* @param value - Valor a ser formatado
* @returns CPF formatado
*/
export const formatCPF = (value: string): string => {
const numbers = value.replace(/\D/g, '');
if (numbers.length <= 11) {
return numbers.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4');
}
return numbers.substring(0, 11).replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4');
};
/**
* Formata um CNPJ com a máscara XX.XXX.XXX/XXXX-XX
* @param value - Valor a ser formatado
* @returns CNPJ formatado
*/
export const formatCNPJ = (value: string): string => {
const numbers = value.replace(/\D/g, '');
if (numbers.length <= 14) {
return numbers.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5');
}
return numbers.substring(0, 14).replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5');
};
/**
* Formata um telefone com a máscara +55 (XX) XXXXX-XXXX ou +55 (XX) XXXX-XXXX
* @param value - Valor a ser formatado
* @returns Telefone formatado no padrão brasileiro
*/
export const formatPhone = (value: string): string => {
const numbers = value.replace(/\D/g, '');
// Se já tem código do país (55), remove para reformatar
let cleanNumbers = numbers;
if (numbers.startsWith('55') && numbers.length >= 12) {
cleanNumbers = numbers.substring(2);
}
// Formata conforme o tamanho
if (cleanNumbers.length === 10) {
// Telefone fixo: +55 (XX) XXXX-XXXX
return cleanNumbers.replace(/(\d{2})(\d{4})(\d{4})/, '+55 ($1) $2-$3');
} else if (cleanNumbers.length === 11) {
// Celular: +55 (XX) XXXXX-XXXX
return cleanNumbers.replace(/(\d{2})(\d{5})(\d{4})/, '+55 ($1) $2-$3');
} else if (cleanNumbers.length >= 8) {
// Tenta formatar com o que tem disponível
if (cleanNumbers.length <= 10) {
return cleanNumbers.replace(/(\d{2})(\d{4})(\d{0,4})/, '+55 ($1) $2-$3');
} else {
return cleanNumbers.replace(/(\d{2})(\d{5})(\d{0,4})/, '+55 ($1) $2-$3');
}
}
// Se não conseguir formatar, retorna com +55 na frente
return numbers.length > 0 ? `+55 ${numbers}` : numbers;
};
/**
* Formata um CEP com a máscara XXXXX-XXX
* @param value - Valor a ser formatado
* @returns CEP formatado
*/
export const formatCEP = (value: string): string => {
const numbers = value.replace(/\D/g, '');
if (numbers.length <= 8) {
return numbers.replace(/(\d{5})(\d{3})/, '$1-$2');
}
return numbers.substring(0, 8).replace(/(\d{5})(\d{3})/, '$1-$2');
};
/**
* Remove todos os caracteres não numéricos de uma string
* @param value - Valor a ser limpo
* @returns String apenas com números
*/
export const removeNonNumeric = (value: string): string => {
return value.replace(/\D/g, '');
};
/**
* Valida se um CPF é válido
* @param cpf - CPF a ser validado
* @returns true se válido, false caso contrário
*/
export const validateCPF = (cpf: string): boolean => {
const numbers = removeNonNumeric(cpf);
if (numbers.length !== 11) return false;
// Verifica se todos os dígitos são iguais
if (/^(\d)\1{10}$/.test(numbers)) return false;
// Validação do primeiro dígito verificador
let sum = 0;
for (let i = 0; i < 9; i++) {
sum += parseInt(numbers[i]) * (10 - i);
}
let remainder = sum % 11;
const digit1 = remainder < 2 ? 0 : 11 - remainder;
if (parseInt(numbers[9]) !== digit1) return false;
// Validação do segundo dígito verificador
sum = 0;
for (let i = 0; i < 10; i++) {
sum += parseInt(numbers[i]) * (11 - i);
}
remainder = sum % 11;
const digit2 = remainder < 2 ? 0 : 11 - remainder;
return parseInt(numbers[10]) === digit2;
};
/**
* Valida se um CNPJ é válido
* @param cnpj - CNPJ a ser validado
* @returns true se válido, false caso contrário
*/
export const validateCNPJ = (cnpj: string): boolean => {
const numbers = removeNonNumeric(cnpj);
if (numbers.length !== 14) return false;
// Verifica se todos os dígitos são iguais
if (/^(\d)\1{13}$/.test(numbers)) return false;
// Validação do primeiro dígito verificador
const weights1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
let sum = 0;
for (let i = 0; i < 12; i++) {
sum += parseInt(numbers[i]) * weights1[i];
}
let remainder = sum % 11;
const digit1 = remainder < 2 ? 0 : 11 - remainder;
if (parseInt(numbers[12]) !== digit1) return false;
// Validação do segundo dígito verificador
const weights2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
sum = 0;
for (let i = 0; i < 13; i++) {
sum += parseInt(numbers[i]) * weights2[i];
}
remainder = sum % 11;
const digit2 = remainder < 2 ? 0 : 11 - remainder;
return parseInt(numbers[13]) === digit2;
};
/**
* Valida se um telefone tem formato válido
* @param phone - Telefone a ser validado
* @returns true se válido, false caso contrário
*/
export const validatePhone = (phone: string): boolean => {
const numbers = removeNonNumeric(phone);
return numbers.length >= 10 && numbers.length <= 11;
};
/**
* Valida se um CEP tem formato válido
* @param cep - CEP a ser validado
* @returns true se válido, false caso contrário
*/
export const validateCEP = (cep: string): boolean => {
const numbers = removeNonNumeric(cep);
return numbers.length === 8;
};
/**
* Valida se um email tem formato válido
* @param email - Email a ser validado
* @returns true se válido, false caso contrário
*/
export const validateEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
/**
* Capitaliza a primeira letra de cada palavra
* @param text - Texto a ser formatado
* @returns Texto com primeira letra de cada palavra maiúscula
*/
export const capitalizeWords = (text: string): string => {
return text.toLowerCase().replace(/\b\w/g, l => l.toUpperCase());
};
/**
* Formata um valor monetário para o padrão brasileiro
* @param value - Valor a ser formatado
* @returns Valor formatado como moeda brasileira
*/
export const formatCurrency = (value: number): string => {
return new Intl.NumberFormat('pt-BR', {
style: 'currency',
currency: 'BRL'
}).format(value);
};
/**
* Formata uma data para o padrão brasileiro
* @param date - Data a ser formatada
* @returns Data formatada como DD/MM/AAAA
*/
export const formatDate = (date: Date | string): string => {
const dateObj = typeof date === 'string' ? new Date(date) : date;
return dateObj.toLocaleDateString('pt-BR');
};
/**
* Formata uma data e hora para o padrão brasileiro
* @param date - Data a ser formatada
* @returns Data e hora formatada como DD/MM/AAAA HH:MM
*/
export const formatDateTime = (date: Date | string): string => {
const dateObj = typeof date === 'string' ? new Date(date) : date;
return dateObj.toLocaleString('pt-BR');
};