future lessons

This commit is contained in:
Claudio 2025-12-25 21:12:29 +01:00
parent b592be5831
commit 6124e7e8fa
4 changed files with 1104 additions and 62 deletions

View File

@ -22,6 +22,19 @@ if (!$school) {
}
$school_id = $school['id'];
$school_name = $school['name'];
// === LISTA UTENTI DELLA SCUOLA (per dropdown "Aggiungi partecipante") ===
// NOTA: uso user_schools (come nel tuo progetto). Se la tabella si chiama diversamente, cambia qui.
$stmtUsers = $pdo->prepare("
SELECT au.id, au.first_name, au.last_name, au.email
FROM user_schools us
JOIN auth_users au ON au.id = us.user_id
WHERE us.school_id = ?
AND us.status = 'active'
ORDER BY au.first_name, au.last_name
");
$stmtUsers->execute([$school_id]);
$schoolUsers = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);
// === GESTIONE AZIONI ===
$feedback = '';
@ -34,7 +47,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Cancellazione lezione
if ($action === 'delete_session') {
$session_id = (int)($_POST['session_id'] ?? 0);
$send_email = !empty($_POST['send_email']);
$send_email = isset($_POST['send_email']) && $_POST['send_email'] === '1';
error_log("DELETE_SESSION: session_id={$session_id} send_email_POST=" . var_export($_POST['send_email'] ?? null, true));
error_log("DELETE_SESSION: send_email_BOOL=" . var_export($send_email, true));
$stmt = $pdo->prepare("
SELECT cs.id, cs.session_date, cs.start_time, cs.end_time,
@ -54,7 +70,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
SELECT au.email, au.first_name
FROM session_bookings sb
JOIN auth_users au ON sb.user_id = au.id
WHERE sb.session_id = ? AND sb.status IN ('booked','attended','rescheduled')
WHERE sb.session_id = ?
");
$stmt2->execute([$session_id]);
$recipients = $stmt2->fetchAll(PDO::FETCH_ASSOC);
@ -114,7 +130,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
SELECT au.email, au.first_name
FROM session_bookings sb
JOIN auth_users au ON sb.user_id = au.id
WHERE sb.session_id = ? AND sb.status IN ('booked','attended','rescheduled')
WHERE sb.session_id = ?
");
$stmt->execute([$session_id]);
$recipients = $stmt->fetchAll(PDO::FETCH_ASSOC);
@ -160,11 +176,93 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
</div>";
}
// Aggiungi partecipante alla lezione
elseif ($action === 'add_booking') {
$session_id = (int)($_POST['session_id'] ?? 0);
$user_id = (int)($_POST['user_id'] ?? 0);
if ($session_id <= 0 || $user_id <= 0) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Dati non validi.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} else {
// 1) Verifica sessione appartiene alla scuola + capienza
$stmt = $pdo->prepare("
SELECT cs.id, ct.max_capacity,
(SELECT COUNT(*) FROM session_bookings sb
WHERE sb.session_id = cs.id AND sb.status IN ('booked','attended','rescheduled')
) AS booked_count
FROM class_sessions cs
JOIN class_types ct ON cs.class_type_id = ct.id
JOIN classes c ON ct.class_id = c.id
WHERE cs.id = ? AND c.school_id = ?
LIMIT 1
");
$stmt->execute([$session_id, $school_id]);
$info = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$info) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Lezione non trovata o non autorizzata.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} else {
// 2) Verifica utente appartiene alla scuola
$stmt = $pdo->prepare("
SELECT 1
FROM user_schools
WHERE user_id = ? AND school_id = ? AND status = 'active'
LIMIT 1
");
$stmt->execute([$user_id, $school_id]);
$isMember = (bool)$stmt->fetchColumn();
if (!$isMember) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Utente non associato a questa scuola.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} else {
// 3) Verifica già prenotato (qualsiasi status)
$stmt = $pdo->prepare("SELECT 1 FROM session_bookings WHERE session_id = ? AND user_id = ? LIMIT 1");
$stmt->execute([$session_id, $user_id]);
$already = (bool)$stmt->fetchColumn();
if ($already) {
$feedback = '<div class="alert alert-warning alert-dismissible fade show">Questo utente è già presente nella lezione.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} else {
// 4) Verifica capienza (se max_capacity valorizzato)
$max = (int)($info['max_capacity'] ?? 0);
$cnt = (int)($info['booked_count'] ?? 0);
if ($max > 0 && $cnt >= $max) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Lezione piena: capienza massima raggiunta.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} else {
// 5) Inserimento (con fallback se non hai created_at/updated_at)
try {
$stmtIns = $pdo->prepare("
INSERT INTO session_bookings (session_id, user_id, status, created_at, updated_at)
VALUES (?, ?, 'booked', NOW(), NOW())
");
$stmtIns->execute([$session_id, $user_id]);
} catch (PDOException $e) {
// fallback SOLO se l'errore è "Unknown column"
if (stripos($e->getMessage(), 'Unknown column') !== false) {
$stmtIns = $pdo->prepare("
INSERT INTO session_bookings (session_id, user_id, status)
VALUES (?, ?, 'booked')
");
$stmtIns->execute([$session_id, $user_id]);
} else {
throw $e;
}
}
$feedback = '<div class="alert alert-success alert-dismissible fade show">Partecipante aggiunto alla lezione!<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
}
}
}
}
}
}
// Marca come persa
elseif ($action === 'mark_lost') {
$booking_id = (int)($_POST['booking_id'] ?? 0);
$stmt = $pdo->prepare("UPDATE session_bookings SET status = 'lost' WHERE id = ? AND session_id IN (SELECT cs.id FROM class_sessions cs JOIN class_types ct ON cs.class_type_id = ct.id JOIN classes c ON ct.class_id = c.id WHERE c.school_id = ?)");
$stmt = $pdo->prepare("UPDATE session_bookings SET status = 'missed' WHERE id = ? AND session_id IN (SELECT cs.id FROM class_sessions cs JOIN class_types ct ON cs.class_type_id = ct.id JOIN classes c ON ct.class_id = c.id WHERE c.school_id = ?)");
$stmt->execute([$booking_id, $school_id]);
$feedback = '<div class="alert alert-warning alert-dismissible fade show">Presenza segnata come persa.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
}
@ -192,9 +290,9 @@ $stmt = $pdo->prepare("
t.first_name,
t.last_name,
(SELECT COUNT(*) FROM session_bookings sb WHERE sb.session_id = cs.id AND sb.status IN ('booked','attended','rescheduled')) AS booked_count,
(SELECT GROUP_CONCAT(CONCAT(sb.id,'|||',au.first_name,' ',au.last_name,'|||',au.email,'|||',COALESCE(au.phone,''),'|||',sb.status) SEPARATOR ';;;')
FROM session_bookings sb JOIN auth_users au ON sb.user_id = au.id
WHERE sb.session_id = cs.id AND sb.status IN ('booked','attended','rescheduled','lost')) AS booked_students_details
(SELECT GROUP_CONCAT(CONCAT(sb.id,'|||',au.id,'|||',au.first_name,' ',au.last_name,'|||',au.email,'|||',COALESCE(au.phone,''),'|||',sb.status) SEPARATOR ';;;')
FROM session_bookings sb JOIN auth_users au ON sb.user_id = au.id
WHERE sb.session_id = cs.id AND sb.status IN ('booked','attended','rescheduled','missed')) AS booked_students_details
FROM class_sessions cs
JOIN class_types ct ON cs.class_type_id = ct.id
JOIN classes c ON ct.class_id = c.id
@ -224,6 +322,9 @@ foreach ($sessions as $s) {
<title>Lezioni Future - <?php echo htmlspecialchars($school_name); ?></title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<link rel="stylesheet" href="assets/plugins/select2/css/select2.min.css">
</head>
<body>
@ -291,11 +392,20 @@ foreach ($sessions as $s) {
<td><?php echo htmlspecialchars($s['room_name'] ?? '—'); ?></td>
<td><?php echo $s['first_name'] ? htmlspecialchars($s['first_name'] . ' ' . $s['last_name']) : '<em>Non assegnato</em>'; ?></td>
<td>
<button type="button" class="btn btn-sm btn-success position-relative"
<?php if ($s['booked_count'] > 0): ?>data-bs-toggle="modal" data-bs-target="#studentsModal-<?php echo $s['session_id']; ?>" <?php endif; ?>>
<?php echo $s['booked_count']; ?>
<button type="button"
class="btn btn-sm <?php echo ((int)$s['booked_count'] > 0) ? 'btn-success' : 'btn-outline-secondary'; ?> position-relative"
data-bs-toggle="modal"
data-bs-target="#studentsModal-<?php echo (int)$s['session_id']; ?>">
<?php
$bc = (int)$s['booked_count'];
$max = (int)($s['max_capacity'] ?? 0);
echo ($max > 0) ? "{$bc}/{$max}" : "{$bc}/∞";
?>
</button>
</td>
<td>
<button type="button" class="btn btn-sm btn-danger"
data-bs-toggle="modal" data-bs-target="#deleteModal-<?php echo $s['session_id']; ?>">
@ -324,11 +434,12 @@ foreach ($sessions as $s) {
if (empty(trim($entry))) continue;
$parts = explode('|||', $entry);
$students_list[] = [
'booking_id' => $parts[0] ?? 0,
'name' => $parts[1] ?? '',
'email' => $parts[2] ?? '',
'phone' => $parts[3] ?? '—',
'status' => $parts[4] ?? 'booked'
'booking_id' => (int)($parts[0] ?? 0),
'user_id' => (int)($parts[1] ?? 0),
'name' => $parts[2] ?? '',
'email' => $parts[3] ?? '',
'phone' => $parts[4] ?? '—',
'status' => $parts[5] ?? 'booked'
];
}
}
@ -343,6 +454,65 @@ foreach ($sessions as $s) {
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<?php
// Utenti già presenti (per escluderli dal dropdown)
$bookedUserIds = [];
foreach ($students_list as $st) {
if (!empty($st['user_id'])) $bookedUserIds[] = (int)$st['user_id'];
}
// Utenti disponibili = utenti scuola - già presenti
$availableUsers = array_values(array_filter($schoolUsers, function ($u) use ($bookedUserIds) {
return !in_array((int)$u['id'], $bookedUserIds, true);
}));
$isFull = false;
$maxCap = (int)($session['max_capacity'] ?? 0);
$bookedCnt = (int)($session['booked_count'] ?? 0);
if ($maxCap > 0 && $bookedCnt >= $maxCap) $isFull = true;
?>
<div class="mb-3 p-3 border rounded bg-light">
<div class="d-flex align-items-center justify-content-between mb-2">
<strong>Aggiungi partecipante</strong>
<small class="text-muted">
Capienza: <?php echo $maxCap > 0 ? ($bookedCnt . '/' . $maxCap) : ($bookedCnt . '/∞'); ?>
</small>
</div>
<?php if ($isFull): ?>
<div class="text-danger small">Lezione piena: non puoi aggiungere altri partecipanti.</div>
<?php elseif (empty($availableUsers)): ?>
<div class="text-muted small">Nessun utente disponibile (tutti già presenti o nessun utente associato alla scuola).</div>
<?php else: ?>
<form method="POST" class="row g-2 align-items-end">
<input type="hidden" name="action" value="add_booking">
<input type="hidden" name="session_id" value="<?php echo (int)$session['session_id']; ?>">
<div class="col-12 col-md-8">
<label class="form-label mb-1">Seleziona utente</label>
<select name="user_id" class="form-select select2-user" required data-placeholder="Cerca per nome o email">
<option value=""></option>
<?php foreach ($availableUsers as $u): ?>
<option value="<?php echo (int)$u['id']; ?>">
<?php
$full = trim(($u['first_name'] ?? '') . ' ' . ($u['last_name'] ?? ''));
echo htmlspecialchars($full . ' — ' . ($u['email'] ?? ''));
?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-12 col-md-4">
<button type="submit" class="btn btn-primary w-100">
<i class="bx bx-plus"></i> Aggiungi
</button>
</div>
</form>
<?php endif; ?>
</div>
<?php if (empty($students_list)): ?>
<p class="text-center text-muted">Nessuno prenotato.</p>
<?php else: ?>
@ -363,12 +533,12 @@ foreach ($sessions as $s) {
<td><?php echo htmlspecialchars($stud['email']); ?></td>
<td><?php echo htmlspecialchars($stud['phone']); ?></td>
<td>
<span class="badge <?php echo $stud['status'] === 'lost' ? 'bg-warning' : 'bg-success'; ?>">
<?php echo $stud['status'] === 'lost' ? 'Persa' : 'Prenotato'; ?>
<span class="badge <?php echo $stud['status'] === 'missed' ? 'bg-warning' : 'bg-success'; ?>">
<?php echo $stud['status'] === 'missed' ? 'Persa' : 'Prenotato'; ?>
</span>
</td>
<td>
<?php if ($stud['status'] !== 'lost'): ?>
<?php if ($stud['status'] !== 'missed'): ?>
<button type="button" class="btn btn-sm btn-warning me-1" data-bs-toggle="modal" data-bs-target="#lostModal-<?php echo $stud['booking_id']; ?>">P</button>
<?php endif; ?>
<button type="button" class="btn btn-sm btn-danger" data-bs-toggle="modal" data-bs-target="#cancelModal-<?php echo $stud['booking_id']; ?>">C</button>
@ -432,54 +602,54 @@ foreach ($sessions as $s) {
</div>
</div>
<?php endforeach; ?>
<!-- Modale Cancellazione Lezione con checkbox email -->
<!-- Modale Cancellazione Lezione con checkbox email (FIX DEFINITIVO) -->
<div class="modal fade" id="deleteModal-<?php echo $session['session_id']; ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title">Cancella Lezione</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Confermi la cancellazione della lezione:</p>
<ul>
<li><strong>Classe:</strong> <?php echo htmlspecialchars($session['class_name']); ?></li>
<li><strong>Data:</strong> <?php echo date('d/m/Y (l)', strtotime($session['session_date'])); ?></li>
<li><strong>Orario:</strong> <?php echo substr($session['start_time'], 0, 5); ?> - <?php echo substr($session['end_time'], 0, 5); ?></li>
<li><strong>Prenotati:</strong> <?php echo $session['booked_count']; ?></li>
</ul>
<?php if ($session['booked_count'] > 0): ?>
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox" id="sendEmail-<?php echo $session['session_id']; ?>">
<label class="form-check-label text-primary fw-bold" for="sendEmail-<?php echo $session['session_id']; ?>">
Invia email di avviso ai <?php echo $session['booked_count']; ?> partecipanti?
</label>
</div>
<?php endif; ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
<form method="POST" id="deleteForm-<?php echo $session['session_id']; ?>">
<form method="POST">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title">Cancella Lezione</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Confermi la cancellazione della lezione:</p>
<ul>
<li><strong>Classe:</strong> <?php echo htmlspecialchars($session['class_name']); ?></li>
<li><strong>Data:</strong> <?php echo date('d/m/Y (l)', strtotime($session['session_date'])); ?></li>
<li><strong>Orario:</strong> <?php echo substr($session['start_time'], 0, 5); ?> - <?php echo substr($session['end_time'], 0, 5); ?></li>
<li><strong>Prenotati:</strong> <?php echo (int)$session['booked_count']; ?></li>
</ul>
<?php if ((int)$session['booked_count'] > 0): ?>
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox"
name="send_email" value="1"
id="sendEmail-<?php echo $session['session_id']; ?>">
<label class="form-check-label text-primary fw-bold"
for="sendEmail-<?php echo $session['session_id']; ?>">
Invia email di avviso ai <?php echo (int)$session['booked_count']; ?> partecipanti?
</label>
</div>
<?php endif; ?>
<input type="hidden" name="action" value="delete_session">
<input type="hidden" name="session_id" value="<?php echo $session['session_id']; ?>">
<input type="hidden" name="send_email" value="0" id="hiddenEmail-<?php echo $session['session_id']; ?>">
<input type="hidden" name="session_id" value="<?php echo (int)$session['session_id']; ?>">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
<button type="submit" class="btn btn-danger">Cancella Lezione</button>
</form>
</div>
</div>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const check = document.getElementById('sendEmail-<?php echo $session['session_id']; ?>');
const hidden = document.getElementById('hiddenEmail-<?php echo $session['session_id']; ?>');
if (check && hidden) {
check.addEventListener('change', () => hidden.value = check.checked ? '1' : '0');
}
});
</script>
<?php endforeach; ?>
<!-- Modale Invio Email Cancellazione -->
@ -538,6 +708,28 @@ Grazie per la comprensione,
</div>
<?php include('jsinclude.php'); ?>
<script src="assets/plugins/select2/js/select2.min.js"></script>
<script>
document.addEventListener('shown.bs.modal', function(e) {
const modal = e.target;
if (!window.jQuery || !jQuery.fn || !jQuery.fn.select2) return;
modal.querySelectorAll('.select2-user').forEach(function(sel) {
const $sel = jQuery(sel);
// evita doppia init
if ($sel.hasClass('select2-hidden-accessible')) return;
$sel.select2({
dropdownParent: jQuery(modal),
width: '100%',
placeholder: sel.dataset.placeholder || 'Seleziona...'
});
});
});
</script>
</body>
</html>

View File

@ -11,7 +11,212 @@ $stmt = $pdo->prepare("SELECT id, name FROM schools WHERE owner_id = ?");
$stmt->execute([$iduserlogin]);
$school = $stmt->fetch();
if (!$school) die("Scuola non trovata.");
$school_id = $school['id'];
$school_id = (int)$school['id'];
// === UTENTI DELLA SCUOLA (dropdown cercabile) ===
$stmtUsers = $pdo->prepare("
SELECT au.id, au.first_name, au.last_name, au.email
FROM user_schools us
JOIN auth_users au ON au.id = us.user_id
WHERE us.school_id = ?
AND us.status = 'active'
ORDER BY au.first_name, au.last_name
");
$stmtUsers->execute([$school_id]);
$schoolUsers = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);
// === PRODOTTI ATTIVI ===
$stmtProd = $pdo->prepare("
SELECT id, name, type
FROM products
WHERE school_id = ? AND status = 'active'
ORDER BY name
");
$stmtProd->execute([$school_id]);
$products = $stmtProd->fetchAll(PDO::FETCH_ASSOC);
// === VARIAZIONI ATTIVE (per filtro lato JS) ===
$variations = [];
if (!empty($products)) {
$prodIds = array_column($products, 'id');
$in = implode(',', array_fill(0, count($prodIds), '?'));
$stmtVar = $pdo->prepare("
SELECT id, product_id, name, price, duration_days, max_entries, max_recoveries
FROM product_variations
WHERE product_id IN ($in)
AND status = 'active'
ORDER BY product_id, name
");
$stmtVar->execute($prodIds);
$variations = $stmtVar->fetchAll(PDO::FETCH_ASSOC);
}
// === CLASSI ATTIVE ===
$stmtClasses = $pdo->prepare("
SELECT id, name
FROM classes
WHERE school_id = ? AND status = 'active'
ORDER BY name
");
$stmtClasses->execute([$school_id]);
$classes = $stmtClasses->fetchAll(PDO::FETCH_ASSOC);
// === CLASS TYPES (filtrati lato JS per class_id) ===
$stmtCT = $pdo->prepare("
SELECT ct.id, ct.class_id, ct.level, ct.day_of_week
FROM class_types ct
JOIN classes c ON ct.class_id = c.id
WHERE c.school_id = ?
ORDER BY c.name, ct.day_of_week, ct.level
");
$stmtCT->execute([$school_id]);
$classTypes = $stmtCT->fetchAll(PDO::FETCH_ASSOC);
$feedback = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'add_order_manual') {
$user_id = (int)($_POST['user_id'] ?? 0);
$product_id = (int)($_POST['product_id'] ?? 0);
$variation_id = (int)($_POST['variation_id'] ?? 0);
$payment_method = trim($_POST['payment_method'] ?? '');
$status = trim($_POST['status'] ?? 'completed');
$price = isset($_POST['price']) ? (float)str_replace(',', '.', $_POST['price']) : 0.0;
$total_entries = ($_POST['total_entries'] ?? '') !== '' ? (int)$_POST['total_entries'] : null;
$available_entries = ($_POST['available_entries'] ?? '') !== '' ? (int)$_POST['available_entries'] : null;
$activation_date = $_POST['activation_date'] ?? date('Y-m-d');
$expiration_date = $_POST['expiration_date'] ?? null;
$expiration_date = ($expiration_date === '') ? null : $expiration_date;
$class_id = ($_POST['class_id'] ?? '') !== '' ? (int)$_POST['class_id'] : null;
$class_type_id = ($_POST['class_type_id'] ?? '') !== '' ? (int)$_POST['class_type_id'] : null;
// Validazioni base
if ($user_id <= 0 || $product_id <= 0 || $payment_method === '') {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Compila utente, prodotto e metodo di pagamento.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} else {
// 1) utente appartiene alla scuola
$stmt = $pdo->prepare("SELECT 1 FROM user_schools WHERE school_id = ? AND user_id = ? AND status='active' LIMIT 1");
$stmt->execute([$school_id, $user_id]);
if (!$stmt->fetchColumn()) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Utente non associato alla scuola.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} else {
// 2) prodotto appartiene alla scuola
$stmt = $pdo->prepare("SELECT id FROM products WHERE id=? AND school_id=? AND status='active' LIMIT 1");
$stmt->execute([$product_id, $school_id]);
if (!$stmt->fetchColumn()) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Prodotto non valido.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} else {
// 3) se variation_id valorizzato, deve appartenere al prodotto
$varMeta = null;
if ($variation_id > 0) {
$stmt = $pdo->prepare("SELECT id, price, duration_days, max_entries, max_recoveries FROM product_variations WHERE id=? AND product_id=? AND status='active' LIMIT 1");
$stmt->execute([$variation_id, $product_id]);
$varMeta = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$varMeta) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Variazione non valida.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
}
}
if ($feedback === '') {
// 4) class / class_type se presenti devono essere coerenti e della scuola
if ($class_id) {
$stmt = $pdo->prepare("SELECT 1 FROM classes WHERE id=? AND school_id=? LIMIT 1");
$stmt->execute([$class_id, $school_id]);
if (!$stmt->fetchColumn()) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Classe non valida.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
}
}
if ($class_type_id) {
$stmt = $pdo->prepare("
SELECT 1
FROM class_types ct
JOIN classes c ON ct.class_id = c.id
WHERE ct.id=? AND c.school_id=?
LIMIT 1
");
$stmt->execute([$class_type_id, $school_id]);
if (!$stmt->fetchColumn()) {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Class type non valido.<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
}
}
}
if ($feedback === '') {
// Autocomplete intelligente da variazione se non inserito
if ($varMeta) {
if ($price <= 0) $price = (float)$varMeta['price'];
if ($total_entries === null && $varMeta['max_entries'] !== null) $total_entries = (int)$varMeta['max_entries'];
if ($available_entries === null && $total_entries !== null) $available_entries = $total_entries;
if (!$expiration_date && !empty($varMeta['duration_days'])) {
$d = new DateTime($activation_date);
$d->modify('+' . (int)$varMeta['duration_days'] . ' days');
$expiration_date = $d->format('Y-m-d');
}
$available_recoveries = ($varMeta['max_recoveries'] !== null) ? (int)$varMeta['max_recoveries'] : null;
} else {
$available_recoveries = null;
}
// order_number progressivo per scuola
try {
$pdo->beginTransaction();
$stmt = $pdo->prepare("SELECT COALESCE(MAX(order_number),0) + 1 FROM orders WHERE school_id=? FOR UPDATE");
$stmt->execute([$school_id]);
$nextOrderNumber = (int)$stmt->fetchColumn();
$stmtIns = $pdo->prepare("
INSERT INTO orders
(order_number, school_id, user_id, product_id, variation_id, class_id, class_type_id,
created_at, payment_method, price, status,
total_entries, available_entries, available_recoveries,
expiration_date, activation_date)
VALUES
(?, ?, ?, ?, ?, ?, ?,
NOW(), ?, ?, ?,
?, ?, ?,
?, ?)
");
$stmtIns->execute([
$nextOrderNumber,
$school_id,
$user_id,
$product_id,
($variation_id > 0 ? $variation_id : null),
$class_id,
$class_type_id,
$payment_method,
$price,
$status,
$total_entries,
$available_entries,
$available_recoveries,
$expiration_date,
$activation_date
]);
$pdo->commit();
$feedback = '<div class="alert alert-success alert-dismissible fade show">Ordine manuale inserito con successo!<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
} catch (Exception $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
$feedback = '<div class="alert alert-danger alert-dismissible fade show">Errore inserimento ordine: ' . htmlspecialchars($e->getMessage()) . '<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>';
}
}
}
}
}
}
}
// Recupera tutti gli ordini con tutti i dati necessari
$stmt = $pdo->prepare("
@ -55,6 +260,7 @@ $orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
<title>Ordini - <?php echo htmlspecialchars($school['name']); ?></title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<link rel="stylesheet" href="assets/plugins/select2/css/select2.min.css">
<!-- DataTables CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.7/css/dataTables.bootstrap5.min.css">
@ -77,13 +283,15 @@ $orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
Gestione Ordini
<span class="badge bg-light text-dark ms-2"><?php echo count($orders); ?></span>
</h4>
<div>
<button class="btn btn-light btn-sm" onclick="table.buttons().export()">
Esporta
<div class="d-flex gap-2">
<button type="button" class="btn btn-light btn-sm" data-bs-toggle="modal" data-bs-target="#manualOrderModal">
+ Ordine manuale
</button>
</div>
</div>
</div>
<?php echo $feedback; ?>
<div class="card radius-15 shadow">
<div class="card-body p-0">
@ -170,11 +378,154 @@ $orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
</div>
</div>
</div>
<div class="modal fade" id="manualOrderModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form method="POST">
<input type="hidden" name="action" value="add_order_manual">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title">Inserisci ordine manuale</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Utente</label>
<select name="user_id" class="form-select select2-user" required data-placeholder="Cerca per nome o email">
<option value=""></option>
<?php foreach ($schoolUsers as $u): ?>
<option value="<?php echo (int)$u['id']; ?>">
<?php
$full = trim(($u['first_name'] ?? '') . ' ' . ($u['last_name'] ?? ''));
echo htmlspecialchars($full . ' — ' . ($u['email'] ?? ''));
?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Metodo pagamento</label>
<select name="payment_method" class="form-select" required>
<option value="">Seleziona...</option>
<option value="cash">Cash</option>
<option value="pos">POS</option>
<option value="bank_transfer">Bonifico</option>
<option value="manual">Manuale</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Prodotto</label>
<select name="product_id" class="form-select select2-product" required data-placeholder="Seleziona prodotto">
<option value=""></option>
<?php foreach ($products as $p): ?>
<option value="<?php echo (int)$p['id']; ?>">
<?php echo htmlspecialchars($p['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Variazione</label>
<select name="variation_id" class="form-select select2-variation" data-placeholder="(opzionale)">
<option value=""></option>
<?php foreach ($variations as $v): ?>
<option
value="<?php echo (int)$v['id']; ?>"
data-product-id="<?php echo (int)$v['product_id']; ?>"
data-price="<?php echo htmlspecialchars($v['price']); ?>"
data-duration-days="<?php echo (int)($v['duration_days'] ?? 0); ?>"
data-max-entries="<?php echo ($v['max_entries'] !== null ? (int)$v['max_entries'] : ''); ?>">
<?php echo htmlspecialchars($v['name']); ?>
</option>
<?php endforeach; ?>
</select>
<small class="text-muted">Le variazioni verranno filtrate in base al prodotto.</small>
</div>
<div class="col-md-4">
<label class="form-label">Prezzo ()</label>
<input type="text" name="price" class="form-control" placeholder="es. 49.90">
</div>
<div class="col-md-4">
<label class="form-label">Stato</label>
<select name="status" class="form-select">
<option value="completed" selected>completed</option>
<option value="pending">pending</option>
<option value="cancelled">cancelled</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Attivazione</label>
<input type="date" name="activation_date" class="form-control" value="<?php echo date('Y-m-d'); ?>">
</div>
<div class="col-md-4">
<label class="form-label">Ingressi totali</label>
<input type="number" name="total_entries" class="form-control" min="0" placeholder="(vuoto = illimitati)">
</div>
<div class="col-md-4">
<label class="form-label">Ingressi disponibili</label>
<input type="number" name="available_entries" class="form-control" min="0" placeholder="(auto)">
</div>
<div class="col-md-4">
<label class="form-label">Scadenza</label>
<input type="date" name="expiration_date" class="form-control" placeholder="(auto se duration)">
</div>
<?php if (isset($classes, $classTypes)): ?>
<hr class="my-2">
<div class="col-md-6">
<label class="form-label">Classe (opzionale)</label>
<select name="class_id" class="form-select select2-class" data-placeholder="Tutte le classi">
<option value=""></option>
<?php foreach ($classes as $c): ?>
<option value="<?php echo (int)$c['id']; ?>"><?php echo htmlspecialchars($c['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Class Type (opzionale)</label>
<select name="class_type_id" class="form-select select2-classtype" data-placeholder="Qualsiasi">
<option value=""></option>
<?php foreach ($classTypes as $ct): ?>
<option value="<?php echo (int)$ct['id']; ?>" data-class-id="<?php echo (int)$ct['class_id']; ?>">
<?php echo htmlspecialchars(($ct['day_of_week'] ?? '') . ' - ' . ($ct['level'] ?? '')); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
<button type="submit" class="btn btn-primary">Salva ordine</button>
</div>
</form>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script src="assets/plugins/select2/js/select2.min.js"></script>
<!-- DataTables + Plugin -->
<script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.min.js"></script>
@ -222,6 +573,101 @@ $orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
});
});
</script>
<script>
$(function() {
// Select2 dentro modale
$('#manualOrderModal').on('shown.bs.modal', function() {
const $m = $('#manualOrderModal');
function initSel(selector) {
const $el = $m.find(selector);
if (!$el.length) return;
if ($el.hasClass('select2-hidden-accessible')) return;
$el.select2({
dropdownParent: $m,
width: '100%',
allowClear: true,
placeholder: $el.data('placeholder') || 'Seleziona...'
});
}
initSel('.select2-user');
initSel('.select2-product');
initSel('.select2-variation');
initSel('.select2-class');
initSel('.select2-classtype');
});
// Filtra variazioni in base al prodotto
$(document).on('change', 'select[name="product_id"]', function() {
const pid = $(this).val();
const $var = $('#manualOrderModal').find('select[name="variation_id"]');
$var.val('').trigger('change');
$var.find('option').each(function() {
const optPid = $(this).data('product-id');
if (!optPid) return; // option vuota
$(this).toggle(String(optPid) === String(pid));
});
});
// Quando selezioni una variazione: precompila prezzo + ingressi + scadenza
$(document).on('change', '#manualOrderModal select[name="variation_id"]', function() {
const $m = $('#manualOrderModal');
const $opt = $(this).find('option:selected');
const price = $opt.data('price');
const maxEntries = $opt.data('max-entries');
const durationDays = parseInt($opt.data('duration-days') || 0, 10);
// Prezzo
if (price !== undefined && price !== '') {
$m.find('input[name="price"]').val(price);
}
// Ingressi
if (maxEntries !== undefined && maxEntries !== '') {
$m.find('input[name="total_entries"]').val(maxEntries);
$m.find('input[name="available_entries"]').val(maxEntries);
}
// Scadenza (activation_date + durationDays)
const act = $m.find('input[name="activation_date"]').val();
if (durationDays > 0 && act) {
const d = new Date(act);
d.setDate(d.getDate() + durationDays);
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, '0');
const dd = String(d.getDate()).padStart(2, '0');
$m.find('input[name="expiration_date"]').val(`${yyyy}-${mm}-${dd}`);
}
});
// ricalcola scadenza se cambia activation_date (solo se variation con duration)
$(document).on('change', 'input[name="activation_date"]', function() {
$('select[name="variation_id"]').trigger('change');
});
// Filtra class_types in base alla classe
$(document).on('change', 'select[name="class_id"]', function() {
const cid = $(this).val();
const $ct = $('select[name="class_type_id"]');
$ct.val('').trigger('change');
$ct.find('option').each(function() {
const optCid = $(this).data('class-id');
if (!optCid) return;
$(this).toggle(String(optCid) === String(cid));
});
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,404 @@
<?php
// propagation_overview.php - Propagation Blocks Overview (Grouped, not single sessions)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
if (!isset($iduserlogin)) {
die("Errore: ID utente non definito.");
}
/*
|--------------------------------------------------------------------------
| 1) Load school owned by current user
|--------------------------------------------------------------------------
*/
$stmt = $pdo->prepare("SELECT id, name, logo FROM schools WHERE owner_id = ? LIMIT 1");
$stmt->execute([(int)$iduserlogin]);
$school = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$school) {
die("Errore: Nessuna scuola trovata per questo account.");
}
$school_id = (int)$school['id'];
$school_name = $school['name'] ?? 'School';
/*
|--------------------------------------------------------------------------
| 2) Helpers
|--------------------------------------------------------------------------
*/
function itDayLabel(string $dow): string
{
$map = [
'monday' => 'Lunedì',
'tuesday' => 'Martedì',
'wednesday' => 'Mercoledì',
'thursday' => 'Giovedì',
'friday' => 'Venerdì',
'saturday' => 'Sabato',
'sunday' => 'Domenica'
];
return $map[$dow] ?? ucfirst($dow);
}
function safeTime($t): string
{
// expects "HH:MM:SS" or "HH:MM"
if (!$t) return '—';
return substr((string)$t, 0, 5);
}
/*
|--------------------------------------------------------------------------
| 3) Handle delete block propagation (bookings + sessions for that block)
|--------------------------------------------------------------------------
| Block key = propagation_id + class_type_id + start_time + end_time
|--------------------------------------------------------------------------
*/
$feedback = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'delete_propagation_block') {
$propagation_id = trim($_POST['propagation_id'] ?? '');
$class_type_id = (int)($_POST['class_type_id'] ?? 0);
$start_time = trim($_POST['start_time'] ?? '');
$end_time = trim($_POST['end_time'] ?? '');
if ($propagation_id === '' || $class_type_id <= 0 || $start_time === '' || $end_time === '') {
$feedback = '<div class="alert alert-danger alert-dismissible fade show">
Parametri non validi per la cancellazione della propagazione.
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>';
} else {
try {
$pdo->beginTransaction();
// Delete bookings for sessions matching this block (only this school)
$stmtDelBookings = $pdo->prepare("
DELETE sb
FROM session_bookings sb
JOIN class_sessions cs ON sb.session_id = cs.id
JOIN class_types ct ON cs.class_type_id = ct.id
JOIN classes c ON ct.class_id = c.id
WHERE c.school_id = ?
AND cs.propagation_id = ?
AND cs.class_type_id = ?
AND cs.start_time = ?
AND cs.end_time = ?
");
$stmtDelBookings->execute([$school_id, $propagation_id, $class_type_id, $start_time, $end_time]);
$deletedBookings = $stmtDelBookings->rowCount();
// Delete sessions for this block (only this school)
$stmtDelSessions = $pdo->prepare("
DELETE cs
FROM class_sessions cs
JOIN class_types ct ON cs.class_type_id = ct.id
JOIN classes c ON ct.class_id = c.id
WHERE c.school_id = ?
AND cs.propagation_id = ?
AND cs.class_type_id = ?
AND cs.start_time = ?
AND cs.end_time = ?
");
$stmtDelSessions->execute([$school_id, $propagation_id, $class_type_id, $start_time, $end_time]);
$deletedSessions = $stmtDelSessions->rowCount();
$pdo->commit();
$feedback = "<div class='alert alert-success alert-dismissible fade show'>
Propagazione rimossa con successo.
<br><small>
<strong>Codice:</strong> " . htmlspecialchars($propagation_id) . " |
<strong>Sessioni eliminate:</strong> {$deletedSessions} |
<strong>Prenotazioni eliminate:</strong> {$deletedBookings}
</small>
<button type='button' class='btn-close' data-bs-dismiss='alert'></button>
</div>";
} catch (Throwable $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
$feedback = "<div class='alert alert-danger alert-dismissible fade show'>
Errore durante la cancellazione: " . htmlspecialchars($e->getMessage()) . "
<button type='button' class='btn-close' data-bs-dismiss='alert'></button>
</div>";
}
}
}
}
/*
|--------------------------------------------------------------------------
| 4) Load propagation blocks (GROUPED - no single sessions list)
|--------------------------------------------------------------------------
| One row per propagation_id + class_type + time range.
|--------------------------------------------------------------------------
*/
$stmt = $pdo->prepare("
SELECT
cs.propagation_id,
ct.id AS class_type_id,
c.name AS class_name,
ct.level,
ct.day_of_week,
cs.start_time,
cs.end_time,
MIN(cs.session_date) AS range_start,
MAX(cs.session_date) AS range_end,
COUNT(DISTINCT cs.id) AS sessions_count,
SUM(CASE WHEN sb.id IS NULL THEN 0 ELSE 1 END) AS bookings_count
FROM class_sessions cs
JOIN class_types ct ON cs.class_type_id = ct.id
JOIN classes c ON ct.class_id = c.id
LEFT JOIN session_bookings sb ON sb.session_id = cs.id
WHERE c.school_id = ?
AND cs.propagation_id IS NOT NULL
AND cs.propagation_id <> ''
GROUP BY
cs.propagation_id,
ct.id,
c.name,
ct.level,
ct.day_of_week,
cs.start_time,
cs.end_time
ORDER BY range_start DESC, c.name ASC, cs.start_time ASC
");
$stmt->execute([$school_id]);
$blocks = $stmt->fetchAll(PDO::FETCH_ASSOC);
/*
|--------------------------------------------------------------------------
| 5) Optional quick counters for a nicer header
|--------------------------------------------------------------------------
*/
$totalBlocks = count($blocks);
$totalSessions = 0;
$totalBookings = 0;
foreach ($blocks as $b) {
$totalSessions += (int)($b['sessions_count'] ?? 0);
$totalBookings += (int)($b['bookings_count'] ?? 0);
}
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Propagazioni - <?php echo htmlspecialchars($school_name); ?></title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<!-- Header (same style as your other pages) -->
<div class="card radius-10 mb-4">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="me-4">
<img src="<?php echo $school['logo'] ? htmlspecialchars($school['logo']) : 'assets/images/default-school-logo.png'; ?>"
alt="Logo" class="rounded-circle" style="width: 90px; height: 90px; object-fit: cover;">
</div>
<div class="flex-grow-1">
<h4 class="mb-1">Propagazioni - <?php echo htmlspecialchars($school_name); ?></h4>
<p class="mb-0 text-muted">
Vista “a blocchi”: codice propagazione + classe + giorno/ora + range (daa).
Nessun elenco di singole sessioni.
</p>
</div>
<div class="text-end">
<a href="school_dashboard.php" class="btn btn-outline-primary"> Dashboard</a>
</div>
</div>
<!-- Small summary badges -->
<div class="mt-3 d-flex flex-wrap gap-2">
<span class="badge bg-primary">Blocchi: <?php echo (int)$totalBlocks; ?></span>
<span class="badge bg-info text-dark">Sessioni generate: <?php echo (int)$totalSessions; ?></span>
<span class="badge bg-secondary">Prenotazioni totali: <?php echo (int)$totalBookings; ?></span>
</div>
</div>
</div>
<?php echo $feedback; ?>
<?php if (empty($blocks)): ?>
<div class="card radius-10">
<div class="card-body text-center py-5">
<h5 class="text-muted">Nessuna propagazione trovata.</h5>
<p class="text-muted mb-0">Quando generi lezioni propagate, appariranno qui raggruppate per blocchi.</p>
</div>
</div>
<?php else: ?>
<!-- Main table -->
<div class="card radius-10">
<div class="card-header bg-primary text-white d-flex align-items-center justify-content-between">
<h5 class="mb-0">Blocchi di Propagazione</h5>
<div class="d-flex align-items-center gap-2">
<input type="text" id="quickSearch" class="form-control form-control-sm"
placeholder="Cerca codice / classe / giorno..." style="max-width: 320px;">
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0" id="blocksTable">
<thead class="table-light">
<tr>
<th style="white-space:nowrap;">Codice</th>
<th>Classe</th>
<th style="white-space:nowrap;">Giorno</th>
<th style="white-space:nowrap;">Ora</th>
<th style="white-space:nowrap;">Da</th>
<th style="white-space:nowrap;">A</th>
<th style="white-space:nowrap;" class="text-center">Sessioni</th>
<th style="white-space:nowrap;" class="text-center">Prenotazioni</th>
<th style="white-space:nowrap;" class="text-end">Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($blocks as $b): ?>
<?php
$pid = $b['propagation_id'];
$hash = md5($pid . '|' . $b['class_type_id'] . '|' . $b['start_time'] . '|' . $b['end_time']);
$dayLabel = itDayLabel((string)$b['day_of_week']);
$timeLabel = safeTime($b['start_time']) . ' - ' . safeTime($b['end_time']);
$from = $b['range_start'] ? date('d/m/Y', strtotime($b['range_start'])) : '—';
$to = $b['range_end'] ? date('d/m/Y', strtotime($b['range_end'])) : '—';
$sessionsCount = (int)($b['sessions_count'] ?? 0);
$bookingsCount = (int)($b['bookings_count'] ?? 0);
$level = $b['level'] ? ucfirst($b['level']) : '';
?>
<tr>
<td>
<code><?php echo htmlspecialchars($pid); ?></code>
<div class="text-muted"><small>ID tipo: <?php echo (int)$b['class_type_id']; ?></small></div>
</td>
<td>
<div class="fw-bold"><?php echo htmlspecialchars($b['class_name']); ?></div>
<?php if ($level): ?>
<small class="text-muted">Livello: <?php echo htmlspecialchars($level); ?></small>
<?php endif; ?>
</td>
<td><?php echo htmlspecialchars($dayLabel); ?></td>
<td><span class="badge bg-light text-dark"><?php echo htmlspecialchars($timeLabel); ?></span></td>
<td><?php echo $from; ?></td>
<td><?php echo $to; ?></td>
<td class="text-center"><span class="badge bg-info text-dark"><?php echo $sessionsCount; ?></span></td>
<td class="text-center"><span class="badge bg-secondary"><?php echo $bookingsCount; ?></span></td>
<td class="text-end">
<button type="button"
class="btn btn-sm btn-danger"
data-bs-toggle="modal"
data-bs-target="#deleteBlockModal-<?php echo $hash; ?>">
<i class="bx bx-trash"></i> Cancella
</button>
</td>
</tr>
<!-- Delete modal (clean and safe) -->
<div class="modal fade" id="deleteBlockModal-<?php echo $hash; ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<form method="POST">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title">Cancella Blocco Propagazione</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Stai per cancellare questo blocco:</p>
<ul class="mb-3">
<li><strong>Codice:</strong> <code><?php echo htmlspecialchars($pid); ?></code></li>
<li><strong>Classe:</strong> <?php echo htmlspecialchars($b['class_name']); ?> <?php echo $level ? '(' . htmlspecialchars($level) . ')' : ''; ?></li>
<li><strong>Giorno:</strong> <?php echo htmlspecialchars($dayLabel); ?></li>
<li><strong>Ora:</strong> <?php echo htmlspecialchars($timeLabel); ?></li>
<li><strong>Range:</strong> <?php echo $from; ?> → <?php echo $to; ?></li>
<li><strong>Sessioni:</strong> <?php echo $sessionsCount; ?> | <strong>Prenotazioni:</strong> <?php echo $bookingsCount; ?></li>
</ul>
<div class="alert alert-warning mb-0">
Verranno eliminate:
<ul class="mb-0">
<li>tutte le righe in <code>session_bookings</code> collegate a queste sessioni</li>
<li>tutte le righe in <code>class_sessions</code> di questo blocco</li>
</ul>
<small>Operazione irreversibile.</small>
</div>
<input type="hidden" name="action" value="delete_propagation_block">
<input type="hidden" name="propagation_id" value="<?php echo htmlspecialchars($pid); ?>">
<input type="hidden" name="class_type_id" value="<?php echo (int)$b['class_type_id']; ?>">
<input type="hidden" name="start_time" value="<?php echo htmlspecialchars($b['start_time']); ?>">
<input type="hidden" name="end_time" value="<?php echo htmlspecialchars($b['end_time']); ?>">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
<button type="submit" class="btn btn-danger">, cancella</button>
</div>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Quick search JS (no dependencies) -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const input = document.getElementById('quickSearch');
const table = document.getElementById('blocksTable');
if (!input || !table) return;
input.addEventListener('input', () => {
const q = input.value.toLowerCase().trim();
const rows = table.querySelectorAll('tbody tr');
rows.forEach(tr => {
const text = tr.innerText.toLowerCase();
tr.style.display = (text.includes(q)) ? '' : 'none';
});
});
});
</script>
<?php endif; ?>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
</body>
</html>

View File

@ -829,6 +829,7 @@ $daily_sessions = $stmt->fetchAll();
</div>
<div>
<a href="future_sessions.php" class="btn btn-primary">Calendario Lezioni</a>
<a href="propagation_manager.php" class="btn btn-warning">Lista Propagazioni</a>
<a href="school_profile.php" class="btn btn-warning">Modifica Profilo</a>
</div>
</div>
@ -983,7 +984,6 @@ $daily_sessions = $stmt->fetchAll();
<th>Sala</th>
<th>Insegnante</th>
<th>Stato</th>
<th>Prenotati</th>
<th>Azioni</th>
</tr>
</thead>