deadline widget
This commit is contained in:
@@ -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 ===== -->
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user