deadline widget

This commit is contained in:
2026-04-19 09:14:19 +03:00
parent 1fadc22178
commit dd5edab2f3
4 changed files with 395 additions and 112 deletions
+5
View File
@@ -296,6 +296,11 @@
<div class="page-wrapper"> <div class="page-wrapper">
<div class="page-content"> <div class="page-content">
<?php
$pdo = DBHandlerSelect::getInstance()->getConnection();
include(__DIR__ . '/scadenzario/include/my_deadlines_widget.php');
?>
<h3 class="dashboard-title">Dashboard Produzione</h3> <h3 class="dashboard-title">Dashboard Produzione</h3>
<!-- ===== STATISTICHE PRINCIPALI ===== --> <!-- ===== STATISTICHE PRINCIPALI ===== -->
+96 -47
View File
@@ -98,58 +98,81 @@ $departments = $pdo->query("SELECT DISTINCT department FROM employees WHERE depa
<div class="page-wrapper"> <div class="page-wrapper">
<div class="page-content"> <div class="page-content">
<nav class="scad-breadcrumb" aria-label="breadcrumb"> <?php include(__DIR__ . '/include/my_deadlines_widget.php'); ?>
<ol class="breadcrumb mb-0">
<li class="breadcrumb-item"><a href="scadenzario/index.php">Scadenzario</a></li>
<li class="breadcrumb-item active" aria-current="page">Calendario</li>
</ol>
</nav>
<div class="d-flex gap-2 mb-3"> <div class="d-flex gap-2 mb-3 flex-wrap align-items-center">
<a href="scadenzario/index.php" class="btn btn-scad-outline d-inline-flex align-items-center gap-2"> <button type="button" class="btn btn-scad-outline d-inline-flex align-items-center gap-2" data-bs-toggle="modal" data-bs-target="#filtersModal">
<i class="fa-solid fa-list"></i><span>Lista Scadenze</span> <i class="fa-solid fa-filter"></i>
</a> <span>Filtri</span>
<span id="filterCountBadge" class="badge bg-primary rounded-pill d-none" style="font-size:0.7rem">0</span>
</button>
<button id="btnResetFilters" type="button" class="btn btn-light border d-inline-flex align-items-center justify-content-center gap-1" title="Reset filtri" style="min-width:38px;height:38px">
<i class="fa-solid fa-rotate-left"></i>
<span class="d-none d-sm-inline">Reset</span>
</button>
<span id="activeFiltersSummary" class="text-muted small text-truncate d-none d-md-inline"></span>
</div> </div>
<div id="activeFiltersSummaryMobile" class="text-muted small d-md-none mb-2" style="padding-left:0.25rem"></div>
<div class="filter-bar mb-3"> <!-- Filters Modal -->
<div class="row g-2 align-items-center"> <div class="modal fade" id="filtersModal" tabindex="-1" aria-hidden="true">
<div class="col-12 col-sm-6 col-md-auto"> <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<select id="filterStatus" class="form-select" style="font-size:0.85rem;border-color:#d0d9e8;min-width:160px"> <div class="modal-content">
<option value="non-completata" selected>Stato: Non completate</option> <div class="modal-header">
<option value="">Stato: Tutti</option> <h5 class="modal-title"><i class="fa-solid fa-filter me-2"></i>Filtri calendario</h5>
<option value="attiva">Attive</option> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Chiudi"></button>
<option value="in-scadenza">In scadenza</option> </div>
<option value="scaduta">Scadute</option> <div class="modal-body">
<option value="completata">Completate</option> <div class="mb-3">
</select> <label class="form-label fw-semibold">Stato</label>
</div> <select id="filterStatus" class="form-select">
<div class="col-12 col-sm-6 col-md-auto"> <option value="non-completata" selected>Non completate</option>
<select id="filterDepartment" class="form-select" style="font-size:0.85rem;border-color:#d0d9e8;min-width:160px"> <option value="">Tutti</option>
<option value="">Reparto: Tutti</option> <option value="attiva">Attive</option>
<?php foreach ($departments as $dept): ?> <option value="in-scadenza">In scadenza</option>
<option value="<?= htmlspecialchars($dept, ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($dept, ENT_QUOTES, 'UTF-8') ?></option> <option value="scaduta">Scadute</option>
<?php endforeach; ?> <option value="completata">Completate</option>
</select> </select>
</div> </div>
<div class="col-12 col-sm-6 col-md-auto"> <div class="mb-3">
<select id="filterEmployee" class="form-select" style="font-size:0.85rem;border-color:#d0d9e8;min-width:160px"> <label class="form-label fw-semibold">Reparto</label>
<option value="">Responsabile: Tutti</option> <select id="filterDepartment" class="form-select">
<?php foreach ($employees as $emp): ?> <option value="">Tutti</option>
<option value="<?= htmlspecialchars(trim($emp['first_name'] . ' ' . $emp['last_name']), ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars(trim($emp['first_name'] . ' ' . $emp['last_name']), ENT_QUOTES, 'UTF-8') ?></option> <?php foreach ($departments as $dept): ?>
<?php endforeach; ?> <option value="<?= htmlspecialchars($dept, ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($dept, ENT_QUOTES, 'UTF-8') ?></option>
</select> <?php endforeach; ?>
</div> </select>
<div class="col-12 col-sm-auto"> </div>
<button id="btnResetFilters" class="btn btn-sm btn-light border w-100 w-sm-auto" title="Reset filtri"> <div class="mb-0">
<i class="fa-solid fa-rotate-left me-1"></i> Reset <label class="form-label fw-semibold">Responsabile</label>
</button> <select id="filterEmployee" class="form-select">
<option value="">Tutti</option>
<?php foreach ($employees as $emp): ?>
<option value="<?= htmlspecialchars(trim($emp['first_name'] . ' ' . $emp['last_name']), ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars(trim($emp['first_name'] . ' ' . $emp['last_name']), ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" id="btnResetFiltersModal">
<i class="fa-solid fa-rotate-left me-1"></i> Reset
</button>
<button type="button" class="btn btn-scad-primary" data-bs-dismiss="modal">
<i class="fa-solid fa-check me-1"></i> Applica
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="card scad-card"> <div class="card scad-card">
<div class="card-header d-flex align-items-center justify-content-between"> <div class="card-header d-flex align-items-center justify-content-between flex-wrap gap-2">
<h5><i class="fa-solid fa-calendar-days me-2"></i>Calendario Scadenze</h5> <h5 class="d-none d-md-flex align-items-center mb-0"><i class="fa-solid fa-calendar-days me-2"></i>Calendario Scadenze</h5>
<div class="header-actions d-flex gap-2 flex-wrap ms-auto">
<a href="scadenzario/index.php" class="btn btn-scad-outline d-inline-flex align-items-center gap-2">
<i class="fa-solid fa-list"></i><span>Lista Scadenze</span>
</a>
</div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="legend"> <div class="legend">
@@ -211,15 +234,41 @@ $departments = $pdo->query("SELECT DISTINCT department FROM employees WHERE depa
calendar.render(); calendar.render();
// Filters // Filters
function updateFilterBadge() {
var active = 0;
var summary = [];
var st = document.getElementById('filterStatus');
var stv = st.value;
if (stv && stv !== 'non-completata') { active++; summary.push(st.options[st.selectedIndex].text); }
var dept = document.getElementById('filterDepartment').value;
if (dept) { active++; summary.push('Reparto: ' + dept); }
var emp = document.getElementById('filterEmployee').value;
if (emp) { active++; summary.push('Responsabile: ' + emp); }
var badge = document.getElementById('filterCountBadge');
if (active > 0) { badge.textContent = active; badge.classList.remove('d-none'); }
else { badge.classList.add('d-none'); }
var summaryText = summary.length ? summary.slice(0, 2).join(' • ') + (summary.length > 2 ? ' +' + (summary.length - 2) : '') : '';
document.getElementById('activeFiltersSummary').textContent = summaryText;
document.getElementById('activeFiltersSummaryMobile').textContent = summaryText;
}
document.querySelectorAll('#filterStatus, #filterDepartment, #filterEmployee').forEach(function(el) { document.querySelectorAll('#filterStatus, #filterDepartment, #filterEmployee').forEach(function(el) {
el.addEventListener('change', function() { calendar.refetchEvents(); }); el.addEventListener('change', function() { calendar.refetchEvents(); updateFilterBadge(); });
}); });
document.getElementById('btnResetFilters').addEventListener('click', function() {
function resetFilters() {
document.getElementById('filterStatus').value = 'non-completata'; document.getElementById('filterStatus').value = 'non-completata';
document.getElementById('filterDepartment').value = ''; document.getElementById('filterDepartment').value = '';
document.getElementById('filterEmployee').value = ''; document.getElementById('filterEmployee').value = '';
calendar.refetchEvents(); calendar.refetchEvents();
}); updateFilterBadge();
}
document.getElementById('btnResetFilters').addEventListener('click', resetFilters);
document.getElementById('btnResetFiltersModal').addEventListener('click', resetFilters);
updateFilterBadge();
}); });
</script> </script>
</body> </body>
@@ -0,0 +1,91 @@
<?php
/**
* Renders two status banners for the current user:
* - red -> overdue deadlines (scaduta)
* - orange -> approaching deadlines (in scadenza)
* Scope: deadlines assigned directly to the user OR to their department.
*/
$_empStmt = $pdo->prepare("SELECT id, department FROM employees WHERE auth_user_id = ? LIMIT 1");
$_empStmt->execute([(int)$iduserlogin]);
$_emp = $_empStmt->fetch(PDO::FETCH_ASSOC) ?: null;
$_overdue = 0;
$_approaching = 0;
if ($_emp) {
$_empId = (int)$_emp['id'];
$_deptRaw = (string)($_emp['department'] ?? '');
$_dept = trim($_deptRaw);
$_sql = "
SELECT
SUM(CASE WHEN d.due_date < CURDATE() THEN 1 ELSE 0 END) AS overdue_cnt,
SUM(CASE WHEN d.due_date >= CURDATE()
AND d.due_date <= DATE_ADD(CURDATE(), INTERVAL d.notification_days DAY)
THEN 1 ELSE 0 END) AS approaching_cnt
FROM scad_deadlines d
WHERE d.status <> 'completed'
AND (
d.id IN (SELECT deadline_id FROM scad_deadline_employee WHERE employee_id = ?)
OR (? <> '' AND FIND_IN_SET(?, REPLACE(d.departments, ', ', ',')) > 0)
)
";
$_st = $pdo->prepare($_sql);
$_st->execute([$_empId, $_dept, $_dept]);
$_row = $_st->fetch(PDO::FETCH_ASSOC) ?: [];
$_overdue = (int)($_row['overdue_cnt'] ?? 0);
$_approaching = (int)($_row['approaching_cnt'] ?? 0);
}
if (!$_emp || ($_overdue === 0 && $_approaching === 0)) {
return;
}
?>
<style>
.my-deadlines-widgets { display: flex; gap: 0.75rem; margin-bottom: 1rem; flex-wrap: wrap; }
.my-deadlines-widgets .mdw {
flex: 1 1 260px;
display: flex; align-items: center; gap: 0.9rem;
padding: 0.85rem 1rem;
border-radius: 0.6rem;
text-decoration: none;
color: #fff;
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
transition: transform 0.15s, box-shadow 0.15s;
}
.my-deadlines-widgets .mdw:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); color: #fff; }
.my-deadlines-widgets .mdw-red { background: linear-gradient(135deg, #dc3545 0%, #b02a37 100%); }
.my-deadlines-widgets .mdw-orange { background: linear-gradient(135deg, #e8930c 0%, #c77a00 100%); }
.my-deadlines-widgets .mdw-icon {
width: 42px; height: 42px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
background: rgba(255,255,255,0.22); font-size: 1.2rem; flex-shrink: 0;
}
.my-deadlines-widgets .mdw-body { flex: 1; line-height: 1.2; }
.my-deadlines-widgets .mdw-count { font-size: 1.6rem; font-weight: 700; }
.my-deadlines-widgets .mdw-label { font-size: 0.8rem; opacity: 0.95; }
.my-deadlines-widgets .mdw-arrow { opacity: 0.7; font-size: 0.9rem; }
</style>
<div class="my-deadlines-widgets">
<?php if ($_overdue > 0): ?>
<a class="mdw mdw-red" href="scadenzario/index.php?filter_my=1&filter_status=scaduta">
<span class="mdw-icon"><i class="fa-solid fa-triangle-exclamation"></i></span>
<span class="mdw-body">
<span class="mdw-count"><?= $_overdue ?></span>
<span class="mdw-label d-block">Scadenz<?= $_overdue === 1 ? 'a' : 'e' ?> scadut<?= $_overdue === 1 ? 'a' : 'e' ?> — <?= $_dept !== '' ? htmlspecialchars($_dept, ENT_QUOTES, 'UTF-8') : 'personali' ?></span>
</span>
<span class="mdw-arrow"><i class="fa-solid fa-arrow-right"></i></span>
</a>
<?php endif; ?>
<?php if ($_approaching > 0): ?>
<a class="mdw mdw-orange" href="scadenzario/index.php?filter_my=1&filter_status=in-scadenza">
<span class="mdw-icon"><i class="fa-solid fa-clock"></i></span>
<span class="mdw-body">
<span class="mdw-count"><?= $_approaching ?></span>
<span class="mdw-label d-block">In scadenza a breve <?= $_dept !== '' ? htmlspecialchars($_dept, ENT_QUOTES, 'UTF-8') : 'personali' ?></span>
</span>
<span class="mdw-arrow"><i class="fa-solid fa-arrow-right"></i></span>
</a>
<?php endif; ?>
</div>
+203 -65
View File
@@ -13,6 +13,16 @@ if ($filterSubjectId) {
if (!$filterSubjectName) { $filterSubjectId = null; } if (!$filterSubjectName) { $filterSubjectId = null; }
} }
// Optional filter: limit to deadlines assigned to the current user (directly OR via department)
$filterMy = !empty($_GET['filter_my']);
$filterMyEmployee = null;
if ($filterMy) {
$st = $pdo->prepare("SELECT id, department FROM employees WHERE auth_user_id = ? LIMIT 1");
$st->execute([(int)$iduserlogin]);
$filterMyEmployee = $st->fetch(PDO::FETCH_ASSOC) ?: null;
if (!$filterMyEmployee) { $filterMy = false; }
}
$sql = " $sql = "
SELECT d.*, SELECT d.*,
s.name AS subject_name, s.name AS subject_name,
@@ -26,11 +36,22 @@ $sql = "
LEFT JOIN scad_deadline_employee de ON de.deadline_id = d.id LEFT JOIN scad_deadline_employee de ON de.deadline_id = d.id
LEFT JOIN employees e ON e.id = de.employee_id LEFT JOIN employees e ON e.id = de.employee_id
"; ";
$where = [];
$params = []; $params = [];
if ($filterSubjectId) { if ($filterSubjectId) {
$sql .= " WHERE d.subject_id = ?"; $where[] = "d.subject_id = ?";
$params[] = $filterSubjectId; $params[] = $filterSubjectId;
} }
if ($filterMy && $filterMyEmployee) {
$where[] = "(d.id IN (SELECT deadline_id FROM scad_deadline_employee WHERE employee_id = ?)"
. " OR (? <> '' AND FIND_IN_SET(?, REPLACE(d.departments, ', ', ',')) > 0))";
$params[] = (int)$filterMyEmployee['id'];
$params[] = (string)($filterMyEmployee['department'] ?? '');
$params[] = (string)($filterMyEmployee['department'] ?? '');
}
if (!empty($where)) {
$sql .= " WHERE " . implode(' AND ', $where);
}
$sql .= " GROUP BY d.id ORDER BY (d.status = 'completed') ASC, d.due_date ASC"; $sql .= " GROUP BY d.id ORDER BY (d.status = 'completed') ASC, d.due_date ASC";
$stmt = $pdo->prepare($sql); $stmt = $pdo->prepare($sql);
@@ -277,10 +298,29 @@ $today = date('Y-m-d');
justify-content: space-between; justify-content: space-between;
} }
.header-menu-btn {
width: 38px !important;
height: 38px !important;
padding: 0 !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
line-height: 1 !important;
font-size: 1rem !important;
position: relative;
}
.header-menu-btn i {
display: block;
line-height: 1;
margin: 0;
font-size: 1rem;
}
.header-menu-btn::after { display: none !important; }
@media (max-width: 575.98px) { @media (max-width: 575.98px) {
.scad-card .card-header { flex-direction: column; gap: 0.75rem; } .scad-card .card-header { flex-direction: column; gap: 0.75rem; align-items: flex-start !important; }
.header-actions { width: 100%; } .header-actions { width: 100%; justify-content: flex-end; }
.header-actions .btn { width: 100%; justify-content: center; } .header-actions #btnAddDeadline { flex: 1; justify-content: center; }
.filter-bar .form-select { width: 100%; } .filter-bar .form-select { width: 100%; }
} }
</style> </style>
@@ -292,6 +332,8 @@ $today = date('Y-m-d');
<div class="page-wrapper"> <div class="page-wrapper">
<div class="page-content"> <div class="page-content">
<?php include(__DIR__ . '/include/my_deadlines_widget.php'); ?>
<?php if ($filterSubjectId): ?> <?php if ($filterSubjectId): ?>
<div class="subject-filter-banner"> <div class="subject-filter-banner">
<div> <div>
@@ -306,60 +348,105 @@ $today = date('Y-m-d');
</div> </div>
<?php endif; ?> <?php endif; ?>
<!-- Filter Bar --> <?php if ($filterMy): ?>
<div class="filter-bar mb-3"> <div class="subject-filter-banner">
<div class="row g-2 align-items-center mb-2"> <div>
<div class="col-12 col-sm-6 col-md-auto"> <i class="fa-solid fa-user-check me-2"></i>
<select id="filterStatus" class="form-select"> <strong>Le mie scadenze</strong>
<?php if ($filterSubjectId): ?> <span class="text-muted ms-2">(assegnate a me o al reparto <?= htmlspecialchars($filterMyEmployee['department'] ?? '—', ENT_QUOTES, 'UTF-8') ?>)</span>
<option value="" selected>Stato: Tutti</option>
<option value="non-completata">Stato: Non completate</option>
<?php else: ?>
<option value="non-completata" selected>Stato: Non completate</option>
<option value="">Stato: Tutti</option>
<?php endif; ?>
<option value="attiva">Attive</option>
<option value="in-scadenza">In scadenza</option>
<option value="scaduta">Scadute</option>
<option value="completata">Completate</option>
</select>
</div>
<div class="col-12 col-sm-6 col-md-auto">
<select id="filterSubject" class="form-select">
<option value="">Argomento: Tutti</option>
<?php foreach ($subjects as $s): ?>
<option value="<?= (int)$s['id'] ?>" <?= $filterSubjectId === (int)$s['id'] ? 'selected' : '' ?>><?= htmlspecialchars($s['name'], ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-12 col-sm-6 col-md-auto">
<select id="filterDepartment" class="form-select">
<option value="">Reparto: Tutti</option>
<?php foreach ($departments as $dept): ?>
<option value="<?= htmlspecialchars($dept, ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($dept, ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-12 col-sm-6 col-md-auto">
<select id="filterEmployee" class="form-select">
<option value="">Responsabile: Tutti</option>
<?php foreach ($employees as $emp): ?>
<option value="<?= htmlspecialchars(trim($emp['first_name'] . ' ' . $emp['last_name']), ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars(trim($emp['first_name'] . ' ' . $emp['last_name']), ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
</div> </div>
<div class="row g-2 align-items-center"> <a href="scadenzario/index.php" class="btn btn-sm btn-light border">
<div class="col-12 col-sm-6 col-md-auto"> <i class="fa-solid fa-xmark me-1"></i> Tutte le scadenze
<input type="text" class="form-control" id="filterDueRange" placeholder="Scadenza: da — a" readonly style="font-size:0.85rem;border-color:#d0d9e8;min-width:220px;background:#fff"> </a>
</div> </div>
<div class="col-12 col-sm-6 col-md-auto"> <?php endif; ?>
<input type="text" class="form-control" id="filterCheckRange" placeholder="Controllo: da — a" readonly style="font-size:0.85rem;border-color:#d0d9e8;min-width:220px;background:#fff">
</div> <!-- Filter Toolbar -->
<div class="col-12 col-sm-auto"> <div class="filter-toolbar mb-3">
<button id="btnResetFilters" class="btn btn-sm btn-light border w-100 w-sm-auto" title="Reset filtri"> <div class="d-flex align-items-center gap-2">
<i class="fa-solid fa-rotate-left me-1"></i> Reset <button type="button" class="btn btn-scad-outline d-inline-flex align-items-center gap-2 flex-shrink-0" data-bs-toggle="modal" data-bs-target="#filtersModal">
</button> <i class="fa-solid fa-filter"></i>
<span>Filtri</span>
<span id="filterCountBadge" class="badge bg-primary rounded-pill d-none" style="font-size:0.7rem">0</span>
</button>
<button id="btnResetFilters" type="button" class="btn btn-light border d-inline-flex align-items-center justify-content-center gap-1 flex-shrink-0" title="Reset filtri" style="min-width:38px;height:38px">
<i class="fa-solid fa-rotate-left"></i>
<span class="d-none d-sm-inline">Reset</span>
</button>
<span id="activeFiltersSummary" class="text-muted small text-truncate d-none d-md-inline"></span>
</div>
<div id="activeFiltersSummaryMobile" class="text-muted small d-md-none mt-1" style="padding-left:0.25rem"></div>
</div>
<!-- Filters Modal -->
<div class="modal fade" id="filtersModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="fa-solid fa-filter me-2"></i>Filtri scadenze</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Chiudi"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label fw-semibold">Stato</label>
<select id="filterStatus" class="form-select">
<?php if ($filterSubjectId): ?>
<option value="" selected>Tutti</option>
<option value="non-completata">Non completate</option>
<?php else: ?>
<option value="non-completata" selected>Non completate</option>
<option value="">Tutti</option>
<?php endif; ?>
<option value="attiva">Attive</option>
<option value="in-scadenza">In scadenza</option>
<option value="scaduta">Scadute</option>
<option value="completata">Completate</option>
</select>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Argomento</label>
<select id="filterSubject" class="form-select">
<option value="">Tutti</option>
<?php foreach ($subjects as $s): ?>
<option value="<?= (int)$s['id'] ?>" <?= $filterSubjectId === (int)$s['id'] ? 'selected' : '' ?>><?= htmlspecialchars($s['name'], ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Reparto</label>
<select id="filterDepartment" class="form-select">
<option value="">Tutti</option>
<?php foreach ($departments as $dept): ?>
<option value="<?= htmlspecialchars($dept, ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($dept, ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Responsabile</label>
<select id="filterEmployee" class="form-select">
<option value="">Tutti</option>
<?php foreach ($employees as $emp): ?>
<option value="<?= htmlspecialchars(trim($emp['first_name'] . ' ' . $emp['last_name']), ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars(trim($emp['first_name'] . ' ' . $emp['last_name']), ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Data scadenza (intervallo)</label>
<input type="text" class="form-control" id="filterDueRange" placeholder="da — a" readonly>
</div>
<div class="mb-0">
<label class="form-label fw-semibold">Data ultimo controllo (intervallo)</label>
<input type="text" class="form-control" id="filterCheckRange" placeholder="da — a" readonly>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" id="btnResetFiltersModal">
<i class="fa-solid fa-rotate-left me-1"></i> Reset
</button>
<button type="button" class="btn btn-scad-primary" data-bs-dismiss="modal">
<i class="fa-solid fa-check me-1"></i> Applica
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -367,20 +454,34 @@ $today = date('Y-m-d');
<!-- Main Card --> <!-- Main Card -->
<div class="card scad-card"> <div class="card scad-card">
<div class="card-header d-flex align-items-center justify-content-between flex-wrap gap-2"> <div class="card-header d-flex align-items-center justify-content-between flex-wrap gap-2">
<h5><i class="fa-solid fa-calendar-check me-2"></i>Lista Scadenze</h5> <h5 class="d-none d-md-flex align-items-center"><i class="fa-solid fa-calendar-check me-2"></i>Lista Scadenze</h5>
<div class="header-actions d-flex gap-2 flex-wrap"> <div class="header-actions d-flex gap-2 flex-wrap">
<a href="scadenzario/subjects/index.php" class="btn btn-scad-outline d-inline-flex align-items-center gap-2"> <!-- Desktop (≥md): tutte le azioni visibili -->
<a href="scadenzario/subjects/index.php" class="btn btn-scad-outline d-none d-md-inline-flex align-items-center gap-2">
<i class="fa-solid fa-tags"></i><span>Argomenti</span> <i class="fa-solid fa-tags"></i><span>Argomenti</span>
</a> </a>
<a href="scadenzario/calendar.php" class="btn btn-scad-outline d-inline-flex align-items-center gap-2"> <a href="scadenzario/calendar.php" class="btn btn-scad-outline d-none d-md-inline-flex align-items-center gap-2">
<i class="fa-solid fa-calendar-days"></i><span>Calendario</span> <i class="fa-solid fa-calendar-days"></i><span>Calendario</span>
</a> </a>
<button class="btn btn-scad-outline d-inline-flex align-items-center gap-2" id="btnStampa"> <button class="btn btn-scad-outline d-none d-md-inline-flex align-items-center gap-2" id="btnStampa">
<i class="fa-solid fa-print"></i><span>Stampa</span> <i class="fa-solid fa-print"></i><span>Stampa</span>
</button> </button>
<button class="btn btn-scad-primary d-inline-flex align-items-center gap-2" id="btnAddDeadline"> <button class="btn btn-scad-primary d-inline-flex align-items-center gap-2" id="btnAddDeadline">
<i class="fa-solid fa-plus"></i><span>Nuova Scadenza</span> <i class="fa-solid fa-plus"></i><span>Nuova Scadenza</span>
</button> </button>
<!-- Mobile (<md): menu a tendina con le altre azioni -->
<div class="dropdown d-md-none">
<button class="btn btn-scad-outline header-menu-btn" type="button" data-bs-toggle="dropdown" aria-expanded="false" title="Altre azioni">
<i class="fa-solid fa-bars"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item d-flex align-items-center gap-2" href="scadenzario/subjects/index.php"><i class="fa-solid fa-tags"></i> Argomenti</a></li>
<li><a class="dropdown-item d-flex align-items-center gap-2" href="scadenzario/calendar.php"><i class="fa-solid fa-calendar-days"></i> Calendario</a></li>
<li><button type="button" class="dropdown-item d-flex align-items-center gap-2" id="btnStampaMobile"><i class="fa-solid fa-print"></i> Stampa</button></li>
</ul>
</div>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -705,6 +806,7 @@ $today = date('Y-m-d');
onChange: function() { onChange: function() {
if (table) table.draw(); if (table) table.draw();
filterCards(); filterCards();
if (typeof updateFilterBadge === 'function') updateFilterBadge();
} }
}; };
var fpDue = flatpickr('#filterDueRange', fpOpts); var fpDue = flatpickr('#filterDueRange', fpOpts);
@@ -832,11 +934,34 @@ $today = date('Y-m-d');
}); });
} }
function updateFilterBadge() {
var active = 0;
var summary = [];
var st = $('#filterStatus').val();
if (st && st !== 'non-completata') { active++; summary.push($('#filterStatus option:selected').text()); }
var subj = $('#filterSubject').val();
if (subj) { active++; summary.push('Argomento: ' + $('#filterSubject option:selected').text()); }
var dept = $('#filterDepartment').val();
if (dept) { active++; summary.push('Reparto: ' + dept); }
var emp = $('#filterEmployee').val();
if (emp) { active++; summary.push('Responsabile: ' + emp); }
if (fpDue.selectedDates.length) { active++; summary.push('Scadenza: ' + $('#filterDueRange').val()); }
if (fpCheck.selectedDates.length) { active++; summary.push('Controllo: ' + $('#filterCheckRange').val()); }
var $badge = $('#filterCountBadge');
if (active > 0) $badge.text(active).removeClass('d-none');
else $badge.addClass('d-none');
var summaryText = summary.length ? summary.slice(0, 2).join(' • ') + (summary.length > 2 ? ' +' + (summary.length - 2) : '') : '';
$('#activeFiltersSummary, #activeFiltersSummaryMobile').text(summaryText);
}
$('#filterStatus, #filterDepartment, #filterEmployee, #filterSubject').on('change', function() { $('#filterStatus, #filterDepartment, #filterEmployee, #filterSubject').on('change', function() {
if (table) table.draw(); if (table) table.draw();
filterCards(); filterCards();
updateFilterBadge();
}); });
$('#btnResetFilters').on('click', function() { function resetFilters() {
$('#filterStatus').val('non-completata'); $('#filterStatus').val('non-completata');
$('#filterDepartment').val(''); $('#filterDepartment').val('');
$('#filterEmployee').val(''); $('#filterEmployee').val('');
@@ -845,11 +970,21 @@ $today = date('Y-m-d');
fpCheck.clear(); fpCheck.clear();
if (table) table.draw(); if (table) table.draw();
filterCards(); filterCards();
}); updateFilterBadge();
}
$('#btnResetFilters, #btnResetFiltersModal').on('click', resetFilters);
// Apply URL filters (e.g. from dashboard widgets)
(function () {
var qs = new URLSearchParams(window.location.search);
var qStatus = qs.get('filter_status');
if (qStatus) $('#filterStatus').val(qStatus);
})();
// Apply default filter on load // Apply default filter on load
if (table) table.draw(); if (table) table.draw();
filterCards(); filterCards();
updateFilterBadge();
// --- Modal --- // --- Modal ---
var modal = new bootstrap.Modal(document.getElementById('deadlineModal')); var modal = new bootstrap.Modal(document.getElementById('deadlineModal'));
@@ -1085,7 +1220,7 @@ $today = date('Y-m-d');
} }
// Stampa // Stampa
document.getElementById('btnStampa').addEventListener('click', function() { function doStampa() {
var params = []; var params = [];
var s = $('#filterStatus').val(); var s = $('#filterStatus').val();
var d = $('#filterDepartment').val(); var d = $('#filterDepartment').val();
@@ -1100,7 +1235,10 @@ $today = date('Y-m-d');
if (chkDates.length >= 1) params.push('check_from=' + formatDate(chkDates[0])); if (chkDates.length >= 1) params.push('check_from=' + formatDate(chkDates[0]));
if (chkDates.length >= 2) params.push('check_to=' + formatDate(chkDates[1])); if (chkDates.length >= 2) params.push('check_to=' + formatDate(chkDates[1]));
window.open('scadenzario/print.php' + (params.length ? '?' + params.join('&') : ''), '_blank'); window.open('scadenzario/print.php' + (params.length ? '?' + params.join('&') : ''), '_blank');
}); }
document.getElementById('btnStampa').addEventListener('click', doStampa);
var btnStampaMobile = document.getElementById('btnStampaMobile');
if (btnStampaMobile) btnStampaMobile.addEventListener('click', doStampa);
}); });
</script> </script>
</body> </body>