UNPKG

voip-click-to-call

Version:

Outil npm pour générer un système click-to-call VoIP compatible Asterisk et FreeSWITCH

152 lines (127 loc) 4.11 kB
function detectPhoneNumbers(text) { if (!text) return []; const phoneRegex = /(?:\+?\d{1,3}[\s.-]?)?\(?\d{1,4}\)?[\s.-]?\d{1,4}[\s.-]?\d{1,4}[\s.-]?\d{1,9}/g; const matches = text.match(phoneRegex); if (!matches) return []; return matches.map(phone => { return phone.replace(/[\s.\-()]/g, ''); }).filter((phone, index, self) => { return self.indexOf(phone) === index && phone.replace(/\D/g, '').length >= 8; }); } function formatPhoneNumber(phone) { const cleaned = phone.replace(/\D/g, ''); if (cleaned.length === 10 && cleaned.startsWith('0')) { return cleaned.replace(/(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/, '$1 $2 $3 $4 $5'); } else if (cleaned.length > 10) { if (cleaned.startsWith('33')) { return '+' + cleaned.replace(/(\d{2})(\d{1})(\d{2})(\d{2})(\d{2})(\d{2})/, '$1 $2 $3 $4 $5 $6'); } return '+' + cleaned; } return cleaned; } function detectPhoneNumbersInDOM(rootElement = document) { const phoneNumbers = new Set(); // Chercher les attributs data-phone const dataPhoneElements = rootElement.querySelectorAll('[data-phone]'); dataPhoneElements.forEach(el => { const phone = el.getAttribute('data-phone'); if (phone) { phoneNumbers.add(phone.replace(/\D/g, '')); } }); // Parcourir tous les nœuds texte const walker = document.createTreeWalker( rootElement, NodeFilter.SHOW_TEXT, null, false ); let node; while (node = walker.nextNode()) { const text = node.textContent; const phones = detectPhoneNumbers(text); phones.forEach(phone => phoneNumbers.add(phone)); } return Array.from(phoneNumbers); } function detectAndTransformPhones() { const phoneNumbers = detectPhoneNumbersInDOM(); phoneNumbers.forEach(phone => { const selector = `[data-voip-phone="${phone}"]`; if (document.querySelector(selector)) { return; } const walker = document.createTreeWalker( document.body, NodeFilter.SHOW_TEXT, null, false ); let node; while (node = walker.nextNode()) { const text = node.textContent; if (text.includes(phone) || text.replace(/\D/g, '').includes(phone)) { const parent = node.parentElement; if (parent && !parent.hasAttribute('data-voip-phone')) { const formatted = formatPhoneNumber(phone); const link = document.createElement('a'); link.href = '#'; link.className = 'phone-link'; link.textContent = formatted; link.setAttribute('data-voip-phone', phone); link.onclick = (e) => { e.preventDefault(); handlePhoneClick(phone); }; parent.replaceChild(link, node); } } } // Gérer les attributs data-phone document.querySelectorAll(`[data-phone="${phone}"]`).forEach(el => { if (!el.hasAttribute('data-voip-transformed')) { el.setAttribute('data-voip-transformed', 'true'); el.className = (el.className + ' phone-link').trim(); el.onclick = (e) => { e.preventDefault(); handlePhoneClick(phone); }; } }); }); } async function handlePhoneClick(phoneNumber) { const link = document.querySelector(`[data-voip-phone="${phoneNumber}"]`); if (link && link.classList.contains('calling')) { return; } if (link) { link.classList.add('calling'); } try { const response = await fetch(`${config.apiUrl}/api/call`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ phoneNumber }), }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || 'Erreur lors de l\'appel'); } console.log('✅ Appel initié:', data); if (link) { link.classList.remove('calling'); } } catch (error) { console.error('❌ Erreur:', error); if (link) { link.classList.remove('calling'); link.classList.add('error'); setTimeout(() => link.classList.remove('error'), 2000); } } }