364 lines
13 KiB
PHP
364 lines
13 KiB
PHP
<?php
|
|
include('include/headscript.php');
|
|
|
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
|
|
|
/* ==========================================
|
|
PERMISSIONS (mirror trainings.php)
|
|
========================================== */
|
|
$isHrManager = Auth::user()->hasRole('Admin')
|
|
|| Auth::user()->hasRole('Superuser')
|
|
|| Auth::user()->hasRole('employee-hr')
|
|
|| Auth::user()->hasRole('manager');
|
|
|
|
if (!$isHrManager) {
|
|
header('Location: employee-profile.php');
|
|
exit;
|
|
}
|
|
|
|
/* Dropdown data */
|
|
$employees = $pdo->query("
|
|
SELECT id, first_name, last_name, employee_code
|
|
FROM employees
|
|
ORDER BY last_name, first_name
|
|
")->fetchAll(PDO::FETCH_ASSOC);
|
|
$topics = $pdo->query("
|
|
SELECT id, name FROM training_topics WHERE is_active = 1 ORDER BY sort_order, name
|
|
")->fetchAll(PDO::FETCH_ASSOC);
|
|
$departments = $pdo->query("
|
|
SELECT id, name FROM departments WHERE is_active = 1 ORDER BY sort_order, name
|
|
")->fetchAll(PDO::FETCH_ASSOC);
|
|
?>
|
|
<!doctype html>
|
|
<html lang="it">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
|
<?php include('cssinclude.php'); ?>
|
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.9/index.global.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/@fullcalendar/core@6.1.9/locales/it.global.min.js"></script>
|
|
<title>Calendario Formazione - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
|
|
|
<style>
|
|
body {
|
|
font-size: 1.05rem;
|
|
background: #f8fafc;
|
|
}
|
|
|
|
.card {
|
|
border-radius: 16px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
}
|
|
|
|
.back-dashboard {
|
|
background-color: #cfe3ff !important;
|
|
color: #1f2d3d !important;
|
|
border: 1px solid #bcd4f4 !important;
|
|
border-radius: 10px;
|
|
font-weight: 600;
|
|
padding: 10px 18px;
|
|
}
|
|
|
|
.training-header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.btn-training-action {
|
|
border-radius: 10px;
|
|
font-weight: 500;
|
|
padding: 10px 16px;
|
|
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
|
|
transition: all 0.2s ease-in-out;
|
|
color: #fff !important;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.btn-training-action:hover {
|
|
transform: translateY(-2px);
|
|
color: #fff !important;
|
|
}
|
|
|
|
.btn-training-topics {
|
|
background-color: #0d6efd !important;
|
|
border: 1px solid #0b5ed7 !important;
|
|
}
|
|
|
|
.btn-training-topics:hover {
|
|
background-color: #0b5ed7 !important;
|
|
}
|
|
|
|
.btn-training-history {
|
|
background-color: #2563eb !important;
|
|
border: 1px solid #1d4ed8 !important;
|
|
}
|
|
|
|
.btn-training-history:hover {
|
|
background-color: #1d4ed8 !important;
|
|
}
|
|
|
|
@media (max-width: 767.98px) {
|
|
.training-header-actions {
|
|
width: 100%;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.training-header-actions .btn,
|
|
.training-header-actions a {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.legend {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.legend-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
font-size: 0.85rem;
|
|
color: #64748b;
|
|
}
|
|
|
|
.legend-dot {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* FullCalendar overrides */
|
|
.fc {
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.fc .fc-toolbar-title {
|
|
font-size: 1.15rem;
|
|
font-weight: 700;
|
|
color: #2c3e6b;
|
|
}
|
|
|
|
.fc .fc-button-primary {
|
|
background: #5a8fd8;
|
|
border-color: #5a8fd8;
|
|
font-weight: 600;
|
|
font-size: 0.82rem;
|
|
border-radius: 0.4rem;
|
|
}
|
|
|
|
.fc .fc-button-primary:hover {
|
|
background: #4578c0;
|
|
border-color: #4578c0;
|
|
}
|
|
|
|
.fc .fc-button-primary:disabled {
|
|
background: #9bbce6;
|
|
border-color: #9bbce6;
|
|
}
|
|
|
|
.fc .fc-button-primary:not(:disabled).fc-button-active {
|
|
background: #2c3e6b;
|
|
border-color: #2c3e6b;
|
|
}
|
|
|
|
.fc .fc-daygrid-day-number {
|
|
color: #2c3e6b;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.fc .fc-daygrid-day.fc-day-today {
|
|
background: #f0f4ff;
|
|
}
|
|
|
|
.fc .fc-event {
|
|
border-radius: 0.3rem;
|
|
padding: 2px 4px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.fc .fc-event:hover {
|
|
filter: brightness(0.92);
|
|
}
|
|
|
|
.fc .fc-list-event:hover td {
|
|
background: #f0f4ff;
|
|
}
|
|
|
|
@media (max-width: 767.98px) {
|
|
.card-header {
|
|
flex-direction: column;
|
|
align-items: flex-start !important;
|
|
gap: .5rem;
|
|
}
|
|
|
|
.fc .fc-toolbar {
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.fc .fc-toolbar-title {
|
|
font-size: 1rem;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="wrapper" id="appWrapper">
|
|
<?php include('include/navbar.php'); ?>
|
|
<?php include('include/topbar.php'); ?>
|
|
|
|
<div class="page-wrapper">
|
|
<div class="page-content">
|
|
<div class="card p-3">
|
|
<div class="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
|
|
<h5 class="mb-0">📅 Calendario Formazione</h5>
|
|
|
|
<div class="training-header-actions">
|
|
<?php if (userCan('hr.training_topics.view')): ?>
|
|
<a href="training_topics.php" class="btn btn-training-action btn-training-topics">
|
|
📘 Corsi Formazione
|
|
</a>
|
|
<?php endif; ?>
|
|
|
|
<?php if (userCan('hr.trainings.view')): ?>
|
|
<a href="trainings.php" class="btn btn-training-action btn-training-history">
|
|
📚 Gestione Formazione
|
|
</a>
|
|
<?php endif; ?>
|
|
|
|
<button type="button" class="btn back-dashboard" onclick="location.href='production_dashboard.php'">
|
|
↩️ Torna alla Dashboard
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<!-- FILTERS -->
|
|
<div class="row g-2 mb-3">
|
|
<div class="col-6 col-md-3">
|
|
<label class="form-label small text-muted mb-1">Stato</label>
|
|
<select id="filterStatus" class="form-select">
|
|
<option value="">Tutti</option>
|
|
<option value="expired">Scaduti</option>
|
|
<option value="due_soon">Da aggiornare</option>
|
|
<option value="compliant">Conformi</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<label class="form-label small text-muted mb-1">Corso</label>
|
|
<select id="filterTopic" class="form-select">
|
|
<option value="">Tutti</option>
|
|
<?php foreach ($topics as $t): ?>
|
|
<option value="<?= (int)$t['id'] ?>"><?= htmlspecialchars($t['name'], ENT_QUOTES, 'UTF-8') ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<label class="form-label small text-muted mb-1">Reparto</label>
|
|
<select id="filterDepartment" class="form-select">
|
|
<option value="">Tutti</option>
|
|
<?php foreach ($departments as $d): ?>
|
|
<option value="<?= (int)$d['id'] ?>"><?= htmlspecialchars($d['name'], ENT_QUOTES, 'UTF-8') ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<label class="form-label small text-muted mb-1">Dipendente</label>
|
|
<div class="d-flex gap-2">
|
|
<select id="filterEmployee" class="form-select">
|
|
<option value="">Tutti</option>
|
|
<?php foreach ($employees as $e): ?>
|
|
<option value="<?= (int)$e['id'] ?>"><?= htmlspecialchars(trim($e['last_name'] . ' ' . $e['first_name']), ENT_QUOTES, 'UTF-8') ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<button id="btnResetFilters" type="button" class="btn btn-light border flex-shrink-0" title="Reset filtri">
|
|
<i class="fa-solid fa-rotate-left"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- LEGEND -->
|
|
<div class="legend">
|
|
<div class="legend-item"><span class="legend-dot" style="background:#dc3545"></span> Scaduto</div>
|
|
<div class="legend-item"><span class="legend-dot" style="background:#e8930c"></span> Da aggiornare</div>
|
|
<div class="legend-item"><span class="legend-dot" style="background:#198754"></span> Conforme</div>
|
|
</div>
|
|
|
|
<div id="calendar"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php include('include/footer.php'); ?>
|
|
</div>
|
|
|
|
<?php include('jsinclude.php'); ?>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var isMobile = window.innerWidth < 768;
|
|
var calendarEl = document.getElementById('calendar');
|
|
|
|
var calendar = new FullCalendar.Calendar(calendarEl, {
|
|
locale: 'it',
|
|
initialView: isMobile ? 'listMonth' : 'dayGridMonth',
|
|
headerToolbar: {
|
|
left: 'prev,next today',
|
|
center: 'title',
|
|
right: isMobile ? 'listMonth,dayGridMonth' : 'dayGridMonth,listMonth'
|
|
},
|
|
height: 'auto',
|
|
navLinks: true,
|
|
eventSources: [{
|
|
url: 'ajax/trainings/calendar_events.php',
|
|
extraParams: function() {
|
|
return {
|
|
status: document.getElementById('filterStatus').value,
|
|
topic_id: document.getElementById('filterTopic').value,
|
|
department_id: document.getElementById('filterDepartment').value,
|
|
employee_id: document.getElementById('filterEmployee').value
|
|
};
|
|
},
|
|
failure: function() {
|
|
if (window.Swal) Swal.fire('Errore', 'Impossibile caricare gli eventi.', 'error');
|
|
}
|
|
}],
|
|
eventClick: function(info) {
|
|
info.jsEvent.preventDefault();
|
|
if (info.event.url) window.location.href = info.event.url;
|
|
},
|
|
windowResize: function() {
|
|
calendar.changeView(window.innerWidth < 768 ? 'listMonth' : 'dayGridMonth');
|
|
}
|
|
});
|
|
calendar.render();
|
|
|
|
document.querySelectorAll('#filterStatus, #filterTopic, #filterDepartment, #filterEmployee').forEach(function(el) {
|
|
el.addEventListener('change', function() {
|
|
calendar.refetchEvents();
|
|
});
|
|
});
|
|
|
|
document.getElementById('btnResetFilters').addEventListener('click', function() {
|
|
['filterStatus', 'filterTopic', 'filterDepartment', 'filterEmployee'].forEach(function(id) {
|
|
document.getElementById(id).value = '';
|
|
});
|
|
calendar.refetchEvents();
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|