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
JavaScript
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);
}
}
}