Selector de teléfonos en asignados y calendario, priorizando móviles sobre fijos

This commit is contained in:
2026-08-27 07:05:13 +00:00
parent b33c65093b
commit fd2dea56a6
2 changed files with 75 additions and 8 deletions

View File

@@ -120,6 +120,7 @@
</div> </div>
<input type="hidden" id="detId"> <input type="hidden" id="detId">
<input type="hidden" id="detPhoneRaw"> <input type="hidden" id="detPhoneRaw">
<div id="phoneSelectorRow" class="hidden flex items-center gap-2 mb-3 overflow-x-auto no-scrollbar"></div>
<div class="grid grid-cols-2 gap-3 mb-6"> <div class="grid grid-cols-2 gap-3 mb-6">
<button onclick="callClient()" class="bg-blue-50 border border-blue-100 text-blue-600 font-black py-3 rounded-2xl flex items-center justify-center gap-2 active:scale-95 transition-transform shadow-sm"> <button onclick="callClient()" class="bg-blue-50 border border-blue-100 text-blue-600 font-black py-3 rounded-2xl flex items-center justify-center gap-2 active:scale-95 transition-transform shadow-sm">
<i data-lucide="phone" class="w-5 h-5"></i> <i data-lucide="phone" class="w-5 h-5"></i>
@@ -675,9 +676,16 @@ function renderServices(servicesToRender = localServices) {
document.getElementById('detName').innerText = raw["Nombre Cliente"] || "Asegurado"; document.getElementById('detName').innerText = raw["Nombre Cliente"] || "Asegurado";
document.getElementById('detAddress').innerText = `${raw["Dirección"] || ""}, ${raw["Población"] || ""}`; document.getElementById('detAddress').innerText = `${raw["Dirección"] || ""}, ${raw["Población"] || ""}`;
// 📞 Usamos los teléfonos ya extraídos y priorizados (móvil primero) por la API.
// Si por caché no vinieran, caemos al match simple de siempre.
const rawPhone = raw["Teléfono"] || raw["TELEFONOS"] || raw["TELEFONO"] || ""; const rawPhone = raw["Teléfono"] || raw["TELEFONOS"] || raw["TELEFONO"] || "";
const matchPhone = String(rawPhone).match(/[6789]\d{8}/); const matchPhone = String(rawPhone).match(/[6789]\d{8}/);
document.getElementById('detPhoneRaw').value = matchPhone ? matchPhone[0] : ""; const fallbackPhone = matchPhone ? matchPhone[0] : "";
const detailPhones = Array.isArray(s.phones) && s.phones.length > 0
? s.phones
: (fallbackPhone ? [{ number: fallbackPhone, isMobile: /^[67]/.test(fallbackPhone), horario: '', contacto: '' }] : []);
document.getElementById('detPhoneRaw').value = detailPhones[0]?.number || "";
renderPhoneSelector(detailPhones);
document.getElementById('durationInput').value = "60"; document.getElementById('durationInput').value = "60";
pickerSelectedDate = ""; pickerSelectedDate = "";
pickerSelectedTime = ""; pickerSelectedTime = "";
@@ -870,6 +878,29 @@ function renderServices(servicesToRender = localServices) {
if (phone) window.open(`https://wa.me/34${phone}`, '_blank'); if (phone) window.open(`https://wa.me/34${phone}`, '_blank');
else alert("No hay un teléfono válido guardado."); else alert("No hay un teléfono válido guardado.");
} }
// 📞 Cuando el servicio trae más de un teléfono (típico de HomeServe), pintamos un
// selector de chips para que el operario elija cuál usar antes de Llamar/WhatsApp.
// Con un solo teléfono no mostramos nada (para no añadir ruido visual de más).
function renderPhoneSelector(phones) {
const row = document.getElementById('phoneSelectorRow');
if (!row) return;
if (!phones || phones.length <= 1) { row.innerHTML = ''; row.classList.add('hidden'); return; }
const active = document.getElementById('detPhoneRaw').value;
row.innerHTML = phones.map(p => {
const isActive = p.number === active;
return `
<button type="button" onclick="selectPhone('${p.number}')" class="shrink-0 flex items-center gap-1.5 px-3 py-1.5 rounded-full border text-[10px] font-black uppercase tracking-widest ${isActive ? 'bg-primary-dynamic text-white border-primary-dynamic' : 'bg-white text-slate-500 border-slate-200'}">
<i data-lucide="${p.isMobile ? 'smartphone' : 'phone'}" class="w-3 h-3"></i> ${p.number}
</button>`;
}).join('');
row.classList.remove('hidden');
lucide.createIcons();
}
function selectPhone(number) {
document.getElementById('detPhoneRaw').value = number;
const s = localServices.find(x => String(x.id) === String(document.getElementById('detId').value));
renderPhoneSelector(Array.isArray(s?.phones) && s.phones.length > 0 ? s.phones : [{number, isMobile:/^[67]/.test(number)}]);
}
async function saveAppointment() { async function saveAppointment() {
const id = document.getElementById('detId').value; const id = document.getElementById('detId').value;
const duration = document.getElementById('durationInput').value; const duration = document.getElementById('durationInput').value;
@@ -981,7 +1012,9 @@ function renderServices(servicesToRender = localServices) {
id: s.id, type: 'sin_cita', address, id: s.id, type: 'sin_cita', address,
name: raw["Nombre Cliente"] || raw["CLIENTE"] || "Asegurado", name: raw["Nombre Cliente"] || raw["CLIENTE"] || "Asegurado",
company: raw["Compañía"] || raw["Procedencia"] || "Particular", company: raw["Compañía"] || raw["Procedencia"] || "Particular",
phone: extractPhone(raw), isUrgent: !!s.is_urgent // 📞 Preferimos el teléfono ya priorizado (móvil primero) que manda la API;
// si no vino (caché vieja), caemos al match simple de siempre.
phone: (Array.isArray(s.phones) && s.phones[0]?.number) || extractPhone(raw), isUrgent: !!s.is_urgent
}); });
}); });
pendingRequests.forEach(req => { pendingRequests.forEach(req => {
@@ -1124,6 +1157,7 @@ function renderServices(servicesToRender = localServices) {
<div class="flex flex-col gap-1.5 shrink-0"> <div class="flex flex-col gap-1.5 shrink-0">
${dirUrl ? `<a href="${dirUrl}" target="_blank" onclick="event.stopPropagation()" class="w-8 h-8 bg-blue-50 border border-blue-100 text-blue-600 rounded-lg flex items-center justify-center"><i data-lucide="navigation" class="w-4 h-4"></i></a>` : ''} ${dirUrl ? `<a href="${dirUrl}" target="_blank" onclick="event.stopPropagation()" class="w-8 h-8 bg-blue-50 border border-blue-100 text-blue-600 rounded-lg flex items-center justify-center"><i data-lucide="navigation" class="w-4 h-4"></i></a>` : ''}
${r.phone ? `<a href="tel:+34${r.phone}" onclick="event.stopPropagation()" class="w-8 h-8 bg-slate-50 border border-slate-200 text-slate-600 rounded-lg flex items-center justify-center"><i data-lucide="phone" class="w-4 h-4"></i></a>` : ''} ${r.phone ? `<a href="tel:+34${r.phone}" onclick="event.stopPropagation()" class="w-8 h-8 bg-slate-50 border border-slate-200 text-slate-600 rounded-lg flex items-center justify-center"><i data-lucide="phone" class="w-4 h-4"></i></a>` : ''}
${r.phone ? `<a href="https://wa.me/34${r.phone}" target="_blank" onclick="event.stopPropagation()" class="w-8 h-8 bg-emerald-50 border border-emerald-100 text-emerald-600 rounded-lg flex items-center justify-center"><i data-lucide="message-circle" class="w-4 h-4"></i></a>` : ''}
</div> </div>
</div> </div>
`; `;

View File

@@ -171,6 +171,8 @@
<i data-lucide="external-link" class="w-4 h-4"></i> Copiar y Abrir Portal <i data-lucide="external-link" class="w-4 h-4"></i> Copiar y Abrir Portal
</button> </button>
<div id="phoneSelectorRow" class="hidden flex items-center gap-2 mb-3 overflow-x-auto no-scrollbar"></div>
<button onclick="callClient()" class="w-full bg-primary-dynamic text-white font-black py-4 rounded-2xl shadow-xl flex items-center justify-center gap-3 uppercase text-sm tracking-widest active:scale-95 transition-all"> <button onclick="callClient()" class="w-full bg-primary-dynamic text-white font-black py-4 rounded-2xl shadow-xl flex items-center justify-center gap-3 uppercase text-sm tracking-widest active:scale-95 transition-all">
<i data-lucide="phone" class="w-5 h-5 fill-current"></i> Llamar al Cliente <i data-lucide="phone" class="w-5 h-5 fill-current"></i> Llamar al Cliente
</button> </button>
@@ -1010,9 +1012,16 @@
const fullAddress = `${raw["Dirección"] || ""}, ${raw["Código Postal"] || ""} ${raw["Población"] || ""}`; const fullAddress = `${raw["Dirección"] || ""}, ${raw["Código Postal"] || ""} ${raw["Población"] || ""}`;
document.getElementById('detAddress').innerText = fullAddress; document.getElementById('detAddress').innerText = fullAddress;
// 📞 Usamos los teléfonos ya extraídos y priorizados (móvil primero) por la API.
// Si por caché no vinieran, caemos al match simple de siempre.
const rawPhone = raw["Teléfono"] || raw["TELEFONOS"] || raw["TELEFONO"] || ""; const rawPhone = raw["Teléfono"] || raw["TELEFONOS"] || raw["TELEFONO"] || "";
const matchPhone = String(rawPhone).match(/[6789]\d{8}/); const matchPhone = String(rawPhone).match(/[6789]\d{8}/);
document.getElementById('detPhoneRaw').value = matchPhone ? matchPhone[0] : ""; const fallbackPhone = matchPhone ? matchPhone[0] : "";
const detailPhones = Array.isArray(s.phones) && s.phones.length > 0
? s.phones
: (fallbackPhone ? [{ number: fallbackPhone, isMobile: /^[67]/.test(fallbackPhone), horario: '', contacto: '' }] : []);
document.getElementById('detPhoneRaw').value = detailPhones[0]?.number || "";
renderPhoneSelector(detailPhones);
const banner = document.getElementById('urgentBanner'); const banner = document.getElementById('urgentBanner');
if (s.is_urgent) banner.classList.remove('hidden'); if (s.is_urgent) banner.classList.remove('hidden');
@@ -1394,6 +1403,30 @@
} else { alert("Sin teléfono"); } } else { alert("Sin teléfono"); }
} }
// 📞 Cuando el servicio trae más de un teléfono (típico de HomeServe), pintamos un
// selector de chips para que el operario elija cuál usar antes de Llamar/WhatsApp.
// Con un solo teléfono no mostramos nada (para no añadir ruido visual de más).
function renderPhoneSelector(phones) {
const row = document.getElementById('phoneSelectorRow');
if (!row) return;
if (!phones || phones.length <= 1) { row.innerHTML = ''; row.classList.add('hidden'); return; }
const active = document.getElementById('detPhoneRaw').value;
row.innerHTML = phones.map(p => {
const isActive = p.number === active;
return `
<button type="button" onclick="selectPhone('${p.number}')" class="shrink-0 flex items-center gap-1.5 px-3 py-1.5 rounded-full border text-[10px] font-black uppercase tracking-widest ${isActive ? 'bg-primary-dynamic text-white border-primary-dynamic' : 'bg-white text-slate-500 border-slate-200'}">
<i data-lucide="${p.isMobile ? 'smartphone' : 'phone'}" class="w-3 h-3"></i> ${p.number}
</button>`;
}).join('');
row.classList.remove('hidden');
lucide.createIcons();
}
function selectPhone(number) {
document.getElementById('detPhoneRaw').value = number;
const s = localServices.find(x => String(x.id) === String(document.getElementById('detId').value));
renderPhoneSelector(Array.isArray(s?.phones) && s.phones.length > 0 ? s.phones : [{number, isMobile:/^[67]/.test(number)}]);
}
async function copyAndOpenPortal() { async function copyAndOpenPortal() {
const btn = document.getElementById('btnPortal'); const btn = document.getElementById('btnPortal');
const originalHtml = btn.innerHTML; const originalHtml = btn.innerHTML;