feat(home): eventos de hoy debajo de los módulos
- 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
This commit is contained in:
@@ -1,12 +1,114 @@
|
|||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
require_once __DIR__ . '/../src/Auth.php';
|
require_once __DIR__ . '/../src/Auth.php';
|
||||||
|
require_once __DIR__ . '/../src/Db.php';
|
||||||
require_once __DIR__ . '/../src/Apps.php';
|
require_once __DIR__ . '/../src/Apps.php';
|
||||||
|
|
||||||
$authed = Auth::isAuthenticated();
|
$authed = Auth::isAuthenticated();
|
||||||
$user = $authed ? Auth::user() : ['email' => '', 'name' => ''];
|
$user = $authed ? Auth::user() : ['email' => '', 'name' => ''];
|
||||||
$apps = $authed ? Apps::catalog() : [];
|
$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 {
|
function initials(string $name): string {
|
||||||
$parts = preg_split('/\s+/u', trim($name));
|
$parts = preg_split('/\s+/u', trim($name));
|
||||||
$a = mb_substr($parts[0] ?? '', 0, 1);
|
$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{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);}
|
.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;}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -248,6 +367,92 @@ a{color:inherit;text-decoration:none;}
|
|||||||
</a>
|
</a>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$meses = ['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre'];
|
||||||
|
$dias = ['domingo','lunes','martes','miércoles','jueves','viernes','sábado'];
|
||||||
|
$ts = strtotime(date('Y-m-d'));
|
||||||
|
$hoyFmt = $dias[(int)date('w', $ts)] . ' ' . (int)date('j', $ts) . ' de ' . $meses[(int)date('n', $ts) - 1];
|
||||||
|
?>
|
||||||
|
<div class="today-wrap">
|
||||||
|
<div class="section-label">Eventos de hoy · <?= htmlspecialchars($hoyFmt) ?></div>
|
||||||
|
<div class="today-list">
|
||||||
|
<?php if (!$hasToday): ?>
|
||||||
|
<div class="today-empty">No hay eventos programados para hoy.</div>
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<?php foreach ($todayEvents['manual'] as $m):
|
||||||
|
$tipo = $m['tipo'] ?: 'evento';
|
||||||
|
$color = $TIPO_COLORS[$tipo] ?? '#27ae60';
|
||||||
|
$tipoLabel = $TIPO_LABELS[$tipo] ?? 'Evento';
|
||||||
|
$time = '';
|
||||||
|
if ($m['hora_inicio']) {
|
||||||
|
$time = fmt_hour($m['hora_inicio']);
|
||||||
|
if ($m['hora_fin']) $time .= ' – ' . fmt_hour($m['hora_fin']);
|
||||||
|
} else { $time = 'Todo el día'; }
|
||||||
|
$metaBits = [htmlspecialchars($m['creado_por_nombre'] ?: $m['creado_por'])];
|
||||||
|
if ($m['ubicacion']) $metaBits[] = htmlspecialchars($m['ubicacion']);
|
||||||
|
?>
|
||||||
|
<a class="today-card linkable" href="/calendario/">
|
||||||
|
<div class="today-bar" style="background:<?= $color ?>"></div>
|
||||||
|
<div class="today-body">
|
||||||
|
<div class="today-title"><?= htmlspecialchars($m['titulo']) ?></div>
|
||||||
|
<div class="today-meta">
|
||||||
|
<span class="today-time"><?= htmlspecialchars($time) ?></span>
|
||||||
|
<?php foreach ($metaBits as $i => $b): ?>
|
||||||
|
<span class="dot"></span><span><?= $b ?></span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="today-tags">
|
||||||
|
<span class="today-tag" style="background:<?= $color ?>"><?= htmlspecialchars($tipoLabel) ?></span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php foreach ($todayEvents['escrituras'] as $e): ?>
|
||||||
|
<a class="today-card linkable" href="/escrituras/?edit=<?= (int)$e['id'] ?>">
|
||||||
|
<div class="today-bar" style="background:#1B3A6B"></div>
|
||||||
|
<div class="today-body">
|
||||||
|
<div class="today-title"><?= htmlspecialchars($e['tramite'] ?: 'Escritura sin nombre') ?></div>
|
||||||
|
<div class="today-meta">
|
||||||
|
<span><?= htmlspecialchars($e['cliente'] ?: '—') ?></span>
|
||||||
|
<span class="dot"></span><span><?= htmlspecialchars($e['abogado'] ?: '—') ?></span>
|
||||||
|
<?php if ($e['estatus']): ?><span class="dot"></span><span><?= htmlspecialchars($e['estatus']) ?></span><?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="today-tags">
|
||||||
|
<span class="today-tag" style="background:#1B3A6B">Escritura</span>
|
||||||
|
<span class="today-tag" style="background:var(--gray-400)">Solicitud</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php foreach ($todayEvents['tramites'] as $t):
|
||||||
|
$dept = $t['departamento'];
|
||||||
|
$color = $DEPT_COLORS[$dept] ?? '#666';
|
||||||
|
$dLab = $DEPT_LABELS[$dept] ?? $dept;
|
||||||
|
?>
|
||||||
|
<a class="today-card linkable" href="/tramites/?edit=<?= urlencode($t['codigo']) ?>">
|
||||||
|
<div class="today-bar" style="background:<?= $color ?>"></div>
|
||||||
|
<div class="today-body">
|
||||||
|
<div class="today-title"><?= htmlspecialchars($t['title']) ?> <span class="today-code">· <?= htmlspecialchars($t['codigo']) ?></span></div>
|
||||||
|
<div class="today-meta">
|
||||||
|
<span><?= htmlspecialchars($t['cliente'] ?: '—') ?></span>
|
||||||
|
<span class="dot"></span><span><?= htmlspecialchars($t['abogado'] ?: '—') ?></span>
|
||||||
|
<?php if ($t['estatus']): ?><span class="dot"></span><span><?= htmlspecialchars($t['estatus']) ?></span><?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="today-tags">
|
||||||
|
<span class="today-tag" style="background:<?= $color ?>"><?= htmlspecialchars($dLab) ?></span>
|
||||||
|
<span class="today-tag" style="background:var(--gray-400)"><?= htmlspecialchars($t['evento_label']) ?></span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="dash-foot">
|
<footer class="dash-foot">
|
||||||
|
|||||||
Reference in New Issue
Block a user