Fix dashboard stat tiles and add sidebar date filters

- Created Today tile: no longer limits to open statuses (count is all statuses)
- Closed Today tile: filters by closed_at range, not updated_at
- Add closed_from/closed_to support to TicketModel and DashboardController
- Add Created/Updated/Closed date range inputs to sidebar filter panel
- Apply button collects date inputs; Clear All removes them
- removeFilter handles date chip removal (clears both _from and _to)
- Active filter chips shown for date ranges

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-06 23:03:14 -04:00
parent dd98bfbd49
commit 603ba18067
4 changed files with 91 additions and 38 deletions
+48 -2
View File
@@ -56,6 +56,21 @@ if (!empty($_GET['assigned_to'])) {
$label = $_GET['assigned_to'] === 'unassigned' ? 'Unassigned' : 'User #' . htmlspecialchars($_GET['assigned_to']);
$activeFilters[] = ['type' => 'assigned_to', 'value' => $_GET['assigned_to'], 'label' => 'Assigned: ' . $label];
}
if (!empty($_GET['created_from']) || !empty($_GET['created_to'])) {
$from = $_GET['created_from'] ?? ''; $to = $_GET['created_to'] ?? '';
$label = $from === $to && $from ? 'Created: ' . $from : 'Created: ' . ($from ?: '…') . ' ' . ($to ?: '…');
$activeFilters[] = ['type' => 'created_from', 'value' => $from, 'label' => $label];
}
if (!empty($_GET['updated_from']) || !empty($_GET['updated_to'])) {
$from = $_GET['updated_from'] ?? ''; $to = $_GET['updated_to'] ?? '';
$label = $from === $to && $from ? 'Updated: ' . $from : 'Updated: ' . ($from ?: '…') . ' ' . ($to ?: '…');
$activeFilters[] = ['type' => 'updated_from', 'value' => $from, 'label' => $label];
}
if (!empty($_GET['closed_from']) || !empty($_GET['closed_to'])) {
$from = $_GET['closed_from'] ?? ''; $to = $_GET['closed_to'] ?? '';
$label = $from === $to && $from ? 'Closed: ' . $from : 'Closed: ' . ($from ?: '…') . ' ' . ($to ?: '…');
$activeFilters[] = ['type' => 'closed_from', 'value' => $from, 'label' => $label];
}
$_lt_statuses = $GLOBALS['config']['TICKET_STATUSES'];
$currentStatus = isset($_GET['status']) ? explode(',', $_GET['status']) : ['Open', 'Pending', 'In Progress'];
@@ -446,6 +461,37 @@ include __DIR__ . '/layout_header.php';
</fieldset>
<?php endif ?>
<!-- Date Filters -->
<fieldset class="lt-filter-group">
<legend class="lt-filter-label">Created</legend>
<div class="lt-flex lt-flex-col lt-flex-gap-xs">
<input type="date" id="filter-created-from" name="created_from" class="lt-input lt-input-sm"
placeholder="From" value="<?= htmlspecialchars($_GET['created_from'] ?? '') ?>">
<input type="date" id="filter-created-to" name="created_to" class="lt-input lt-input-sm"
placeholder="To" value="<?= htmlspecialchars($_GET['created_to'] ?? '') ?>">
</div>
</fieldset>
<fieldset class="lt-filter-group">
<legend class="lt-filter-label">Updated</legend>
<div class="lt-flex lt-flex-col lt-flex-gap-xs">
<input type="date" id="filter-updated-from" name="updated_from" class="lt-input lt-input-sm"
placeholder="From" value="<?= htmlspecialchars($_GET['updated_from'] ?? '') ?>">
<input type="date" id="filter-updated-to" name="updated_to" class="lt-input lt-input-sm"
placeholder="To" value="<?= htmlspecialchars($_GET['updated_to'] ?? '') ?>">
</div>
</fieldset>
<fieldset class="lt-filter-group">
<legend class="lt-filter-label">Closed</legend>
<div class="lt-flex lt-flex-col lt-flex-gap-xs">
<input type="date" id="filter-closed-from" name="closed_from" class="lt-input lt-input-sm"
placeholder="From" value="<?= htmlspecialchars($_GET['closed_from'] ?? '') ?>">
<input type="date" id="filter-closed-to" name="closed_to" class="lt-input lt-input-sm"
placeholder="To" value="<?= htmlspecialchars($_GET['closed_to'] ?? '') ?>">
</div>
</fieldset>
<div class="lt-btn-group lt-flex-col">
<button type="button" id="apply-filters-btn" class="lt-btn lt-btn-primary lt-btn-sm">APPLY</button>
<button type="button" id="clear-filters-btn" class="lt-btn lt-btn-ghost lt-btn-sm">CLEAR ALL</button>
@@ -1165,8 +1211,8 @@ document.querySelectorAll('.lt-stat-card').forEach(function (card) {
if (card.classList.contains('stat-open')) url += 'status=Open,Pending,In+Progress';
else if (card.classList.contains('stat-critical')) url += 'status=Open,Pending,In+Progress&priority_max=1';
else if (card.classList.contains('stat-unassigned')) url += 'status=Open,Pending,In+Progress&assigned_to=unassigned';
else if (card.classList.contains('stat-today')) url += 'status=Open,Pending,In+Progress&created_from=' + today + '&created_to=' + today;
else if (card.classList.contains('stat-resolved')) url += 'status=Closed&updated_from=' + today + '&updated_to=' + today;
else if (card.classList.contains('stat-today')) url += 'created_from=' + today + '&created_to=' + today;
else if (card.classList.contains('stat-resolved')) url += 'status=Closed&closed_from=' + today + '&closed_to=' + today;
else return;
window.location.href = url;
});