@@ -1343,12 +1349,67 @@
document.getElementById('nsTime').value = "";
document.getElementById('nsDate').value = selectedDateStr;
+ renderNewServiceAgenda(); // <-- Cargamos la ruta del día
+
const modal = document.getElementById('newServiceModal');
modal.style.display = 'flex';
setTimeout(() => modal.classList.remove('translate-y-full'), 10);
safeLoadIcons();
}
+ // Dibuja los huecos ocupados para que el operario sepa por dónde se mueve
+ function renderNewServiceAgenda() {
+ const dateInput = document.getElementById('nsDate').value;
+ const agendaContainer = document.getElementById('nsAgendaContainer');
+ const agendaList = document.getElementById('nsAgendaList');
+
+ if (!dateInput) {
+ agendaContainer.classList.add('hidden');
+ return;
+ }
+
+ const dayServices = localServices.filter(s => String(s.raw_data.scheduled_date || "").trim() === dateInput);
+
+ dayServices.sort((a, b) => {
+ const tA = String(a.raw_data.scheduled_time || "23:59");
+ const tB = String(b.raw_data.scheduled_time || "23:59");
+ return tA.localeCompare(tB);
+ });
+
+ if (dayServices.length === 0) {
+ agendaList.innerHTML = `
¡Día totalmente libre!`;
+ } else {
+ agendaList.innerHTML = dayServices.map(s => {
+ const time = s.raw_data.scheduled_time || "--:--";
+ const dur = parseInt(s.raw_data.duration_minutes || 60);
+
+ let endTime = "--:--";
+ if (time.includes(':')) {
+ let [h, m] = time.split(':').map(Number);
+ m += dur;
+ h += Math.floor(m / 60);
+ m = m % 60;
+ endTime = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
+ }
+
+ const city = s.raw_data["Población"] || "Sin Zona";
+
+ return `
+
+
+
+ ${time} - ${endTime}
+
+
${city}
+
+
+ `;
+ }).join('');
+ }
+ agendaContainer.classList.remove('hidden');
+ safeLoadIcons();
+ }
+
function closeNewServiceModal() {
const modal = document.getElementById('newServiceModal');
modal.classList.add('translate-y-full');
@@ -1378,8 +1439,101 @@
} catch (e) {}
}
+ async function saveAppointment() {
+ const id = document.getElementById('detId').value;
+ const date = document.getElementById('dateInput').value;
+ const time = document.getElementById('timeInput').value;
+ const duration = parseInt(document.getElementById('durationInput').value) || 60;
+ let statusMap = document.getElementById('detStatusMap').value;
+
+ const selectedSt = systemStatuses.find(st => String(st.id) === String(statusMap));
+ if (selectedSt && !selectedSt.is_final && !date && !selectedSt.name.toLowerCase().includes('pausa') && !selectedSt.name.toLowerCase().includes('asignar')) {
+ if(!confirm("No has asignado Fecha para este estado. ¿Deseas continuar?")) return;
+ }
+
+ // 🛑 RADAR ANTI-SOLAPAMIENTO (PERMISIVO)
+ if (date && time) {
+ let [newH, newM] = time.split(':').map(Number);
+ let newStartMin = newH * 60 + newM;
+ let newEndMin = newStartMin + duration;
+
+ const solapamiento = localServices.find(s => {
+ if (String(s.id) === String(id)) return false;
+ const sDate = String(s.raw_data.scheduled_date || "").trim();
+ const sTime = String(s.raw_data.scheduled_time || "").trim();
+ if (sDate === date && sTime && sTime.includes(':')) {
+ let [sH, sM] = sTime.split(':').map(Number);
+ let sDur = parseInt(s.raw_data.duration_minutes || 60);
+ let sStartMin = sH * 60 + sM;
+ let sEndMin = sStartMin + sDur;
+ return (newStartMin < sEndMin && newEndMin > sStartMin);
+ }
+ return false;
+ });
+
+ if (solapamiento) {
+ const horaC = solapamiento.raw_data.scheduled_time;
+ const zonaC = solapamiento.raw_data["Población"] || "otra zona";
+ // AHORA ES UN CONFIRM: Te avisa, pero te deja pasar si quieres
+ const forzar = confirm(`⚠️ SOLAPAMIENTO DETECTADO\n\nYa tienes una cita a las ${horaC} en ${zonaC}.\n\n¿Deseas FORZAR el guardado y agendarla en el mismo hueco?`);
+ if (!forzar) return; // Si cancela, abortamos
+ }
+ }
+
+ const btn = document.getElementById('btnSaveAppt');
+ const originalContent = btn.innerHTML;
+ btn.innerHTML = `
Guardando...`;
+ btn.disabled = true;
+
+ try {
+ const res = await fetch(`${API_URL}/services/set-appointment/${id}`, {
+ method: 'PUT',
+ headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
+ body: JSON.stringify({ date, time, duration_minutes: duration, status_operativo: statusMap })
+ });
+ if (res.ok) {
+ showToast("Estado actualizado");
+ closeModal();
+ refreshData();
+ } else { alert("Error al guardar"); }
+ } catch (e) { alert("Error de conexión"); }
+ finally { btn.innerHTML = originalContent; btn.disabled = false; safeLoadIcons(); }
+ }
+
async function saveNewServiceApp(e) {
e.preventDefault();
+
+ const date = document.getElementById('nsDate').value;
+ const time = document.getElementById('nsTime').value;
+ const duration = parseInt(document.getElementById('nsDuration').value) || 60;
+
+ // 🛑 RADAR ANTI-SOLAPAMIENTO EN CREACIÓN (PERMISIVO)
+ if (date && time) {
+ let [newH, newM] = time.split(':').map(Number);
+ let newStartMin = newH * 60 + newM;
+ let newEndMin = newStartMin + duration;
+
+ const solapamiento = localServices.find(s => {
+ const sDate = String(s.raw_data.scheduled_date || "").trim();
+ const sTime = String(s.raw_data.scheduled_time || "").trim();
+ if (sDate === date && sTime && sTime.includes(':')) {
+ let [sH, sM] = sTime.split(':').map(Number);
+ let sDur = parseInt(s.raw_data.duration_minutes || 60);
+ let sStartMin = sH * 60 + sM;
+ let sEndMin = sStartMin + sDur;
+ return (newStartMin < sEndMin && newEndMin > sStartMin);
+ }
+ return false;
+ });
+
+ if (solapamiento) {
+ const horaC = solapamiento.raw_data.scheduled_time;
+ const zonaC = solapamiento.raw_data["Población"] || "otra zona";
+ const forzar = confirm(`⚠️ SOLAPAMIENTO DETECTADO\n\nYa tienes una cita a las ${horaC} en ${zonaC}.\n\n¿Deseas FORZAR la creación de este aviso en el mismo hueco?`);
+ if (!forzar) return;
+ }
+ }
+
const btn = document.getElementById('btnSaveNewApp');
const originalHTML = btn.innerHTML;
btn.innerHTML = `
Procesando...`;
@@ -1397,7 +1551,7 @@
description: document.getElementById('nsDesc').value,
guild_id: null,
assigned_to: myWorkerId,
- duration_minutes: document.getElementById('nsDuration').value,
+ duration_minutes: duration,
is_urgent: false,
is_company: false,
company_name: 'Particular',
@@ -1417,10 +1571,6 @@
const citadoSt = systemStatuses.find(st => st.name.toLowerCase().includes('citado'));
const statusMapId = citadoSt ? String(citadoSt.id) : null;
- const date = document.getElementById('nsDate').value;
- const time = document.getElementById('nsTime').value;
- const duration = document.getElementById('nsDuration').value;
-
await fetch(`${API_URL}/services/set-appointment/${dataCreate.id}`, {
method: 'PUT',
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },