Files
zibo-dashboard/public/userarea/training_topics.php
T
2026-07-24 08:32:50 +02:00

880 lines
40 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
include('include/headscript.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
/* ==========================================
PAGE DATA
========================================== */
require_once __DIR__ . '/include/training_coverage.php';
$sql = "
SELECT tt.*,
(SELECT COUNT(*) FROM employee_trainings et WHERE et.training_topic_id = tt.id) AS trainings_count
FROM training_topics tt
ORDER BY tt.sort_order ASC, tt.name ASC
";
$topics = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
/* Coperture: [topic_id => [ ['id'=>..,'name'=>..], ... ]] */
$coverageRows = $pdo->query("
SELECT c.topic_id, c.covered_topic_id, tt.name AS covered_name
FROM training_topic_coverage c
JOIN training_topics tt ON tt.id = c.covered_topic_id
ORDER BY tt.sort_order, tt.name
")->fetchAll(PDO::FETCH_ASSOC);
$coverageByTopic = [];
foreach ($coverageRows as $cr) {
$coverageByTopic[(int)$cr['topic_id']][] = [
'id' => (int)$cr['covered_topic_id'],
'name' => $cr['covered_name'],
];
}
/* Mappa inversa: chi copre questo corso */
$coveredByTopic = [];
foreach ($coverageRows as $cr) {
$coveredByTopic[(int)$cr['covered_topic_id']][] = (int)$cr['topic_id'];
}
$topicNames = [];
foreach ($topics as $t) $topicNames[(int)$t['id']] = $t['name'];
?>
<!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'); ?>
<title>Gestione Corsi di Formazione - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
<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;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease-in-out;
}
.back-dashboard:hover {
background-color: #b9d3ff !important;
transform: translateY(-2px);
}
.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;
}
.btn-training-action:hover {
transform: translateY(-2px);
color: #fff !important;
}
.btn-training-history {
background-color: #0d6efd !important;
border: 1px solid #0b5ed7 !important;
}
.btn-training-history:hover {
background-color: #0b5ed7 !important;
}
.btn-training-calendar {
background-color: #2563eb !important;
border: 1px solid #1d4ed8 !important;
}
.btn-training-calendar:hover {
background-color: #1d4ed8 !important;
}
@media (max-width: 767.98px) {
.training-header-actions {
width: 100%;
flex-direction: column;
}
.training-header-actions .btn {
width: 100%;
}
}
.btn-add {
background-color: #0d6efd;
color: #fff;
border-radius: 8px;
padding: 10px 20px;
font-weight: 500;
}
.btn-add:hover {
background-color: #0b5ed7;
transform: scale(1.02);
}
.training-shortcuts {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 18px;
}
.training-shortcut-btn {
display: inline-flex;
align-items: center;
gap: 8px;
border-radius: 10px;
padding: 10px 16px;
font-weight: 600;
text-decoration: none;
border: 1px solid #bcd4f4;
background: #cfe3ff;
color: #1f2d3d;
box-shadow: 0 3px 8px rgba(0, 0, 0, .08);
transition: all .2s ease-in-out;
}
.training-shortcut-btn:hover {
background: #b9d3ff;
color: #1f2d3d;
transform: translateY(-2px);
}
@media (max-width: 767.98px) {
.training-shortcut-btn {
width: 100%;
justify-content: center;
}
}
.table thead {
background-color: #cfe3ff;
color: #1f2d3d;
}
.modal-content {
border-radius: 16px;
}
#tabellaTopics thead th {
text-align: center;
vertical-align: middle;
}
.badge-status {
padding: 0.25rem 0.6rem;
border-radius: 999px;
font-size: 0.8rem;
font-weight: 600;
}
.badge-status.active {
background-color: #d1fae5;
color: #065f46;
}
.badge-status.inactive {
background-color: #e5e7eb;
color: #374151;
}
.description-cell {
max-width: 280px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
.num-pill {
display: inline-block;
padding: 2px 10px;
border-radius: 999px;
background: #eef2ff;
color: #3730a3;
font-weight: 600;
font-size: 0.85rem;
}
@media (max-width: 767.98px) {
.card-header {
flex-direction: column;
align-items: flex-start !important;
gap: .5rem;
}
.back-dashboard {
width: 100%;
}
.btn-add {
width: 100%;
}
}
.tt-card {
border: 1px solid #e2e8f0;
border-radius: 14px;
padding: 14px 16px;
margin-bottom: 12px;
background: #fff;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
}
.tt-card-title {
font-size: 1.1rem;
font-weight: 600;
color: #1f2937;
margin: 0 0 4px 0;
word-break: break-word;
}
.tt-card-desc {
color: #475569;
font-size: 0.95rem;
margin: 0 0 10px 0;
word-break: break-word;
}
.tt-card-meta {
display: flex;
flex-wrap: wrap;
gap: 8px 14px;
font-size: 0.85rem;
color: #64748b;
margin-bottom: 12px;
}
.tt-card-meta b {
color: #1f2937;
font-weight: 600;
}
.tt-card-actions {
display: flex;
gap: 8px;
}
.tt-card-actions .btn {
flex: 1;
}
.tt-empty {
text-align: center;
color: #94a3b8;
padding: 24px 0;
}
.cov-chip {
display: inline-block;
padding: 2px 9px;
border-radius: 999px;
background: #ede9fe;
color: #5b21b6;
border: 1px solid #ddd6fe;
font-size: 0.78rem;
font-weight: 600;
margin: 2px 3px 2px 0;
white-space: nowrap;
}
.cov-chip-parent {
background: #fef3c7;
color: #92400e;
border-color: #fde68a;
}
.cov-cell {
max-width: 240px;
text-align: left;
white-space: normal;
}
.cov-help {
font-size: .85rem;
color: #64748b;
margin-top: 4px;
}
#addCovered,
#editCovered {
min-height: 140px;
}
</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">Corsi Formazione</h5>
<div class="training-header-actions">
<?php if (userCan('hr.trainings.view')): ?>
<a href="trainings.php" class="btn btn-training-action btn-training-history">
🎓 Gestione Formazione
</a>
<a href="training_calendar.php" class="btn btn-training-action btn-training-calendar">
📅 Calendario 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">
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
<h6 class="fw-semibold mb-0">Elenco Corsi / Training Topics</h6>
<button class="btn btn-add" data-bs-toggle="modal" data-bs-target="#addTopicModal">
Aggiungi Corso
</button>
</div>
<!-- DESKTOP / TABLET ≥768px: TABLE -->
<div class="table-responsive d-none d-md-block">
<table id="tabellaTopics" class="table table-striped align-middle text-center" style="width:100%;">
<thead>
<tr>
<th>ID</th>
<th>Nome</th>
<th>Descrizione</th>
<th>Frequenza<br>(mesi)</th>
<th>Promemoria<br>(giorni)</th>
<th>Ordine</th>
<th>Stato</th>
<th>Formazioni</th>
<th>Copre</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($topics as $row): ?>
<?php
$id = (int)$row['id'];
$name = $row['name'] ?? '';
$description = $row['description'] ?? '';
$freq = $row['default_frequency_months'];
$rem = (int)($row['default_reminder_days'] ?? 30);
$sortOrder = (int)($row['sort_order'] ?? 999);
$isActive = (int)($row['is_active'] ?? 1);
$isMandatory = (int)($row['is_mandatory'] ?? 0);
$cnt = (int)($row['trainings_count'] ?? 0);
$statusClass = $isActive === 1 ? 'active' : 'inactive';
$statusLabel = $isActive === 1 ? 'Attivo' : 'Inattivo';
?>
<tr>
<td><?= $id ?></td>
<td class="fw-semibold text-start">
<?= htmlspecialchars($name) ?>
<?php if ($isMandatory === 1): ?>
<span class="badge bg-warning text-dark ms-1" title="Obbligatorio per tutti">★ Obbl.</span>
<?php endif; ?>
</td>
<td class="description-cell" title="<?= htmlspecialchars($description, ENT_QUOTES) ?>">
<?= $description !== '' ? htmlspecialchars($description) : '-' ?>
</td>
<td>
<?php if ($freq === null || $freq === ''): ?>
<span class="text-muted">una tantum</span>
<?php else: ?>
<span class="num-pill"><?= (int)$freq ?></span>
<?php endif; ?>
</td>
<td><span class="num-pill"><?= $rem ?></span></td>
<td><?= $sortOrder ?></td>
<td><span class="badge-status <?= $statusClass ?>"><?= $statusLabel ?></span></td>
<td><?= $cnt ?></td>
<td class="cov-cell">
<?php $covList = $coverageByTopic[$id] ?? []; ?>
<?php if ($covList): ?>
<?php foreach ($covList as $cv): ?>
<span class="cov-chip">⛓️ <?= htmlspecialchars($cv['name']) ?></span>
<?php endforeach; ?>
<?php else: ?>
<span class="text-muted">—</span>
<?php endif; ?>
<?php if (!empty($coveredByTopic[$id])): ?>
<div class="mt-1">
<?php foreach ($coveredByTopic[$id] as $parentId): ?>
<span class="cov-chip cov-chip-parent" title="Questo corso è assorbito da">
↑ <?= htmlspecialchars($topicNames[$parentId] ?? ('#' . $parentId)) ?>
</span>
<?php endforeach; ?>
</div>
<?php endif; ?>
</td>
<td>
<button class="btn btn-sm btn-outline-secondary edit-topic"
data-id="<?= $id ?>"
data-name="<?= htmlspecialchars($name, ENT_QUOTES) ?>"
data-description="<?= htmlspecialchars($description, ENT_QUOTES) ?>"
data-freq="<?= $freq === null ? '' : (int)$freq ?>"
data-rem="<?= $rem ?>"
data-sort_order="<?= $sortOrder ?>"
data-is_active="<?= $isActive ?>"
data-is_mandatory="<?= $isMandatory ?>"
data-covered="<?= htmlspecialchars(json_encode(array_column($coverageByTopic[$id] ?? [], 'id')), ENT_QUOTES) ?>">
✏️ Modifica
</button>
<button class="btn btn-sm btn-outline-danger delete-topic"
data-id="<?= $id ?>"
data-name="<?= htmlspecialchars($name, ENT_QUOTES) ?>"
data-count="<?= $cnt ?>">
🗑️ Cancella
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- MOBILE <768px: CARDS -->
<div class="d-block d-md-none">
<?php if (empty($topics)): ?>
<div class="tt-empty">Nessun corso presente</div>
<?php endif; ?>
<?php foreach ($topics as $row): ?>
<?php
$id = (int)$row['id'];
$name = $row['name'] ?? '';
$description = $row['description'] ?? '';
$freq = $row['default_frequency_months'];
$rem = (int)($row['default_reminder_days'] ?? 30);
$sortOrder = (int)($row['sort_order'] ?? 999);
$isActive = (int)($row['is_active'] ?? 1);
$isMandatory = (int)($row['is_mandatory'] ?? 0);
$cnt = (int)($row['trainings_count'] ?? 0);
$statusClass = $isActive === 1 ? 'active' : 'inactive';
$statusLabel = $isActive === 1 ? 'Attivo' : 'Inattivo';
$freqLabel = ($freq === null || $freq === '') ? 'una tantum' : ((int)$freq . ' mesi');
?>
<div class="tt-card">
<h6 class="tt-card-title">
<?= htmlspecialchars($name) ?>
<?php if ($isMandatory === 1): ?>
<span class="badge bg-warning text-dark ms-1" title="Obbligatorio per tutti">★ Obbl.</span>
<?php endif; ?>
</h6>
<?php if ($description !== ''): ?>
<p class="tt-card-desc"><?= htmlspecialchars($description) ?></p>
<?php endif; ?>
<div class="tt-card-meta">
<span><span class="badge-status <?= $statusClass ?>"><?= $statusLabel ?></span></span>
<span><b>Frequenza:</b> <?= htmlspecialchars($freqLabel) ?></span>
<span><b>Promemoria:</b> <?= $rem ?> gg</span>
<span><b>Formazioni:</b> <?= $cnt ?></span>
<span><b>Ordine:</b> <?= $sortOrder ?></span>
</div>
<?php $covList = $coverageByTopic[$id] ?? []; ?>
<?php if ($covList || !empty($coveredByTopic[$id])): ?>
<div class="mb-2">
<?php foreach ($covList as $cv): ?>
<span class="cov-chip">⛓️ <?= htmlspecialchars($cv['name']) ?></span>
<?php endforeach; ?>
<?php foreach (($coveredByTopic[$id] ?? []) as $parentId): ?>
<span class="cov-chip cov-chip-parent">↑ <?= htmlspecialchars($topicNames[$parentId] ?? ('#' . $parentId)) ?></span>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="tt-card-actions">
<button class="btn btn-sm btn-outline-secondary edit-topic"
data-id="<?= $id ?>"
data-name="<?= htmlspecialchars($name, ENT_QUOTES) ?>"
data-description="<?= htmlspecialchars($description, ENT_QUOTES) ?>"
data-freq="<?= $freq === null ? '' : (int)$freq ?>"
data-rem="<?= $rem ?>"
data-sort_order="<?= $sortOrder ?>"
data-is_active="<?= $isActive ?>"
data-is_mandatory="<?= $isMandatory ?>"
data-covered="<?= htmlspecialchars(json_encode(array_column($coverageByTopic[$id] ?? [], 'id')), ENT_QUOTES) ?>">
✏️ Modifica
</button>
<button class="btn btn-sm btn-outline-danger delete-topic"
data-id="<?= $id ?>"
data-name="<?= htmlspecialchars($name, ENT_QUOTES) ?>"
data-count="<?= $cnt ?>">
🗑️ Cancella
</button>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<!-- ADD -->
<div class="modal fade" id="addTopicModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-lg modal-fullscreen-sm-down">
<div class="modal-content">
<div class="modal-header" style="background-color:#cfe3ff;">
<h5 class="modal-title">Aggiungi Corso</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="addTopicForm">
<div class="mb-3">
<label class="form-label fw-semibold">Nome</label>
<input type="text" class="form-control" id="addName" name="name" placeholder="es. Sicurezza antincendio" required>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Descrizione</label>
<textarea class="form-control" id="addDescription" name="description" rows="3" placeholder="Opzionale"></textarea>
</div>
<div class="row">
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Frequenza aggiornamento</label>
<select class="form-select" id="addFreq" name="default_frequency_months">
<option value="" selected>Una tantum (nessun aggiornamento)</option>
<option value="3">3 mesi</option>
<option value="6">6 mesi</option>
<option value="12">12 mesi (1 anno)</option>
<option value="18">18 mesi</option>
<option value="24">24 mesi (2 anni)</option>
<option value="36">36 mesi (3 anni)</option>
<option value="48">48 mesi (4 anni)</option>
<option value="60">60 mesi (5 anni)</option>
</select>
</div>
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Promemoria (giorni prima della scadenza)</label>
<input type="number" class="form-control" id="addRem" name="default_reminder_days" value="30" min="0">
</div>
</div>
<div class="row">
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Ordine</label>
<input type="number" class="form-control" id="addSortOrder" name="sort_order" value="999" min="0">
</div>
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Stato</label>
<select class="form-select" id="addIsActive" name="is_active">
<option value="1" selected>Attivo</option>
<option value="0">Inattivo</option>
</select>
</div>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="addIsMandatory" value="1">
<label class="form-check-label fw-semibold" for="addIsMandatory">
Obbligatorio per tutti i dipendenti
</label>
<div class="small text-muted">
Se attivo, i dipendenti senza registrazione di questo corso compaiono come "Non presente" nello storico.
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">⛓️ Corsi assorbiti da questo</label>
<select class="form-select" id="addCovered" multiple size="6">
<?php foreach ($topics as $t): ?>
<option value="<?= (int)$t['id'] ?>"><?= htmlspecialchars($t['name']) ?></option>
<?php endforeach; ?>
</select>
<div class="cov-help">
Chi completa questo corso risulta automaticamente in regola anche per quelli selezionati.
La scadenza del corso assorbito viene ricalcolata con la sua frequenza propria.
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-add">💾 Salva</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- EDIT -->
<div class="modal fade" id="editTopicModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-lg modal-fullscreen-sm-down">
<div class="modal-content">
<div class="modal-header" style="background-color:#cfe3ff;">
<h5 class="modal-title">Modifica Corso</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="editTopicForm">
<input type="hidden" id="editTopicId">
<div class="mb-3">
<label class="form-label fw-semibold">Nome</label>
<input type="text" class="form-control" id="editName" name="name" required>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Descrizione</label>
<textarea class="form-control" id="editDescription" name="description" rows="3"></textarea>
</div>
<div class="row">
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Frequenza aggiornamento</label>
<select class="form-select" id="editFreq" name="default_frequency_months">
<option value="">Una tantum (nessun aggiornamento)</option>
<option value="3">3 mesi</option>
<option value="6">6 mesi</option>
<option value="12">12 mesi (1 anno)</option>
<option value="18">18 mesi</option>
<option value="24">24 mesi (2 anni)</option>
<option value="36">36 mesi (3 anni)</option>
<option value="48">48 mesi (4 anni)</option>
<option value="60">60 mesi (5 anni)</option>
</select>
</div>
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Promemoria (giorni prima della scadenza)</label>
<input type="number" class="form-control" id="editRem" name="default_reminder_days" min="0">
</div>
</div>
<div class="row">
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Ordine</label>
<input type="number" class="form-control" id="editSortOrder" name="sort_order" min="0">
</div>
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Stato</label>
<select class="form-select" id="editIsActive" name="is_active">
<option value="1">Attivo</option>
<option value="0">Inattivo</option>
</select>
</div>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="editIsMandatory" value="1">
<label class="form-check-label fw-semibold" for="editIsMandatory">
Obbligatorio per tutti i dipendenti
</label>
<div class="small text-muted">
Se attivo, i dipendenti senza registrazione di questo corso compaiono come "Non presente" nello storico.
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">⛓️ Corsi assorbiti da questo</label>
<select class="form-select" id="editCovered" multiple size="6">
<?php foreach ($topics as $t): ?>
<option value="<?= (int)$t['id'] ?>"><?= htmlspecialchars($t['name']) ?></option>
<?php endforeach; ?>
</select>
<div class="cov-help">
Chi completa questo corso risulta automaticamente in regola anche per quelli selezionati.
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-add">💾 Salva Modifiche</button>
</div>
</form>
</div>
</div>
</div>
</div>
<?php include('jsinclude.php'); ?>
<script>
$(document).ready(function() {
$('#tabellaTopics').DataTable({
columnDefs: [{
targets: [8, 9],
orderable: false
}],
order: [
[5, 'asc'],
[1, 'asc']
],
pageLength: 25,
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json',
emptyTable: 'Nessun corso presente'
}
});
function ajaxPost(url, payload, successTitle, errorFallback) {
return fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: payload.toString()
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: "success",
title: successTitle,
confirmButtonColor: "#3085d6"
})
.then(() => location.reload());
} else {
Swal.fire({
icon: "error",
title: "Errore",
text: data.message || errorFallback
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Errore",
text: "Errore di comunicazione."
});
console.error(err);
});
}
$("#addTopicForm").on("submit", function(e) {
e.preventDefault();
const p = new URLSearchParams();
p.append('name', $("#addName").val().trim());
p.append('description', $("#addDescription").val().trim());
p.append('default_frequency_months', $("#addFreq").val());
p.append('default_reminder_days', $("#addRem").val());
p.append('sort_order', $("#addSortOrder").val());
p.append('is_active', $("#addIsActive").val());
p.append('is_mandatory', $("#addIsMandatory").is(':checked') ? '1' : '0');
($("#addCovered").val() || []).forEach(function(v) {
p.append('covered_ids[]', v);
});
ajaxPost("ajax/training_topics/save.php", p, "Salvato!", "Impossibile salvare il corso.");
});
$(document).on("click", ".edit-topic", function() {
const b = $(this);
const rawFreq = b.data("freq");
const freqStr = (rawFreq === '' || rawFreq === null || rawFreq === undefined) ? '' : String(rawFreq);
if (freqStr !== '' && $("#editFreq option[value='" + freqStr + "']").length === 0) {
$("#editFreq").append('<option value="' + freqStr + '">' + freqStr + ' mesi</option>');
}
$("#editTopicId").val(b.data("id"));
$("#editName").val(b.data("name"));
$("#editDescription").val(b.data("description"));
$("#editFreq").val(freqStr);
$("#editRem").val(b.data("rem"));
$("#editSortOrder").val(b.data("sort_order"));
$("#editIsActive").val(String(b.data("is_active")));
$("#editIsMandatory").prop('checked', String(b.data("is_mandatory")) === '1');
// Coperture: nascondi il corso stesso e preseleziona le esistenti
var selfId = String(b.data("id"));
var covered = b.data("covered") || [];
if (typeof covered === 'string') {
try {
covered = JSON.parse(covered);
} catch (e) {
covered = [];
}
}
covered = covered.map(String);
$("#editCovered option").each(function() {
$(this).prop('hidden', this.value === selfId)
.prop('disabled', this.value === selfId);
});
$("#editCovered").val(covered);
$("#editTopicModal").modal("show");
});
$("#editTopicForm").on("submit", function(e) {
e.preventDefault();
const p = new URLSearchParams();
p.append('id', $("#editTopicId").val());
p.append('name', $("#editName").val().trim());
p.append('description', $("#editDescription").val().trim());
p.append('default_frequency_months', $("#editFreq").val());
p.append('default_reminder_days', $("#editRem").val());
p.append('sort_order', $("#editSortOrder").val());
p.append('is_active', $("#editIsActive").val());
p.append('is_mandatory', $("#editIsMandatory").is(':checked') ? '1' : '0');
($("#editCovered").val() || []).forEach(function(v) {
p.append('covered_ids[]', v);
});
ajaxPost("ajax/training_topics/save.php", p, "Aggiornato!", "Impossibile aggiornare il corso.");
});
$(document).on("click", ".delete-topic", function() {
const id = $(this).data("id");
const name = $(this).data("name");
const cnt = parseInt($(this).data("count")) || 0;
if (cnt > 0) {
Swal.fire({
icon: "warning",
title: "Impossibile cancellare",
text: "Il corso \"" + name + "\" ha " + cnt + " registrazione/i di formazione. Cancella prima le registrazioni."
});
return;
}
Swal.fire({
title: "Confermi la cancellazione?",
text: name ? ("Corso: " + name) : "Il corso verrà cancellato.",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#d33",
cancelButtonColor: "#6c757d",
confirmButtonText: "Sì, cancella",
cancelButtonText: "Annulla"
}).then((result) => {
if (!result.isConfirmed) return;
const p = new URLSearchParams();
p.append('id', id);
ajaxPost("ajax/training_topics/delete.php", p, "Cancellato!", "Impossibile cancellare il corso.");
});
});
});
</script>
</body>
</html>