Datos del Cliente
@@ -245,7 +247,6 @@
let allStatuses = [];
let currentServiceId = null;
let autocomplete;
- let currentServiceData = null; // Guardamos datos del servicio actual para edición
document.addEventListener("DOMContentLoaded", () => {
const token = localStorage.getItem("token");
@@ -272,12 +273,12 @@
document.getElementById('servicesListView').classList.remove('hidden');
fetchServices();
} else {
- // RESETEAR FORMULARIO SI ES NUEVO
if(document.getElementById('editServiceId').value !== "") {
- document.getElementById('editServiceId').value = ""; // Limpiar ID
+ document.getElementById('editServiceId').value = "";
document.querySelector('form').reset();
document.getElementById('formTitle').innerHTML = '
Alta de Nuevo Servicio';
- document.getElementById('sDate').valueAsDate = new Date(); // Reset fecha
+ document.getElementById('sDate').valueAsDate = new Date();
+ document.getElementById('sCreateStatus').disabled = false; // Reactivar al crear
lucide.createIcons();
}
document.getElementById('createServiceView').classList.remove('hidden');
@@ -285,16 +286,71 @@
}
}
- // --- FUNCIONES EDICIÓN Y BORRADO (NUEVAS) ---
+ // --- CARGA DE DATOS ---
+ async function fetchStatuses() {
+ try {
+ const res = await fetch(`${API_URL}/statuses`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
+ const data = await res.json();
+ if(data.ok) {
+ allStatuses = data.statuses;
+ const createSel = document.getElementById('sCreateStatus');
+ createSel.innerHTML = '';
+ allStatuses.forEach(s => {
+ const isDef = s.is_default ? 'selected' : '';
+ createSel.innerHTML += `
`;
+ });
+ }
+ } catch(e) {}
+ }
+
+ // MODIFICADO: Devuelve promesa y no borra si ya existen
+ async function loadCompanies() {
+ try {
+ const sel = document.getElementById('sCompanyId');
+ // Si ya tiene datos (>1 porque la primera es "--Seleccionar--"), no recargamos
+ if (sel.options.length > 1) return;
+
+ const res = await fetch(`${API_URL}/companies`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
+ const data = await res.json();
+ if (data.ok) {
+ sel.innerHTML = '
';
+ data.companies.forEach(c => sel.innerHTML += `
`);
+ }
+ } catch (e) {}
+ }
+
+ async function quickAddCompany() {
+ const name = prompt("Nombre de la nueva compañía:");
+ if(!name) return;
+ try {
+ const res = await fetch(`${API_URL}/companies`, {
+ method: 'POST',
+ headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
+ body: JSON.stringify({ name })
+ });
+ if(res.ok) { showToast("Compañía añadida"); document.getElementById('sCompanyId').innerHTML = ""; await loadCompanies(); }
+ } catch(e) { alert("Error"); }
+ }
+
+ // --- EDICIÓN Y LOGICA DE FORMULARIO ---
+ function toggleCompanyFields() {
+ const isChecked = document.getElementById('sIsCompany').checked;
+ const div = document.getElementById('companyFields');
+ if(isChecked) {
+ div.classList.remove('hidden');
+ loadCompanies();
+ } else {
+ div.classList.add('hidden');
+ }
+ }
+
async function editService() {
if(!currentServiceId) return;
-
- // Cargar datos completos si no los tenemos
try {
const res = await fetch(`${API_URL}/services/${currentServiceId}`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const json = await res.json();
if(json.ok) {
- fillEditForm(json.service);
+ await fillEditForm(json.service); // AWAIT IMPORTANTE
closeDetailPanel();
document.getElementById('createServiceView').classList.remove('hidden');
document.getElementById('servicesListView').classList.add('hidden');
@@ -302,7 +358,8 @@
} catch(e) { showToast("Error cargando datos", true); }
}
- function fillEditForm(s) {
+ // MODIFICADO: AWAIT para esperar carga de compañías antes de asignar valor
+ async function fillEditForm(s) {
document.getElementById('editServiceId').value = s.id;
document.getElementById('formTitle').innerHTML = '
Editando Servicio #' + s.id;
@@ -312,7 +369,6 @@
document.getElementById('sEmail').value = s.email || '';
document.getElementById('sDesc').value = s.description || '';
- // Fechas (Cortar la parte de tiempo ISO)
if(s.scheduled_date) document.getElementById('sDate').value = s.scheduled_date.split('T')[0];
if(s.scheduled_time) document.getElementById('sTime').value = s.scheduled_time;
@@ -320,37 +376,24 @@
document.getElementById('sUrgent').checked = s.is_urgent;
document.getElementById('sIsCompany').checked = s.is_company;
- toggleCompanyFields(); // Mostrar/ocultar panel
+
+ // LÓGICA CRÍTICA PARA COMPAÑÍA
if(s.is_company) {
+ document.getElementById('companyFields').classList.remove('hidden');
+ await loadCompanies(); // Esperamos a que el select se llene
document.getElementById('sCompanyId').value = s.company_id || '';
document.getElementById('sCompanyRef').value = s.company_ref || '';
+ } else {
+ document.getElementById('companyFields').classList.add('hidden');
}
document.getElementById('sNotesInternal').value = s.internal_notes || '';
document.getElementById('sNotesClient').value = s.client_notes || '';
- // El estado inicial no se edita aquí, se hace desde el panel de estados
- document.getElementById('sCreateStatus').disabled = true;
-
+ document.getElementById('sCreateStatus').disabled = true; // No editar estado aquí
lucide.createIcons();
}
- async function deleteService() {
- if(!currentServiceId || !confirm("¿Estás seguro de que quieres borrar este servicio permanentemente?")) return;
- try {
- const res = await fetch(`${API_URL}/services/${currentServiceId}`, {
- method: 'DELETE',
- headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` }
- });
- if(res.ok) {
- showToast("Servicio eliminado");
- closeDetailPanel();
- fetchServices();
- } else { showToast("Error al borrar", true); }
- } catch(e) { showToast("Error conexión", true); }
- }
-
- // --- SUBMIT UNIFICADO (CREAR / EDITAR) ---
async function handleFormSubmit(e) {
e.preventDefault();
const btn = document.getElementById('btnSave');
@@ -377,7 +420,7 @@
};
if (!isEdit) {
- data.status_id = document.getElementById('sCreateStatus').value; // Solo al crear
+ data.status_id = document.getElementById('sCreateStatus').value;
}
const url = isEdit ? `${API_URL}/services/${editId}` : `${API_URL}/services`;
@@ -392,66 +435,27 @@
const json = await res.json();
if (json.ok) {
- showToast(isEdit ? "✅ Servicio Actualizado" : "✅ Servicio Creado");
+ showToast(isEdit ? "✅ Actualizado" : "✅ Creado");
toggleView('list');
} else {
showToast("❌ " + (json.error || "Error"), true);
}
- } catch (e) {
- showToast("Error de conexión", true);
- } finally {
- btn.disabled = false; btn.innerText = "GUARDAR";
- }
+ } catch (e) { showToast("Error conexión", true); }
+ finally { btn.disabled = false; btn.innerText = "GUARDAR"; }
}
- // --- RESTO DE FUNCIONES (MAESTROS, LISTAR, ETC) ---
- async function fetchStatuses() {
+ async function deleteService() {
+ if(!currentServiceId || !confirm("¿Borrar servicio permanentemente?")) return;
try {
- const res = await fetch(`${API_URL}/statuses`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
- const data = await res.json();
- if(data.ok) {
- allStatuses = data.statuses;
- const createSel = document.getElementById('sCreateStatus');
- createSel.innerHTML = '';
- allStatuses.forEach(s => {
- const isDef = s.is_default ? 'selected' : '';
- createSel.innerHTML += `
`;
- });
- }
- } catch(e) {}
- }
-
- async function loadCompanies() {
- try {
- const res = await fetch(`${API_URL}/companies`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
- const data = await res.json();
- if (data.ok) {
- const sel = document.getElementById('sCompanyId');
- sel.innerHTML = '
';
- data.companies.forEach(c => sel.innerHTML += `
`);
- }
- } catch (e) {}
- }
-
- async function quickAddCompany() {
- const name = prompt("Nombre de la nueva compañía:");
- if(!name) return;
- try {
- const res = await fetch(`${API_URL}/companies`, {
- method: 'POST',
- headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
- body: JSON.stringify({ name })
+ const res = await fetch(`${API_URL}/services/${currentServiceId}`, {
+ method: 'DELETE',
+ headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` }
});
- if(res.ok) { showToast("Compañía añadida"); loadCompanies(); }
- } catch(e) { alert("Error"); }
- }
-
- function toggleCompanyFields() {
- const isChecked = document.getElementById('sIsCompany').checked;
- const div = document.getElementById('companyFields');
- if(isChecked) { div.classList.remove('hidden'); loadCompanies(); } else { div.classList.add('hidden'); }
+ if(res.ok) { showToast("Eliminado"); closeDetailPanel(); fetchServices(); }
+ } catch(e) { showToast("Error", true); }
}
+ // --- BÚSQUEDA CLIENTE ---
async function searchClientByPhone() {
const phone = document.getElementById('sPhone').value;
if(phone.length < 8) return;
@@ -475,72 +479,53 @@
document.getElementById('clientFoundMsg').classList.add('hidden');
document.getElementById('sAddressSelect').classList.add('hidden');
}
- } catch (e) { console.error(e); }
+ } catch (e) {}
}
-
function selectAddress(val) { if(val) document.getElementById('sAddress').value = val; }
- // --- LISTAR Y DETALLES ---
+ // --- LISTAR SERVICIOS ---
async function fetchServices() {
try {
const res = await fetch(`${API_URL}/services`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const data = await res.json();
const tbody = document.getElementById('servicesTableBody');
tbody.innerHTML = "";
-
if(!data.ok || data.services.length === 0) {
- tbody.innerHTML = `
| No hay servicios registrados. |
`;
+ tbody.innerHTML = `
| No hay servicios. |
`;
return;
}
-
data.services.forEach(s => {
const color = s.status_color || 'gray';
const date = new Date(s.created_at);
const formattedDate = date.toLocaleDateString('es-ES', { day: '2-digit', month: 'short' });
-
tbody.innerHTML += `
| ${formattedDate} |
-
- ${s.contact_name}
- ${s.address}
- |
-
- ${s.description || 'Sin detalles'}
- ${s.is_urgent ? 'Urgente' : ''}
- ${s.is_company ? `${s.company_name || 'Compañía'}` : ''}
- |
-
-
- ${s.status_name || 'Nuevo'}
-
- |
+ ${s.contact_name} ${s.address} |
+ ${s.description || 'Sin detalles'} ${s.is_urgent ? 'Urgente' : ''}${s.is_company ? `${s.company_name || 'Compañía'}` : ''} |
+ ${s.status_name || 'Nuevo'} |
|
`;
});
lucide.createIcons();
- } catch (e) { console.error(e); }
+ } catch (e) {}
}
async function openDetail(id, client, title, statusName, statusColor, date) {
currentServiceId = id;
document.getElementById('serviceDetailPanel').classList.remove('hidden');
-
document.getElementById('detailTitle').innerText = title || 'Servicio General';
document.getElementById('detailClient').innerText = client;
document.getElementById('detailId').innerText = `#${id}`;
document.getElementById('detailDate').innerText = date;
-
const badge = document.getElementById('detailStatusBadge');
badge.innerText = statusName;
badge.className = `px-2 py-1 rounded text-[10px] font-bold text-white uppercase tracking-wide bg-${statusColor}-500`;
-
const sel = document.getElementById('newStatusSelect');
sel.innerHTML = "";
allStatuses.forEach(s => sel.innerHTML += `
`);
-
loadTimeline(id);
}
@@ -550,15 +535,15 @@
const res = await fetch(`${API_URL}/services/${id}/logs`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const data = await res.json();
timeline.innerHTML = "";
- if(data.logs.length === 0) { timeline.innerHTML = '
Sin historial registrado.
'; return; }
+ if(data.logs.length === 0) { timeline.innerHTML = '
Sin historial.
'; return; }
data.logs.forEach(log => {
const color = log.new_color || 'gray';
const date = new Date(log.created_at);
timeline.innerHTML += `
-
+
${log.new_status}
-
${log.comment || 'Cambio de estado'}
Usuario: ${log.user_name || 'Sistema'}
+
${log.comment || 'Cambio de estado'}
Usuario: ${log.user_name || 'Sistema'}
`;
});
@@ -567,7 +552,7 @@
async function updateStatus() {
const statusId = document.getElementById('newStatusSelect').value;
if(!statusId) return;
- const comment = prompt("Añade un comentario sobre este cambio (opcional):");
+ const comment = prompt("Comentario (opcional):");
try {
await fetch(`${API_URL}/services/${currentServiceId}/status`, {
method: 'PUT',
@@ -577,7 +562,7 @@
showToast("Estado actualizado");
loadTimeline(currentServiceId);
fetchServices();
- } catch(e) { showToast("Error al actualizar", true); }
+ } catch(e) { showToast("Error", true); }
}
function closeDetailPanel() { document.getElementById('serviceDetailPanel').classList.add('hidden'); }