/** * 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'); };