diff --git a/presupuestos.html b/presupuestos.html index afd5815..4ad86e9 100644 --- a/presupuestos.html +++ b/presupuestos.html @@ -455,7 +455,7 @@ async function downloadPDF(id) { } } - // ------------------ RENDERIZAR LA LISTA EN PANTALLA ------------------ + // ------------------ RENDERIZAR LA LISTA EN PANTALLA ------------------ function renderBudgetsList(budgets) { const container = document.getElementById('budgetsList'); if(budgets.length === 0) { @@ -470,7 +470,6 @@ async function downloadPDF(id) { } container.innerHTML = budgets.map(b => { - // 🔴 LÓGICA DE ESTADOS Y CADUCIDAD (Igual que en el Portal) let bDate = new Date(b.created_at); let diffDays = Math.ceil(Math.abs(new Date() - bDate) / (1000 * 60 * 60 * 24)); let isExpired = diffDays > 30; @@ -479,27 +478,33 @@ async function downloadPDF(id) { let statusText = "Pte. Resolver"; let icon = "clock"; - // Prioridad de estados if (b.status === 'paid') { - statusColor = "bg-emerald-100 text-emerald-700 border border-emerald-200"; - statusText = "Pagado Online"; - icon = "badge-check"; + statusColor = "bg-emerald-100 text-emerald-700 border border-emerald-200"; statusText = "Pagado Online"; icon = "badge-check"; } else if (isExpired && b.status !== 'rejected') { - statusColor = "bg-slate-100 text-slate-500 border border-slate-200"; - statusText = "Caducado"; - icon = "clock-alert"; + statusColor = "bg-slate-100 text-slate-500 border border-slate-200"; statusText = "Caducado"; icon = "clock-alert"; } else if (b.status === 'accepted' || b.status === 'converted') { - statusColor = "bg-blue-100 text-blue-700 border border-blue-200"; - statusText = "Aceptado (Pte. Pago)"; - icon = "clock"; + statusColor = "bg-blue-100 text-blue-700 border border-blue-200"; statusText = "Aceptado (Pte. Pago)"; icon = "clock"; } else if (b.status === 'rejected') { - statusColor = "bg-rose-100 text-rose-700"; - statusText = "Rechazado"; - icon = "x-circle"; + statusColor = "bg-rose-100 text-rose-700"; statusText = "Rechazado"; icon = "x-circle"; } const d = bDate.toLocaleDateString('es-ES', { day: '2-digit', month: 'short', year: '2-digit' }); + // LÓGICA DE BOTONES PARA EL TÉCNICO + let actionBtns = ''; + if (b.status === 'pending' && !isExpired) { + actionBtns = ` + + + `; + } else if ((b.status === 'accepted' || b.status === 'paid') && !isExpired) { + actionBtns = ``; + } else if (b.status === 'converted') { + actionBtns = `Agendado`; + } else { + actionBtns = `Cerrado`; + } + return `
@@ -519,13 +524,8 @@ async function downloadPDF(id) {
-
- ${ (b.status === 'pending' && !isExpired) ? ` - - - ` : (b.status === 'paid' ? - `Cobrado` : - `Cerrado`) } +
+ ${actionBtns}
@@ -681,6 +681,138 @@ async function downloadPDF(id) { lucide.createIcons(); } } + + // ------------------ SISTEMA DE CITA Y AGENDA EN TIEMPO REAL ------------------ + function openAppointmentModal(id, clientName) { + document.getElementById('apptBudgetId').value = id; + document.getElementById('apptClientName').innerText = clientName || "Cliente"; + document.getElementById('apptDate').value = ""; + document.getElementById('apptTime').value = ""; + document.getElementById('agendaPreview').classList.add('hidden'); + + document.getElementById('appointmentModal').classList.remove('hidden'); + document.getElementById('appointmentModal').classList.add('flex'); + setTimeout(() => document.getElementById('apptModalSheet').classList.remove('translate-y-full'), 10); + + loadGuilds(); + } + + function closeAppointmentModal() { + document.getElementById('apptModalSheet').classList.add('translate-y-full'); + setTimeout(() => { + document.getElementById('appointmentModal').classList.add('hidden'); + document.getElementById('appointmentModal').classList.remove('flex'); + }, 300); + } + + async function loadGuilds() { + const gSel = document.getElementById('apptGuild'); + gSel.innerHTML = ''; + try { + const res = await fetch(`${API_URL}/guilds`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); + const data = await res.json(); + gSel.innerHTML = ''; + if (data.ok && data.guilds) { + data.guilds.forEach(g => { gSel.innerHTML += ``; }); + } + } catch (e) { gSel.innerHTML = ''; } + } + + // 🟢 MAGIA: BUSCAR LA RUTA DEL TÉCNICO ESE DÍA + async function checkAgendaForDate(dateStr) { + const preview = document.getElementById('agendaPreview'); + const list = document.getElementById('agendaList'); + + if(!dateStr) { + preview.classList.add('hidden'); + return; + } + + preview.classList.remove('hidden'); + list.innerHTML = '
'; + lucide.createIcons(); + + try { + // Descargamos las averías del técnico logueado + const res = await fetch(`${API_URL}/services`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); + const data = await res.json(); + + if(data.ok && data.services) { + // Filtramos solo las que coinciden con el día seleccionado + const dayServices = data.services.filter(s => s.scheduled_date === dateStr && s.status !== 'archived'); + + if(dayServices.length === 0) { + list.innerHTML = '

Libre: No tienes nada agendado este día.

'; + return; + } + + // Ordenar por hora + dayServices.sort((a, b) => (a.scheduled_time || "23:59").localeCompare(b.scheduled_time || "23:59")); + + list.innerHTML = dayServices.map(s => { + const raw = s.raw_data || {}; + const pob = raw['Población'] || raw['POBLACION-PROVINCIA'] || raw['Dirección'] || 'Sin ubicación'; + const time = s.scheduled_time ? s.scheduled_time.substring(0,5) : 'S/H'; + return ` +
+ ${time} + ${pob} +
+ `; + }).join(''); + } else { + list.innerHTML = '

No se pudo cargar la agenda.

'; + } + } catch(e) { + list.innerHTML = '

Error de conexión.

'; + } + } + + async function confirmAppointment() { + const id = document.getElementById('apptBudgetId').value; + const guild_id = document.getElementById('apptGuild').value; + const date = document.getElementById('apptDate').value; + const time = document.getElementById('apptTime').value; + + if (!guild_id || !date || !time) return showToast("⚠️ Gremio, Fecha y Hora son obligatorios."); + + const btn = document.getElementById('btnConfirmAppt'); + btn.disabled = true; + btn.innerHTML = ' Procesando...'; + lucide.createIcons(); + + // El técnico se auto-asigna al enviar assigned_to: 'self' + const payload = { + guild_id: guild_id, + date: date, + time: time, + use_automation: false, + assigned_to: 'self' + }; + + try { + const res = await fetch(`${API_URL}/budgets/${id}/convert`, { + method: 'POST', + headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, + body: JSON.stringify(payload) + }); + const data = await res.json(); + + if(data.ok) { + showToast("✅ ¡Cita agendada con éxito!"); + closeAppointmentModal(); + fetchBudgets(); + } else { + showToast("❌ " + (data.error || "Error al agendar cita.")); + } + } catch(e) { + showToast("❌ Error de conexión al convertir."); + } finally { + btn.disabled = false; + btn.innerHTML = ' Confirmar Cita'; + lucide.createIcons(); + } + } \ No newline at end of file