diff --git a/public/calendario/index.php b/public/calendario/index.php new file mode 100644 index 0000000..60adb35 --- /dev/null +++ b/public/calendario/index.php @@ -0,0 +1,8 @@ + 'live', ], [ - 'slug' => 'agenda', - 'title' => 'Agenda', - 'description' => 'Calendario compartido de audiencias, reuniones y vencimientos.', + 'slug' => 'calendario', + 'title' => 'Calendario', + 'description' => 'Vista visual de eventos de Escrituras y Trámites: solicitudes y vencimientos por año, mes, semana y día.', 'icon' => 'calendar', - 'href' => '#', - 'status' => 'coming-soon', + 'href' => '/calendario/', + 'status' => 'live', ], [ 'slug' => 'clientes', diff --git a/views/calendario.html b/views/calendario.html new file mode 100644 index 0000000..4e3a609 --- /dev/null +++ b/views/calendario.html @@ -0,0 +1,838 @@ + + + + + +Calendario — AALN Donna + + + + + + + +
+
+ + + Portal + + +
+
+
+
+ Conectando… +
+
+
?
+ … +
+ Cerrar sesión +
+
+ +
+
+ + + + +
+
+ + + +
+ — + +
+ Escrituras + Admin + Corporativo + Migración + Litigios +
+
+ +
+
Total eventos
—
+
Vencen ≤ 7 días
—
+
Vencen ≤ 30 días
—
+
Vencidos abiertos
—
+
+ +
+

Próximos vencimientos

+
Cargando…
+
+ +
+ + + + + +
+ + + + diff --git a/views/escrituras.html b/views/escrituras.html index 6f91d4b..4ab8b4b 100644 --- a/views/escrituras.html +++ b/views/escrituras.html @@ -612,6 +612,7 @@ let pollTimer = null; let editModalOpen = false; // modal de edición/nuevo abierta let editingId = null; // id del trámite siendo editado (null = nuevo) let pendingRefresh = false; // poll trajo datos durante una edición +let firstLoadDone = false; // deep-link ?edit=ID solo aplica en la primera carga function esc(s) { return (s||'').replace(/&/g,'&').replace(/"/g,'"').replace(//g,'>'); } function fmtDate(dt) { @@ -672,6 +673,10 @@ async function loadAll(showOverlay=false) { } else { render(); setSyncState('ok','Sincronizado'); + if (!firstLoadDone) { + firstLoadDone = true; + checkDeepLink(); + } } } catch(e) { setSyncState('error','Sin conexión'); @@ -729,6 +734,23 @@ function doLogout() { if (confirm('¿Cerrar sesión?')) window.location.href = 'api.php?action=logout'; } +// Si el usuario llegó desde el Calendario con ?edit=ID, abre la modal sobre esa fila +function checkDeepLink() { + const params = new URLSearchParams(location.search); + const raw = params.get('edit'); + if (!raw) return; + const id = parseInt(raw, 10); + if (Number.isNaN(id)) return; + const r = allRows.find(x => x.id === id); + if (r) { + openEditModal(id); + } else { + toast('Trámite #' + id + ' no encontrado','error'); + } + // Limpiar la URL para no re-disparar en refresh + history.replaceState({}, '', location.pathname); +} + // ── EDIT MODAL ─────────────────────────────────────────────────────────── function openEditModal(id) { editingId = id; diff --git a/views/tramites.html b/views/tramites.html index 1e9ffea..49844f4 100644 --- a/views/tramites.html +++ b/views/tramites.html @@ -194,9 +194,10 @@ const SI_NO = ['Sí','No']; const API = 'api.php'; let data = {adm:[],corp:[],mig:[],lit:[]}; -let currentDept = 'adm'; -let editingId = null; -let authUser = {email:'', name:''}; +let currentDept = 'adm'; +let editingId = null; +let authUser = {email:'', name:''}; +let firstLoadDone = false; // deep-link ?edit=CODIGO solo aplica en la primera carga function esc(s){return (s==null?'':String(s)).replace(/&/g,'&').replace(/"/g,'"').replace(//g,'>');} function setSync(state,label){ @@ -288,6 +289,10 @@ async function loadAll(){ setSync('ok', 'Sincronizado'); setUserChip(); renderAll(); + if (!firstLoadDone) { + firstLoadDone = true; + checkDeepLink(); + } } catch(e){ setSync('error','Sin conexión'); toast('Error al cargar: '+e.message,'error'); @@ -304,6 +309,24 @@ function switchTab(dept){ renderPanel(dept); } +// Si el usuario llegó desde el Calendario con ?edit=ADM-001, busca el dept y abre el modal +function checkDeepLink(){ + const params = new URLSearchParams(location.search); + const code = params.get('edit'); + if(!code) return; + for(const dept of ['adm','corp','mig','lit']){ + const r = data[dept].find(x => x.id === code); + if(r){ + switchTab(dept); + openModal(dept, code); + history.replaceState({}, '', location.pathname); + return; + } + } + toast('Trámite ' + code + ' no encontrado','error'); + history.replaceState({}, '', location.pathname); +} + function renderAll(){['adm','corp','mig','lit'].forEach(renderPanel);} function renderPanel(dept){