deadline widget
This commit is contained in:
parent
1fadc22178
commit
dd5edab2f3
@ -296,6 +296,11 @@
|
||||
<div class="page-wrapper">
|
||||
<div class="page-content">
|
||||
|
||||
<?php
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
include(__DIR__ . '/scadenzario/include/my_deadlines_widget.php');
|
||||
?>
|
||||
|
||||
<h3 class="dashboard-title">Dashboard Produzione</h3>
|
||||
|
||||
<!-- ===== STATISTICHE PRINCIPALI ===== -->
|
||||
|
||||
@ -98,58 +98,81 @@ $departments = $pdo->query("SELECT DISTINCT department FROM employees WHERE depa
|
||||
<div class="page-wrapper">
|
||||
<div class="page-content">
|
||||
|
||||
<nav class="scad-breadcrumb" aria-label="breadcrumb">
|
||||
<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>
|
||||
<?php include(__DIR__ . '/include/my_deadlines_widget.php'); ?>
|
||||
|
||||
<div class="d-flex gap-2 mb-3">
|
||||
<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 class="d-flex gap-2 mb-3 flex-wrap align-items-center">
|
||||
<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-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" 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 mb-2" style="padding-left:0.25rem"></div>
|
||||
|
||||
<div class="filter-bar mb-3">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-12 col-sm-6 col-md-auto">
|
||||
<select id="filterStatus" class="form-select" style="font-size:0.85rem;border-color:#d0d9e8;min-width:160px">
|
||||
<option value="non-completata" selected>Stato: Non completate</option>
|
||||
<option value="">Stato: Tutti</option>
|
||||
<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="filterDepartment" class="form-select" style="font-size:0.85rem;border-color:#d0d9e8;min-width:160px">
|
||||
<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" style="font-size:0.85rem;border-color:#d0d9e8;min-width:160px">
|
||||
<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 class="col-12 col-sm-auto">
|
||||
<button id="btnResetFilters" class="btn btn-sm btn-light border w-100 w-sm-auto" title="Reset filtri">
|
||||
<i class="fa-solid fa-rotate-left me-1"></i> Reset
|
||||
</button>
|
||||
<!-- 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 calendario</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">
|
||||
<option value="non-completata" selected>Non completate</option>
|
||||
<option value="">Tutti</option>
|
||||
<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">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-0">
|
||||
<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>
|
||||
<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 class="card scad-card">
|
||||
<div class="card-header d-flex align-items-center justify-content-between">
|
||||
<h5><i class="fa-solid fa-calendar-days me-2"></i>Calendario Scadenze</h5>
|
||||
<div class="card-header d-flex align-items-center justify-content-between flex-wrap gap-2">
|
||||
<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 class="card-body">
|
||||
<div class="legend">
|
||||
@ -211,15 +234,41 @@ $departments = $pdo->query("SELECT DISTINCT department FROM employees WHERE depa
|
||||
calendar.render();
|
||||
|
||||
// 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) {
|
||||
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('filterDepartment').value = '';
|
||||
document.getElementById('filterEmployee').value = '';
|
||||
calendar.refetchEvents();
|
||||
});
|
||||
updateFilterBadge();
|
||||
}
|
||||
document.getElementById('btnResetFilters').addEventListener('click', resetFilters);
|
||||
document.getElementById('btnResetFiltersModal').addEventListener('click', resetFilters);
|
||||
|
||||
updateFilterBadge();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
91
public/userarea/scadenzario/include/my_deadlines_widget.php
Normal file
91
public/userarea/scadenzario/include/my_deadlines_widget.php
Normal file
@ -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>
|
||||
@ -13,6 +13,16 @@ if ($filterSubjectId) {
|
||||
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 = "
|
||||
SELECT d.*,
|
||||
s.name AS subject_name,
|
||||
@ -26,11 +36,22 @@ $sql = "
|
||||
LEFT JOIN scad_deadline_employee de ON de.deadline_id = d.id
|
||||
LEFT JOIN employees e ON e.id = de.employee_id
|
||||
";
|
||||
$where = [];
|
||||
$params = [];
|
||||
if ($filterSubjectId) {
|
||||
$sql .= " WHERE d.subject_id = ?";
|
||||
$where[] = "d.subject_id = ?";
|
||||
$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";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
@ -277,10 +298,29 @@ $today = date('Y-m-d');
|
||||
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) {
|
||||
.scad-card .card-header { flex-direction: column; gap: 0.75rem; }
|
||||
.header-actions { width: 100%; }
|
||||
.header-actions .btn { width: 100%; justify-content: center; }
|
||||
.scad-card .card-header { flex-direction: column; gap: 0.75rem; align-items: flex-start !important; }
|
||||
.header-actions { width: 100%; justify-content: flex-end; }
|
||||
.header-actions #btnAddDeadline { flex: 1; justify-content: center; }
|
||||
.filter-bar .form-select { width: 100%; }
|
||||
}
|
||||
</style>
|
||||
@ -292,6 +332,8 @@ $today = date('Y-m-d');
|
||||
<div class="page-wrapper">
|
||||
<div class="page-content">
|
||||
|
||||
<?php include(__DIR__ . '/include/my_deadlines_widget.php'); ?>
|
||||
|
||||
<?php if ($filterSubjectId): ?>
|
||||
<div class="subject-filter-banner">
|
||||
<div>
|
||||
@ -306,60 +348,105 @@ $today = date('Y-m-d');
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Filter Bar -->
|
||||
<div class="filter-bar mb-3">
|
||||
<div class="row g-2 align-items-center mb-2">
|
||||
<div class="col-12 col-sm-6 col-md-auto">
|
||||
<select id="filterStatus" class="form-select">
|
||||
<?php if ($filterSubjectId): ?>
|
||||
<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>
|
||||
<?php if ($filterMy): ?>
|
||||
<div class="subject-filter-banner">
|
||||
<div>
|
||||
<i class="fa-solid fa-user-check me-2"></i>
|
||||
<strong>Le mie scadenze</strong>
|
||||
<span class="text-muted ms-2">(assegnate a me o al reparto <?= htmlspecialchars($filterMyEmployee['department'] ?? '—', ENT_QUOTES, 'UTF-8') ?>)</span>
|
||||
</div>
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-12 col-sm-6 col-md-auto">
|
||||
<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">
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-auto">
|
||||
<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>
|
||||
<div class="col-12 col-sm-auto">
|
||||
<button id="btnResetFilters" class="btn btn-sm btn-light border w-100 w-sm-auto" title="Reset filtri">
|
||||
<i class="fa-solid fa-rotate-left me-1"></i> Reset
|
||||
</button>
|
||||
<a href="scadenzario/index.php" class="btn btn-sm btn-light border">
|
||||
<i class="fa-solid fa-xmark me-1"></i> Tutte le scadenze
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Filter Toolbar -->
|
||||
<div class="filter-toolbar mb-3">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<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">
|
||||
<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>
|
||||
@ -367,20 +454,34 @@ $today = date('Y-m-d');
|
||||
<!-- Main Card -->
|
||||
<div class="card scad-card">
|
||||
<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">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
</button>
|
||||
|
||||
<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>
|
||||
</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 class="card-body">
|
||||
@ -705,6 +806,7 @@ $today = date('Y-m-d');
|
||||
onChange: function() {
|
||||
if (table) table.draw();
|
||||
filterCards();
|
||||
if (typeof updateFilterBadge === 'function') updateFilterBadge();
|
||||
}
|
||||
};
|
||||
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() {
|
||||
if (table) table.draw();
|
||||
filterCards();
|
||||
updateFilterBadge();
|
||||
});
|
||||
$('#btnResetFilters').on('click', function() {
|
||||
function resetFilters() {
|
||||
$('#filterStatus').val('non-completata');
|
||||
$('#filterDepartment').val('');
|
||||
$('#filterEmployee').val('');
|
||||
@ -845,11 +970,21 @@ $today = date('Y-m-d');
|
||||
fpCheck.clear();
|
||||
if (table) table.draw();
|
||||
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
|
||||
if (table) table.draw();
|
||||
filterCards();
|
||||
updateFilterBadge();
|
||||
|
||||
// --- Modal ---
|
||||
var modal = new bootstrap.Modal(document.getElementById('deadlineModal'));
|
||||
@ -1085,7 +1220,7 @@ $today = date('Y-m-d');
|
||||
}
|
||||
|
||||
// Stampa
|
||||
document.getElementById('btnStampa').addEventListener('click', function() {
|
||||
function doStampa() {
|
||||
var params = [];
|
||||
var s = $('#filterStatus').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 >= 2) params.push('check_to=' + formatDate(chkDates[1]));
|
||||
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>
|
||||
</body>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user