From d75a2a5fdaf21d2536b3cbbf9d779ff25939fa39 Mon Sep 17 00:00:00 2001 From: Soporte ZH Consultores Date: Thu, 4 Jun 2026 21:05:28 -0500 Subject: [PATCH] =?UTF-8?q?feat(home):=20eventos=20de=20hoy=20debajo=20de?= =?UTF-8?q?=20los=20m=C3=B3dulos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Lista con eventos del día agrupados: manuales, escrituras, trámites - Visibilidad: eventos manuales y escrituras → todos los usuarios; trámites legales → solo creador, abogado nombrado o involucrado (mismo canView() que en el módulo de trámites) - Cada evento es clickable y navega al módulo correspondiente (/calendario, /escrituras/?edit=ID, /tramites/?edit=CODIGO) - Cards muestran: título + cliente + abogado + estatus, con tags de tipo y departamento; eventos manuales muestran rango horario y creador --- public/index.php | 205 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/public/index.php b/public/index.php index 002ca60..ccc19fd 100644 --- a/public/index.php +++ b/public/index.php @@ -1,12 +1,114 @@ '', 'name' => '']; $apps = $authed ? Apps::catalog() : []; +/** + * Devuelve los eventos del día agrupados: + * - manuales: visibles a todos + * - escrituras (fecha_solicitud=hoy): visibles a todos + * - trámites (solicitud/vencimiento/término=hoy): solo creador, abogado nombrado o involucrado + */ +function todays_events(array $u, int $myId, bool $isSocio): array { + try { + $pdo = Db::pdo(); + $today = date('Y-m-d'); + + $manual = $pdo->prepare( + 'SELECT id, titulo, tipo, fecha, hora_inicio, hora_fin, ubicacion, creado_por_nombre, creado_por + FROM calendar_events WHERE fecha = :d + ORDER BY (hora_inicio IS NULL), hora_inicio, id' + ); + $manual->execute([':d' => $today]); + $manualRows = $manual->fetchAll(); + + $esc = $pdo->prepare( + 'SELECT id, tramite, cliente, abogado, estatus + FROM escrituras_tramites WHERE DATE(fecha_solicitud) = :d + ORDER BY id DESC' + ); + $esc->execute([':d' => $today]); + $escRows = $esc->fetchAll(); + + if ($isSocio) { + $tra = $pdo->prepare( + "SELECT id, codigo, departamento, nombre, tipo_tramite, tipo_proceso, + cliente, abogado, estatus, fecha_solicitud, fecha_vencimiento, fecha_termino + FROM tramites_legales + WHERE DATE(fecha_solicitud) = :d + OR fecha_vencimiento = :d2 + OR fecha_termino = :d3 + ORDER BY id DESC" + ); + $tra->execute([':d' => $today, ':d2' => $today, ':d3' => $today]); + } else { + $tra = $pdo->prepare( + "SELECT DISTINCT t.id, t.codigo, t.departamento, t.nombre, t.tipo_tramite, t.tipo_proceso, + t.cliente, t.abogado, t.estatus, t.fecha_solicitud, t.fecha_vencimiento, t.fecha_termino + FROM tramites_legales t + LEFT JOIN users ua ON ua.name = t.abogado AND ua.activo = 1 + LEFT JOIN tramites_involucrados ti ON ti.tramite_id = t.id AND ti.user_id = :uid + WHERE (DATE(t.fecha_solicitud) = :d + OR t.fecha_vencimiento = :d2 + OR t.fecha_termino = :d3) + AND (t.creado_por = :email OR ua.id = :uid2 OR ti.user_id IS NOT NULL) + ORDER BY t.id DESC" + ); + $tra->execute([ + ':uid' => $myId, ':uid2' => $myId, ':email' => $u['email'], + ':d' => $today, ':d2' => $today, ':d3' => $today, + ]); + } + $traRows = $tra->fetchAll(); + + // Expandir trámites en 1..N entradas (una por fecha que coincida hoy) + $traEvents = []; + foreach ($traRows as $t) { + $title = $t['nombre'] ?: $t['tipo_tramite'] ?: $t['tipo_proceso'] ?: 'Trámite'; + if (substr((string)$t['fecha_solicitud'], 0, 10) === $today) { + $traEvents[] = $t + ['evento' => 'solicitud', 'evento_label' => 'Solicitud', 'title' => $title]; + } + if (($t['fecha_vencimiento'] ?? '') === $today) { + $traEvents[] = $t + ['evento' => 'vencimiento', 'evento_label' => 'Vencimiento', 'title' => $title]; + } + if (($t['fecha_termino'] ?? '') === $today) { + $traEvents[] = $t + ['evento' => 'termino', 'evento_label' => 'Término procesal', 'title' => $title]; + } + } + + return [ + 'manual' => $manualRows, + 'escrituras' => $escRows, + 'tramites' => $traEvents, + ]; + } catch (Throwable $e) { + error_log('todays_events error: ' . $e->getMessage()); + return ['manual' => [], 'escrituras' => [], 'tramites' => []]; + } +} + +function fmt_hour(?string $t): string { + if (!$t) return ''; + return substr($t, 0, 5); +} + +$todayEvents = $authed + ? todays_events($user, Auth::userId(), Auth::isSocio()) + : ['manual' => [], 'escrituras' => [], 'tramites' => []]; +$hasToday = $authed && ( + !empty($todayEvents['manual']) || !empty($todayEvents['escrituras']) || !empty($todayEvents['tramites']) +); + +$DEPT_LABELS = ['adm' => 'Admin', 'corp' => 'Corp', 'mig' => 'Migración', 'lit' => 'Litigios']; +$DEPT_COLORS = ['adm' => '#6c5b95', 'corp' => '#9E7C2E', 'mig' => '#2980b9', 'lit' => '#722f37']; +$TIPO_LABELS = ['reserva_sala' => 'Reserva de sala', 'cumpleanos' => 'Cumpleaños', 'recordatorio' => 'Recordatorio', 'evento' => 'Evento']; +$TIPO_COLORS = ['reserva_sala' => '#2e7d8f', 'cumpleanos' => '#c2185b', 'recordatorio' => '#e67e22', 'evento' => '#27ae60']; + function initials(string $name): string { $parts = preg_split('/\s+/u', trim($name)); $a = mb_substr($parts[0] ?? '', 0, 1); @@ -136,6 +238,23 @@ a{color:inherit;text-decoration:none;} .dash-foot{text-align:center;padding:24px;font-size:11px;color:var(--gray-400);} .dash-foot a{color:var(--navy);border-bottom:1px dotted var(--gray-400);} + +/* ───────── Today's events ───────── */ +.today-wrap{margin-top:48px;} +.today-list{display:flex;flex-direction:column;gap:10px;} +.today-empty{padding:18px 22px;background:#fff;border:1px dashed var(--gray-200);border-radius:12px;color:var(--gray-400);font-size:13.5px;text-align:center;} +.today-card{background:#fff;border:1px solid var(--gray-100);border-radius:12px;padding:14px 18px;display:grid;grid-template-columns:auto 1fr auto;gap:16px;align-items:center;box-shadow:var(--shadow);transition:all .15s;color:inherit;} +.today-card.linkable{cursor:pointer;} +.today-card.linkable:hover{transform:translateX(3px);border-color:var(--navy-l);box-shadow:0 6px 18px rgba(17,36,70,0.08);} +.today-bar{width:5px;height:46px;border-radius:3px;flex-shrink:0;} +.today-body{min-width:0;} +.today-title{font-family:'DM Serif Display',serif;font-size:17px;color:var(--navy);line-height:1.25;font-weight:400;} +.today-meta{font-size:12.5px;color:var(--gray-700);margin-top:4px;display:flex;gap:10px;flex-wrap:wrap;align-items:center;} +.today-meta .dot{width:3px;height:3px;border-radius:50%;background:var(--gray-400);display:inline-block;} +.today-tags{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end;align-items:center;} +.today-tag{font-size:10.5px;font-weight:600;padding:3px 9px;border-radius:20px;color:#fff;letter-spacing:.04em;text-transform:uppercase;white-space:nowrap;} +.today-time{font-size:13px;font-weight:600;color:var(--navy);font-variant-numeric:tabular-nums;white-space:nowrap;} +.today-code{font-family:'DM Mono','SF Mono',Menlo,monospace;font-size:11px;color:var(--gray-400);letter-spacing:.04em;} @@ -248,6 +367,92 @@ a{color:inherit;text-decoration:none;} + + +
+ + +