teqo-backup/src/lib/phone.ts
Francisco Ignácio Fontoura Solla 9150092e17 B28: e-mail + celular na lista de lideranças
- colunas E-mail/Celular (copy-on-click, toast, "—" vazio) + coluna de
  Ações com WhatsApp (wa.me), no padrão de /campanha/assessores (B19)
- shared/CampaignCopyableCell.tsx nasce compartilhado já no 2º call site;
  AdvisorsTable.tsx migrado no mesmo PR para consumi-lo
- whatsAppHrefForPhone promovido a lib/phone.ts
- leadershipData.ts: contactSummary (+ email), loadLeadershipDetail
  deduplicado (reusa row.email)
- simplify: remove try/catch morto em whatsAppHrefForPhone, remove casts
  redundantes em contactSummary, displayEmail retorna string | null direto
- docs: nucleos-eleitorais.mdc, roadmap.md, plano B28 marcados entregues
2026-07-26 15:30:39 -03:00

61 lines
2.1 KiB
TypeScript

const BRAZIL_COUNTRY_CODE = '55'
const BRAZILIAN_MOBILE_PHONE_LENGTH = 11
export const sanitizeBrazilianPhoneInput = (value: string): string => {
const digits = value.replace(/\D/g, '')
const domesticDigits =
digits.length > BRAZILIAN_MOBILE_PHONE_LENGTH && digits.startsWith(BRAZIL_COUNTRY_CODE)
? digits.slice(BRAZIL_COUNTRY_CODE.length)
: digits
return domesticDigits.slice(0, BRAZILIAN_MOBILE_PHONE_LENGTH)
}
export const formatBrazilianPhoneInput = (value: string): string => {
const digits = sanitizeBrazilianPhoneInput(value)
if (!digits) return ''
if (digits.length <= 2) return `(${digits}`
if (digits.length <= 7) return `(${digits.slice(0, 2)}) ${digits.slice(2)}`
return `(${digits.slice(0, 2)}) ${digits.slice(2, 7)}-${digits.slice(7)}`
}
export const normalizeBrazilianPhone = (value: string): string | null => {
let digits = value.replace(/\D/g, '')
if (digits.length === BRAZILIAN_MOBILE_PHONE_LENGTH + BRAZIL_COUNTRY_CODE.length) {
if (!digits.startsWith(BRAZIL_COUNTRY_CODE)) return null
digits = digits.slice(BRAZIL_COUNTRY_CODE.length)
}
if (!/^[1-9]{2}9\d{8}$/.test(digits)) return null
return digits
}
/** Display formatting for a normalized 11-digit mobile: (71) 99999-9999. */
export const formatBrazilianPhoneDisplay = (phone: string): string =>
phone.replace(/^(\d{2})(\d{5})(\d{4})$/, '($1) $2-$3')
export const buildWhatsAppUrl = (phone: string, message?: string): string => {
const normalizedPhone = normalizeBrazilianPhone(phone)
if (!normalizedPhone) {
throw new Error('Celular brasileiro inválido.')
}
const url = new URL(`https://wa.me/${BRAZIL_COUNTRY_CODE}${normalizedPhone}`)
if (message) {
url.searchParams.set('text', message)
}
return url.toString()
}
/** `wa.me` href for a row's phone, or `null` when it doesn't normalize — the shared guard behind every per-row WhatsApp button in the campaign lists. */
export const whatsAppHrefForPhone = (phone: string | null): string | null => {
if (!phone || !normalizeBrazilianPhone(phone)) return null
return buildWhatsAppUrl(phone)
}