Actualizar servicios.html

This commit is contained in:
2026-03-03 08:37:02 +00:00
parent bb62396aa4
commit 2b14f602b6

View File

@@ -27,6 +27,10 @@
/* Estilos base para formularios mejorados */
.input-modern { @apply w-full bg-slate-50 border border-slate-200 px-4 py-3 rounded-xl text-sm font-semibold text-slate-700 outline-none transition-all focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-100; }
.label-modern { @apply block text-[10px] font-black text-slate-500 uppercase tracking-widest mb-1.5 ml-1; }
/* Estilos para el Modo Edición del Modal */
.input-editable { border-bottom: 2px solid #3b82f6 !important; background: #eff6ff !important; border-radius: 0.5rem !important; padding: 4px 8px !important; pointer-events: auto !important; }
.input-readonly { border: none !important; background: transparent !important; pointer-events: none; outline: none; }
</style>
</head>
<body class="bg-slate-50 text-slate-800 font-sans antialiased text-left">
@@ -132,7 +136,6 @@
<div class="grid grid-cols-1 md:grid-cols-12 gap-8">
<div class="md:col-span-7 space-y-6">
<div class="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm space-y-4">
<h4 class="font-black text-slate-800 uppercase text-xs flex items-center gap-2 border-b border-slate-100 pb-3 mb-4">
<i data-lucide="user" class="w-4 h-4 text-blue-500"></i> Datos del Cliente
@@ -141,7 +144,7 @@
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label class="label-modern">Teléfono</label>
<input type="tel" id="nPhone" placeholder="Ej: 600123456" class="input-modern" required>
<input type="tel" id="nPhone" oninput="searchClientByPhone(this.value)" placeholder="Ej: 600123456" class="input-modern" required>
</div>
<div>
<label class="label-modern">Nombre Completo</label>
@@ -151,6 +154,18 @@
<div>
<label class="label-modern">Dirección Completa</label>
<input type="text" id="nAddr" placeholder="Calle, número, piso, población..." class="input-modern" required>
<div id="addrSuggestions" class="hidden mt-2 p-2 bg-amber-50 border border-amber-200 rounded-lg text-[10px] font-bold text-amber-700">⚠️ Cliente con otras direcciones registradas.</div>
</div>
<div class="pt-2">
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" id="isCompanyCheck" onchange="toggleCompanyFields(this.checked)" class="w-5 h-5 rounded text-blue-600">
<span class="text-xs font-black text-slate-700 uppercase">¿Es de Compañía de Seguros?</span>
</label>
<div id="companyFields" class="hidden mt-4 space-y-4 p-4 bg-blue-50/30 rounded-xl border border-blue-100">
<select id="nCompanySelect" class="input-modern bg-white"><option value="">Seleccionar compañía...</option></select>
<input type="text" id="nExpRef" onblur="checkDuplicateRef(this.value)" placeholder="Nº Expediente" class="input-modern bg-white uppercase">
<p id="refAlert" class="hidden text-[10px] text-red-600 font-bold mt-1 uppercase">⚠️ Referencia ya existente</p>
</div>
</div>
</div>
@@ -159,16 +174,14 @@
<i data-lucide="align-left" class="w-4 h-4 text-amber-500"></i> Detalles de la Avería
</h4>
<label class="label-modern">Descripción</label>
<textarea id="nDesc" placeholder="Describe el problema a reparar..." rows="4" class="input-modern resize-none"></textarea>
<textarea id="nDesc" placeholder="Describe el problema a reparar..." rows="6" class="input-modern resize-none"></textarea>
</div>
</div>
<div class="md:col-span-5 space-y-6">
<div class="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm space-y-4">
<h4 class="font-black text-slate-800 uppercase text-xs flex items-center gap-2 border-b border-slate-100 pb-3 mb-4">
<i data-lucide="hammer" class="w-4 h-4 text-purple-500"></i> Asignación
<i data-lucide="hammer" class="w-4 h-4 text-purple-500"></i> Asignación y Tiempo
</h4>
<div>
@@ -181,7 +194,7 @@
</div>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="grid grid-cols-1 gap-4">
<div>
<label class="label-modern">Operario</label>
<div class="relative">
@@ -192,20 +205,16 @@
</div>
</div>
<div>
<label class="label-modern">Duración (Estimada)</label>
<label class="label-modern">Duración Estimada</label>
<div class="relative">
<select id="nDuration" class="input-modern appearance-none cursor-pointer pr-8">
<select id="nDuration" class="input-modern font-black text-blue-600 uppercase appearance-none cursor-pointer pr-8">
<option value="15">15 min</option>
<option value="30">30 min</option>
<option value="45">45 min</option>
<option value="60" selected>1 hora</option>
<option value="75">1 h 15 min</option>
<option value="90">1 h 30 min</option>
<option value="105">1 h 45 min</option>
<option value="90">1.5 horas</option>
<option value="120">2 horas</option>
<option value="150">2 h 30 min</option>
<option value="180">3 horas</option>
<option value="210">3 h 30 min</option>
<option value="240">4 horas (Max)</option>
</select>
<i data-lucide="clock" class="w-4 h-4 absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none"></i>
@@ -232,7 +241,6 @@
<i data-lucide="zap" class="w-5 h-5 text-amber-400"></i>
</button>
</div>
</div>
</div>
</form>
@@ -242,7 +250,7 @@
<div id="detailModal" class="fixed inset-0 bg-slate-900/90 hidden z-[120] flex items-center justify-center backdrop-blur-sm p-4 text-left">
<div class="bg-white rounded-[2rem] shadow-2xl w-full max-w-4xl overflow-hidden flex flex-col fade-in relative">
<button onclick="closeDetailModal()" class="absolute top-6 right-6 text-slate-400 hover:text-red-500 bg-white shadow-sm border border-slate-200 p-2.5 rounded-full transition-all hover:bg-red-50 hover:border-red-100 z-10"><i data-lucide="x" class="w-5 h-5"></i></button>
<button onclick="closeDetailModal()" class="absolute top-6 right-6 text-slate-400 hover:text-red-500 bg-white shadow-sm border border-slate-200 p-2.5 rounded-full transition-all hover:bg-red-50 hover:border-red-100 z-20"><i data-lucide="x" class="w-5 h-5"></i></button>
<div class="p-6 border-b border-slate-100 flex justify-between items-center bg-slate-50/50 pr-24">
<div class="flex items-center gap-3">
@@ -263,38 +271,35 @@
<input type="hidden" id="detId">
<input type="hidden" id="detCp">
<div class="md:col-span-3 space-y-4">
<div class="bg-slate-50 p-5 rounded-[1.5rem] border border-slate-100 space-y-4">
<div>
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest">Asegurado / Cliente</p>
<input type="text" id="editName" class="input-readonly w-full font-black text-slate-800 text-lg uppercase" readonly>
<div class="md:col-span-3 space-y-4">
<div class="bg-slate-50 p-5 rounded-[1.5rem] border border-slate-100 space-y-4">
<div>
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest">Asegurado / Cliente</p>
<input type="text" id="editName" class="input-readonly w-full font-black text-slate-800 text-lg uppercase mt-0.5" readonly>
<div class="flex items-center gap-4 mt-1.5">
<input type="tel" id="editPhone" class="input-readonly text-sm text-blue-600 font-black" readonly>
</div>
</div>
<hr class="border-slate-200">
<div>
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest">Ubicación y Dirección</p>
<textarea id="editAddr" rows="2" class="input-readonly w-full text-sm font-bold text-slate-600 resize-none uppercase" readonly></textarea>
</div>
</div>
<div>
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest mb-2 ml-2 block">Descripción de la Avería</p>
<textarea id="editDesc" rows="6" class="w-full bg-amber-50/60 border border-amber-100 p-5 rounded-[1.5rem] text-sm font-medium text-slate-700 shadow-inner outline-none" readonly></textarea>
</div>
</div>
<div>
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest mb-2 ml-2">Descripción de la Avería</p>
<textarea id="editDesc" rows="6" class="w-full bg-amber-50/60 border border-amber-100 p-5 rounded-[1.5rem] text-sm font-medium text-slate-700 shadow-inner outline-none" readonly></textarea>
</div>
</div>
<div class="flex items-center gap-4 mt-1.5">
<div class="flex items-center gap-1.5">
<i data-lucide="phone" class="w-3.5 h-3.5 text-blue-600"></i>
<input type="tel" id="editPhone" class="input-readonly text-sm text-blue-600 font-black w-full" readonly>
</div>
<button onclick="copyClientPortalLink()" id="btnPortalLink" class="text-[10px] font-black bg-blue-50 border border-blue-100 hover:bg-blue-600 hover:text-white text-blue-600 px-3 py-1.5 rounded-lg flex items-center gap-1.5 transition-all shadow-sm active:scale-95 shrink-0">
<i data-lucide="link" class="w-3 h-3"></i> Copiar Portal
</button>
</div>
</div>
<hr class="border-slate-200">
<div>
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest">Ubicación y Dirección</p>
<div class="flex items-start gap-1.5 mt-1">
<i data-lucide="map-pin" class="w-4 h-4 mt-0.5 text-slate-400 shrink-0"></i>
<textarea id="editAddr" rows="2" class="input-readonly w-full text-sm font-bold text-slate-600 resize-none uppercase" readonly></textarea>
</div>
</div>
</div>
<div>
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest mb-2 ml-2">Descripción de la Avería</p>
<div class="bg-amber-50/60 border border-amber-100 p-5 rounded-[1.5rem] text-sm font-medium text-slate-700 min-h-[120px] max-h-48 overflow-y-auto no-scrollbar shadow-inner leading-relaxed" id="detDesc"></div>
<textarea id="editDesc" rows="6" class="w-full bg-amber-50/60 border border-amber-100 p-5 rounded-[1.5rem] text-sm font-medium text-slate-700 shadow-inner leading-relaxed outline-none" readonly></textarea>
</div>
</div>
@@ -375,7 +380,19 @@
</button>
</div>
</div>
</div>
</div>
<div class="p-4 bg-slate-50 border-t border-slate-100 flex justify-end items-center px-8 gap-3">
<div id="viewActions">
<button onclick="enableEditing()" id="btnEnableEdit" class="text-slate-400 hover:text-blue-600 flex items-center gap-2 transition-all group">
<span class="text-[10px] font-black uppercase tracking-widest">Editar Ficha</span>
<div class="bg-white border border-slate-200 p-2 rounded-xl shadow-sm group-hover:border-blue-200 group-hover:bg-blue-50 transition-all"><i data-lucide="edit-3" class="w-4 h-4"></i></div>
</button>
</div>
<div id="editActions" class="hidden flex gap-3">
<button onclick="cancelEditing()" class="px-6 py-2 rounded-xl text-[10px] font-black uppercase tracking-widest text-slate-400 hover:bg-slate-100 transition-all">Cancelar</button>
<button onclick="saveFullEdit()" class="px-8 py-3 bg-blue-600 text-white rounded-xl text-[10px] font-black uppercase tracking-widest shadow-lg shadow-blue-100 active:scale-95 transition-all">Guardar Cambios</button>
</div>
</div>
</div>
@@ -557,29 +574,23 @@
const filteredData = localData.filter(s => {
const raw = s.raw_data || {};
const stateInfo = getServiceStateInfo(s);
s._stateInfo = stateInfo; // Guardamos info para el render
s._stateInfo = stateInfo;
// LÓGICA DE CONTADORES REVOLUCIONADA:
const stName = stateInfo.name.toLowerCase();
// 1. SIN ASIGNAR: No tiene nombre de operario O está en bolsa
if (!s.assigned_name || stateInfo.id === 'bolsa' || stName.includes('asignar')) {
kpiUnassigned++;
}
// 2. INCIDENCIA: El estado tiene la palabra clave
else if (stName.includes('incidencia') || stName.includes('pausa')) {
kpiIncident++;
}
// 3. AGENDADOS: Tiene fecha puesta y no es un estado final
else if (raw.scheduled_date && raw.scheduled_date !== "" && !stateInfo.is_final) {
kpiScheduled++;
}
// 4. ESPERA CLIENTE: No tiene cita pero ya tiene técnico (o estado específico)
else if (!stateInfo.is_final && (!raw.scheduled_date || stName.includes('espera'))) {
else if (!stateInfo.is_final && !raw.scheduled_date) {
kpiWaiting++;
}
// Filtros de búsqueda
const name = (raw["Nombre Cliente"] || raw["CLIENTE"] || "").toLowerCase();
const ref = (s.service_ref || "").toLowerCase();
const matchesSearch = searchTerm === "" || name.includes(searchTerm) || ref.includes(searchTerm);
@@ -597,7 +608,6 @@
return matchesSearch && matchesOp && matchesWeek && matchesStatus;
});
// Actualizamos la vista con los números reales
document.getElementById('kpi-unassigned').innerText = kpiUnassigned;
document.getElementById('kpi-scheduled').innerText = kpiScheduled;
document.getElementById('kpi-waiting').innerText = kpiWaiting;
@@ -620,7 +630,7 @@
const addr = raw["Dirección"] || raw["DOMICILIO"] || "---";
const pop = raw["Población"] || raw["POBLACION-PROVINCIA"] || "";
const fullAddr = `${addr} ${pop}`.trim();
const cita = raw.scheduled_date ? `${raw.scheduled_date} | ${raw.scheduled_time}` : 'Pendiente Cita';
const cita = raw.scheduled_date ? `${raw.scheduled_date.split('-').reverse().slice(0,2).join('/')} | ${raw.scheduled_time}` : 'Pte. Cita';
const companyName = raw['Compañía'] || raw['COMPAÑIA'] || raw['Procedencia'] || (s.provider === 'MANUAL' ? 'PARTICULAR' : 'ASEGURADORA');
const isUrgent = s.is_urgent === true || (raw['Urgente'] && raw['Urgente'].toLowerCase() === 'sí') || (raw['URGENTE'] && raw['URGENTE'].toLowerCase() === 'si');
@@ -660,16 +670,25 @@
</div>
</div>
<div class="flex items-center justify-between mt-4 pt-4 border-t border-slate-100">
<div class="flex items-center gap-2 min-w-0">
<div class="bg-slate-100 p-1.5 rounded-lg text-slate-500 shrink-0"><i data-lucide="hard-hat" class="w-3.5 h-3.5"></i></div>
<span class="text-[10px] font-black text-slate-600 uppercase truncate" title="${s.assigned_name || 'Sin asignar'}">${s.assigned_name || 'Sin asignar'}</span>
<div class="flex items-center justify-between mt-4 pt-4 border-t border-slate-100 gap-2">
<div class="flex items-center gap-1 min-w-0 flex-1">
<div class="bg-slate-100 p-1 rounded-lg text-slate-500 shrink-0"><i data-lucide="hard-hat" class="w-3 h-3"></i></div>
<span class="text-[10px] font-black text-slate-600 uppercase truncate flex-1" style="max-width: 70px;" title="${s.assigned_name || 'Sin asignar'}">${s.assigned_name || 'Sin asignar'}</span>
<div class="flex items-center gap-0.5 shrink-0">
<button onclick="event.stopPropagation(); window.location.href='trazabilidad.html?id=${s.id}'" class="p-1.5 text-slate-300 hover:text-blue-600 transition-colors" title="Ver Historial">
<i data-lucide="history" class="w-4 h-4"></i>
</button>
<button onclick="event.stopPropagation(); openDetail(${s.id}, true)" class="p-1.5 text-slate-300 hover:text-amber-600 transition-colors" title="Editar Ficha">
<i data-lucide="edit-3" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="flex items-center gap-1 text-blue-600 shrink-0 bg-blue-50 px-2 py-1 rounded-md border border-blue-100">
<i data-lucide="${iconEstado}" class="w-3 h-3"></i>
<span class="text-[9px] font-black uppercase whitespace-nowrap">${raw.scheduled_date ? cita.split('|')[0] : 'Pte. Cita'}</span>
</div>
${raw.scheduled_date ? `
<div class="flex items-center gap-1.5 text-blue-600 shrink-0 ml-2 bg-blue-50 px-2 py-1 rounded-md border border-blue-100">
<i data-lucide="${iconEstado}" class="w-3.5 h-3.5"></i>
<span class="text-[9px] font-black uppercase">${cita}</span>
</div>` : ''}
</div>
</div>`;
}
@@ -698,7 +717,7 @@
setTimeout(() => { toast.classList.add('hidden'); }, 3500);
}
function openDetail(id) {
function openDetail(id, startInEditMode = false) {
const s = localData.find(x => x.id === id);
if (!s) return;
const raw = s.raw_data;
@@ -708,26 +727,21 @@
const companyName = raw['Compañía'] || raw['COMPAÑIA'] || raw['Procedencia'] || "Particular";
document.getElementById('detCompany').innerText = companyName;
document.getElementById('detName').innerText = raw["Nombre Cliente"] || raw["CLIENTE"] || "Asegurado Sin Nombre";
// RELLENADO DE CAMPOS PARA EL EDITOR Y VISTA
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "Asegurado Sin Nombre";
if(document.getElementById('editName')) document.getElementById('editName').value = clientName;
const rawPhone = raw["Teléfono"] || raw["TELEFONOS"] || raw["TELEFONO"] || "";
const matchPhone = rawPhone.toString().match(/[6789]\d{8}/);
const singlePhone = matchPhone ? matchPhone[0] : "";
if(document.getElementById('editPhone')) document.getElementById('editPhone').value = singlePhone;
if (singlePhone) {
document.getElementById('detPhone').innerText = singlePhone;
document.getElementById('detPhoneLink').href = `tel:+34${singlePhone}`;
document.getElementById('detPhoneLink').classList.remove('text-slate-400', 'pointer-events-none');
document.getElementById('detPhoneLink').classList.add('text-blue-600');
} else {
document.getElementById('detPhone').innerText = "Sin Teléfono";
document.getElementById('detPhoneLink').href = "#";
document.getElementById('detPhoneLink').classList.remove('text-blue-600');
document.getElementById('detPhoneLink').classList.add('text-slate-400', 'pointer-events-none');
}
const fullAddr = `${raw["Dirección"] || ""} ${raw["Población"] || ""}`.trim();
if(document.getElementById('editAddr')) document.getElementById('editAddr').value = fullAddr;
document.getElementById('detAddrText').innerText = `${raw["Dirección"] || "Dirección no especificada"} ${raw["Población"] || ""}`;
document.getElementById('detDesc').innerHTML = (raw["Descripción"] || raw["DESCRIPCION"] || "Sin notas.").replace(/\n/g, '<br>');
const descContent = raw["Descripción"] || raw["DESCRIPCION"] || "Sin notas.";
if(document.getElementById('editDesc')) document.getElementById('editDesc').value = descContent;
const stateInfo = s._stateInfo;
@@ -761,6 +775,13 @@
}
document.getElementById('detailModal').classList.remove('hidden');
if (startInEditMode) {
enableEditing();
} else {
cancelEditing();
}
lucide.createIcons();
}
@@ -876,6 +897,8 @@
async function saveNewService(e) {
e.preventDefault();
const action = e.submitter.value;
const is_company = document.getElementById('isCompanyCheck').checked;
const data = {
phone: document.getElementById('nPhone').value,
name: document.getElementById('nName').value,
@@ -883,19 +906,70 @@
description: document.getElementById('nDesc').value,
guild_id: document.getElementById('nGuild').value,
assigned_to: document.getElementById('nWorker').value || null,
duration_minutes: document.getElementById('nDuration').value // <--- CAPTURA DE DURACIÓN
duration_minutes: document.getElementById('nDuration').value,
is_company: is_company,
company_name: is_company ? document.getElementById('nCompanySelect').value : 'Particular',
company_ref: is_company ? document.getElementById('nExpRef').value : null,
mode: action
};
try {
const res = await fetch(`${API_URL}/services/manual-high`, {
method: 'POST', headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
body: JSON.stringify({ ...data, mode: action })
body: JSON.stringify(data)
});
if (res.ok) { closeCreateModal(); refreshPanel(); }
if (res.ok) { closeCreateModal(); refreshPanel(); showToast("✅ Servicio guardado correctamente"); }
} catch(e) { alert("Error al guardar"); }
}
function closeDetailModal() { document.getElementById('detailModal').classList.add('hidden'); }
function openCreateModal() { document.getElementById('createModal').classList.remove('hidden'); }
async function openCreateModal() {
document.getElementById('createModal').classList.remove('hidden');
document.getElementById('isCompanyCheck').checked = false;
toggleCompanyFields(false);
try {
const res = await fetch(`${API_URL}/companies`, {
headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` }
});
const data = await res.json();
const sel = document.getElementById('nCompanySelect');
sel.innerHTML = '<option value="">Seleccionar compañía...</option>';
data.companies.forEach(c => {
sel.innerHTML += `<option value="${c.name}">${c.name.toUpperCase()}</option>`;
});
} catch(e) {}
lucide.createIcons();
}
function toggleCompanyFields(show) {
const fields = document.getElementById('companyFields');
fields.classList.toggle('hidden', !show);
if(!show) {
document.getElementById('nExpRef').value = "";
document.getElementById('refAlert').classList.add('hidden');
}
}
async function checkDuplicateRef(ref) {
if(!ref) return;
const res = await fetch(`${API_URL}/services/check-ref?ref=${ref}`, {
headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` }
});
const data = await res.json();
const alertEl = document.getElementById('refAlert');
const inputEl = document.getElementById('nExpRef');
if(data.exists) {
alertEl.classList.remove('hidden');
inputEl.classList.add('border-red-500', 'bg-red-50');
} else {
alertEl.classList.add('hidden');
inputEl.classList.remove('border-red-500', 'bg-red-50');
}
}
function closeCreateModal() { document.getElementById('createModal').classList.add('hidden'); }
async function loadGuilds() {
@@ -917,9 +991,9 @@
}
async function copyClientPortalLink() {
const phone = document.getElementById('detPhone').innerText;
const name = document.getElementById('detName').innerText;
const addr = document.getElementById('detAddrText').innerText;
const phone = document.getElementById('editPhone').value;
const name = document.getElementById('editName').value;
const addr = document.getElementById('editAddr').value;
if (!phone || phone === "Sin Teléfono") {
showToast("No hay un teléfono válido para este cliente.", "warning");
@@ -955,7 +1029,7 @@
setTimeout(() => {
btn.innerHTML = originalHtml;
btn.className = "text-[10px] font-black bg-blue-50 border border-blue-100 hover:bg-blue-600 hover:text-white text-blue-600 px-3 py-1.5 rounded-lg flex items-center gap-1.5 transition-all shadow-sm active:scale-95";
btn.className = "text-[10px] font-black bg-blue-50 border border-blue-100 hover:bg-blue-600 hover:text-white text-blue-600 px-3 py-1.5 rounded-lg flex items-center gap-1.5 transition-all shadow-sm active:scale-95 shrink-0";
lucide.createIcons();
}, 3000);
} else {
@@ -970,6 +1044,88 @@
lucide.createIcons();
}
}
async function searchClientByPhone(phone) {
if (phone.length < 9) {
document.getElementById('addrSuggestions').classList.add('hidden');
return;
}
try {
const res = await fetch(`${API_URL}/clients/search?phone=${phone}`, {
headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` }
});
const data = await res.json();
if (data.ok && data.client) {
const nameInput = document.getElementById('nName');
if (!nameInput.value) {
nameInput.value = data.client.full_name;
nameInput.classList.add('bg-emerald-50');
}
const addrDiv = document.getElementById('addrSuggestions');
if (data.client.addresses && data.client.addresses.length > 0) {
addrDiv.classList.remove('hidden');
if (!document.getElementById('nAddr').value) {
document.getElementById('nAddr').value = data.client.addresses[0];
}
}
}
} catch (e) { console.error("Error en buscador rápido:", e); }
}
// --- FUNCIONES DEL EDITOR ---
function enableEditing() {
document.getElementById('viewActions').classList.add('hidden');
document.getElementById('editActions').classList.remove('hidden');
['editName', 'editPhone', 'editAddr', 'editDesc'].forEach(id => {
const el = document.getElementById(id);
if(el) {
el.readOnly = false;
el.classList.add('input-editable');
el.classList.remove('input-readonly');
}
});
}
function cancelEditing() {
document.getElementById('viewActions').classList.remove('hidden');
document.getElementById('editActions').classList.add('hidden');
['editName', 'editPhone', 'editAddr', 'editDesc'].forEach(id => {
const el = document.getElementById(id);
if(el) {
el.readOnly = true;
el.classList.add('input-readonly');
el.classList.remove('input-editable');
}
});
}
async function saveFullEdit() {
const id = document.getElementById('detId').value;
const payload = {
name: document.getElementById('editName').value,
phone: document.getElementById('editPhone').value,
address: document.getElementById('editAddr').value,
description: document.getElementById('editDesc').value
};
try {
const res = await fetch(`${API_URL}/providers/scraped/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem("token")}` },
body: JSON.stringify(payload)
});
if (res.ok) {
showToast("✅ Ficha actualizada");
cancelEditing();
refreshPanel();
}
} catch (e) { showToast("Error al guardar", "warning"); }
}
</script>
</body>
</html>