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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Próximos vencimientos
+
+
+
+
+
+
+
+
+
+
+ Detalle del evento
+
+
+
+
+
+
+
+
+
+
+
+
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){