yogiboook_new/public/userarea/school_dashboard.php
2026-01-28 20:32:02 +01:00

1993 lines
116 KiB
PHP

<?php
// Forza la visualizzazione degli errori
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
include('include/headscript.php');
// Connessione al database
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
// Verifica che iduserlogin sia definito
if (!isset($iduserlogin)) {
die("Errore: ID utente non definito.");
}
// Recupera i dati della scuola in base all'utente loggato
$stmt = $pdo->prepare("
SELECT id, name, website, email, phone, description, address_street, address_city, address_postal_code, address_province, address_country, logo, status
FROM schools
WHERE owner_id = ?
ORDER BY id DESC
LIMIT 1
");
$stmt->execute([$iduserlogin]);
$school = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$school) {
// Owner/admin senza scuola: manda al profilo scuola (creazione)
$_SESSION['school_id'] = 0;
header("Location: school_profile.php");
exit;
}
// ok: scuola trovata → sincronizza sessione
$school_id = (int)$school['id'];
$_SESSION['school_id'] = $school_id;
$school_name = $school['name'];
// Recupera tutte le categorie disponibili
$stmt = $pdo->prepare("SELECT id, name FROM class_categories WHERE status = 'active' ORDER BY name");
$stmt->execute();
$categories = $stmt->fetchAll();
// Recupera tutti gli insegnanti della scuola
// Teachers linked to this school (active/pending)
$stmt = $pdo->prepare("
SELECT
t.id,
u.first_name,
u.last_name
FROM teacher_schools ts
JOIN teachers t ON ts.teacher_id = t.id
JOIN auth_users u ON t.user_id = u.id
WHERE ts.school_id = ?
AND ts.status IN ('active','pending')
ORDER BY u.first_name, u.last_name
");
$stmt->execute([$school_id]);
$teachers = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Funzione per ridimensionare l'immagine
function resizeImage($source_path, $dest_path, $max_width = 800)
{
list($width, $height, $type) = getimagesize($source_path);
if ($width <= $max_width) {
copy($source_path, $dest_path);
return;
}
$new_width = $max_width;
$new_height = (int)(($height * $new_width) / $width);
switch ($type) {
case IMAGETYPE_JPEG:
$source = imagecreatefromjpeg($source_path);
break;
case IMAGETYPE_PNG:
$source = imagecreatefrompng($source_path);
break;
case IMAGETYPE_GIF:
$source = imagecreatefromgif($source_path);
break;
default:
throw new Exception("Formato immagine non supportato.");
}
$dest = imagecreatetruecolor($new_width, $new_height);
if ($type == IMAGETYPE_PNG) {
imagealphablending($dest, false);
imagesavealpha($dest, true);
}
imagecopyresampled($dest, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
switch ($type) {
case IMAGETYPE_JPEG:
imagejpeg($dest, $dest_path, 90);
break;
case IMAGETYPE_PNG:
imagepng($dest, $dest_path);
break;
case IMAGETYPE_GIF:
imagegif($dest, $dest_path);
break;
}
imagedestroy($source);
imagedestroy($dest);
}
// Gestione delle azioni (aggiunta, modifica, cancellazione)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
// Aggiunta di una nuova classe
if ($action === 'add') {
$category_id = $_POST['category_id'] ?? 0;
$name = $_POST['name'] ?? '';
$description = $_POST['description'] ?? null;
$requirements = $_POST['requirements'] ?? null;
$status = $_POST['status'] === 'active' ? 'active' : 'inactive';
if (empty($name) || $category_id <= 0) {
$error = "I campi obbligatori non sono stati compilati.";
} else {
$photo = null;
if (isset($_FILES['photo']) && $_FILES['photo']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['photo'];
$timestamp = time();
$original_name = basename($file['name']);
$extension = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
if (in_array($extension, $allowed_extensions)) {
$new_filename = "photoclass/{$school_id}-{$timestamp}-{$original_name}";
$temp_path = $file['tmp_name'];
try {
resizeImage($temp_path, $new_filename);
$photo = $new_filename;
} catch (Exception $e) {
$error = "Errore durante il ridimensionamento della foto: " . $e->getMessage();
}
} else {
$error = "Estensione del file non consentita. Usa JPG, JPEG, PNG o GIF.";
}
}
if (!isset($error)) {
$stmt = $pdo->prepare("
INSERT INTO classes (school_id, category_id, name, description, photo, requirements, status)
VALUES (?, ?, ?, ?, ?, ?, ?)
");
$success = $stmt->execute([
$school_id,
$category_id,
$name,
$description,
$photo,
$requirements,
$status
]);
if ($success) {
$success_message = "Classe aggiunta con successo!";
} else {
$error = "Errore durante l'aggiunta della classe.";
}
}
}
}
// Modifica di una classe esistente
if ($action === 'edit') {
$id = $_POST['id'] ?? 0;
$category_id = $_POST['category_id'] ?? 0;
$name = $_POST['name'] ?? '';
$description = $_POST['description'] ?? null;
$requirements = $_POST['requirements'] ?? null;
$status = $_POST['status'] === 'active' ? 'active' : 'inactive';
if (empty($name) || $category_id <= 0) {
$error = "I campi obbligatori non sono stati compilati.";
} else {
// Recupera la classe esistente per ottenere il percorso della foto attuale
$stmt = $pdo->prepare("SELECT photo FROM classes WHERE id = ? AND school_id = ?");
$stmt->execute([$id, $school_id]);
$class = $stmt->fetch();
if (!$class) {
$error = "Classe non trovata.";
} else {
$photo = $class['photo'];
if (isset($_FILES['photo']) && $_FILES['photo']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['photo'];
$timestamp = time();
$original_name = basename($file['name']);
$extension = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
if (in_array($extension, $allowed_extensions)) {
$new_filename = "photoclass/{$school_id}-{$timestamp}-{$original_name}";
$temp_path = $file['tmp_name'];
try {
resizeImage($temp_path, $new_filename);
$photo = $new_filename;
if ($class['photo'] && file_exists($class['photo'])) {
unlink($class['photo']);
}
} catch (Exception $e) {
$error = "Errore durante il ridimensionamento della foto: " . $e->getMessage();
}
} else {
$error = "Estensione del file non consentita. Usa JPG, JPEG, PNG o GIF.";
}
}
if (!isset($error)) {
$stmt = $pdo->prepare("
UPDATE classes
SET category_id = ?, name = ?, description = ?, photo = ?, requirements = ?, status = ?
WHERE id = ? AND school_id = ?
");
$success = $stmt->execute([
$category_id,
$name,
$description,
$photo,
$requirements,
$status,
$id,
$school_id
]);
if ($success) {
$success_message = "Classe aggiornata con successo!";
} else {
$error = "Errore durante l'aggiornamento della classe.";
}
}
}
}
}
// Cancellazione di una classe
if ($action === 'delete') {
$id = $_POST['id'] ?? 0;
$stmt = $pdo->prepare("SELECT photo FROM classes WHERE id = ? AND school_id = ?");
$stmt->execute([$id, $school_id]);
$class = $stmt->fetch();
if ($class) {
if ($class['photo'] && file_exists($class['photo'])) {
unlink($class['photo']);
}
$stmt = $pdo->prepare("DELETE FROM classes WHERE id = ? AND school_id = ?");
$success = $stmt->execute([$id, $school_id]);
if ($success) {
$success_message = "Classe eliminata con successo!";
} else {
$error = "Errore durante l'eliminazione della classe.";
}
} else {
$error = "Classe non trovata.";
}
}
// Aggiunta di una variazione
if ($action === 'add_variation') {
$class_id = $_POST['class_id'] ?? 0;
$level = in_array($_POST['level'], ['beginner', 'intermediate', 'advanced']) ? $_POST['level'] : 'beginner';
$typical_duration = $_POST['typical_duration'] ? (int)$_POST['typical_duration'] : null;
$max_capacity = $_POST['max_capacity'] ? (int)$_POST['max_capacity'] : 0;
$day_of_week = in_array($_POST['day_of_week'], ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']) ? $_POST['day_of_week'] : null;
$start_time = $_POST['start_time'] ?? '';
$room_name = $_POST['room_name'] ?? null;
$notes = $_POST['notes'] ?? null;
$status = $_POST['status'] === 'active' ? 'active' : 'inactive';
if ($class_id <= 0 || empty($day_of_week) || empty($start_time)) {
$error = "I campi obbligatori non sono stati compilati.";
} else {
$photo = null;
if (isset($_FILES['photo']) && $_FILES['photo']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['photo'];
$timestamp = time();
$original_name = basename($file['name']);
$extension = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
if (in_array($extension, $allowed_extensions)) {
$new_filename = "photoclass/{$school_id}-{$timestamp}-{$original_name}";
$temp_path = $file['tmp_name'];
try {
resizeImage($temp_path, $new_filename);
$photo = $new_filename;
} catch (Exception $e) {
$error = "Errore durante il ridimensionamento della foto: " . $e->getMessage();
}
} else {
$error = "Estensione del file non consentita. Usa JPG, JPEG, PNG o GIF.";
}
}
if (!isset($error)) {
$stmt = $pdo->prepare("
INSERT INTO class_types (class_id, school_id, level, typical_duration, max_capacity, day_of_week, start_time, room_name, notes, photo, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$success = $stmt->execute([
$class_id,
$school_id,
$level,
$typical_duration,
$max_capacity,
$day_of_week,
$start_time,
$room_name,
$notes,
$photo,
$status
]);
if ($success) {
$success_message = "Variazione aggiunta con successo!";
} else {
$error = "Errore durante l'aggiunta della variazione.";
}
}
}
}
// Modifica di una variazione
if ($action === 'edit_variation') {
$id = $_POST['id'] ?? 0;
$class_id = $_POST['class_id'] ?? 0;
$level = in_array($_POST['level'], ['beginner', 'intermediate', 'advanced']) ? $_POST['level'] : 'beginner';
$typical_duration = $_POST['typical_duration'] ? (int)$_POST['typical_duration'] : null;
$max_capacity = $_POST['max_capacity'] ? (int)$_POST['max_capacity'] : 0;
$day_of_week = in_array($_POST['day_of_week'], ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']) ? $_POST['day_of_week'] : null;
$start_time = $_POST['start_time'] ?? '';
$room_name = $_POST['room_name'] ?? null;
$notes = $_POST['notes'] ?? null;
$status = $_POST['status'] === 'active' ? 'active' : 'inactive';
if ($id <= 0 || $class_id <= 0 || empty($day_of_week) || empty($start_time)) {
$error = "I campi obbligatori non sono stati compilati.";
} else {
// Recupera la variazione esistente per ottenere il percorso della foto attuale
$stmt = $pdo->prepare("SELECT photo FROM class_types WHERE id = ? AND school_id = ? AND class_id = ?");
$stmt->execute([$id, $school_id, $class_id]);
$variation = $stmt->fetch();
if (!$variation) {
$error = "Variazione non trovata.";
} else {
$photo = $variation['photo'];
if (isset($_FILES['photo']) && $_FILES['photo']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['photo'];
$timestamp = time();
$original_name = basename($file['name']);
$extension = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
if (in_array($extension, $allowed_extensions)) {
$new_filename = "photoclass/{$school_id}-{$timestamp}-{$original_name}";
$temp_path = $file['tmp_name'];
try {
resizeImage($temp_path, $new_filename);
$photo = $new_filename;
if ($variation['photo'] && file_exists($variation['photo'])) {
unlink($variation['photo']);
}
} catch (Exception $e) {
$error = "Errore durante il ridimensionamento della foto: " . $e->getMessage();
}
} else {
$error = "Estensione del file non consentita. Usa JPG, JPEG, PNG o GIF.";
}
}
if (!isset($error)) {
$stmt = $pdo->prepare("
UPDATE class_types
SET level = ?, typical_duration = ?, max_capacity = ?, day_of_week = ?, start_time = ?, room_name = ?, notes = ?, photo = ?, status = ?
WHERE id = ? AND school_id = ? AND class_id = ?
");
$success = $stmt->execute([
$level,
$typical_duration,
$max_capacity,
$day_of_week,
$start_time,
$room_name,
$notes,
$photo,
$status,
$id,
$school_id,
$class_id
]);
if ($success) {
$success_message = "Variazione aggiornata con successo!";
} else {
$error = "Errore durante l'aggiornamento della variazione.";
}
}
}
}
}
// Cancellazione di una variazione
if ($action === 'delete_variation') {
$id = $_POST['id'] ?? 0;
$class_id = $_POST['class_id'] ?? 0;
$stmt = $pdo->prepare("SELECT photo FROM class_types WHERE id = ? AND school_id = ? AND class_id = ?");
$stmt->execute([$id, $school_id, $class_id]);
$variation = $stmt->fetch();
if ($variation) {
if ($variation['photo'] && file_exists($variation['photo'])) {
unlink($variation['photo']);
}
$stmt = $pdo->prepare("DELETE FROM class_types WHERE id = ? AND school_id = ? AND class_id = ?");
$success = $stmt->execute([$id, $school_id, $class_id]);
if ($success) {
$success_message = "Variazione eliminata con successo!";
} else {
$error = "Errore durante l'eliminazione della variazione.";
}
} else {
$error = "Variazione non trovata.";
}
}
// Assegnazione di un insegnante
if ($action === 'assign_teacher') {
$class_type_id = $_POST['class_type_id'] ?? 0;
$teacher_id = !empty($_POST['teacher_id']) ? (int)$_POST['teacher_id'] : null;
// Verifica che la variazione appartenga alla scuola
$stmt = $pdo->prepare("SELECT id FROM class_types WHERE id = ? AND school_id = ?");
$stmt->execute([$class_type_id, $school_id]);
if (!$stmt->fetch()) {
$error = "Variazione non trovata.";
} else {
// Se teacher_id è null, rimuoviamo l'assegnazione; altrimenti, assegniamo l'insegnante
$stmt = $pdo->prepare("UPDATE class_types SET teacher_id = ? WHERE id = ?");
$success = $stmt->execute([$teacher_id, $class_type_id]);
if ($success) {
$success_message = "Insegnante assegnato con successo!";
} else {
$error = "Errore durante l'assegnazione dell'insegnante.";
}
}
}
// Propagazione delle sessioni
if ($action === 'propagate_sessions') {
$class_type_id = $_POST['class_type_id'] ?? 0;
$start_date = $_POST['start_date'] ?? '';
$end_date = $_POST['end_date'] ?? '';
// Validazione delle date
if (empty($start_date) || empty($end_date)) {
$error = "Le date di inizio e fine sono obbligatorie.";
} elseif (strtotime($end_date) < strtotime($start_date)) {
$error = "La data di fine non può essere precedente alla data di inizio.";
} else {
// Verifica che la variazione appartenga alla scuola
$stmt = $pdo->prepare("
SELECT ct.day_of_week, ct.start_time, ct.typical_duration, ct.teacher_id, ct.class_id, ct.school_id, ct.max_capacity, ct.notes
FROM class_types ct
WHERE ct.id = ? AND ct.school_id = ?
");
$stmt->execute([$class_type_id, $school_id]);
$variation = $stmt->fetch();
if (!$variation) {
$error = "Variazione non trovata.";
} else {
// Recupera i giorni di chiusura della scuola
$stmt = $pdo->prepare("
SELECT start_date, end_date
FROM day_off
WHERE school_id = ? AND (
(start_date BETWEEN ? AND ?) OR
(end_date BETWEEN ? AND ?) OR
(start_date <= ? AND end_date >= ?)
)
");
$stmt->execute([
$school_id,
$start_date,
$end_date,
$start_date,
$end_date,
$start_date,
$end_date
]);
$days_off = $stmt->fetchAll();
// Crea un array di giorni di chiusura
$off_dates = [];
foreach ($days_off as $day_off) {
$current = new DateTime($day_off['start_date']);
$end = new DateTime($day_off['end_date']);
while ($current <= $end) {
$off_dates[] = $current->format('Y-m-d');
$current->modify('+1 day');
}
}
// Mappa i giorni della settimana per il confronto
$days_map = [
'monday' => 'Monday',
'tuesday' => 'Tuesday',
'wednesday' => 'Wednesday',
'thursday' => 'Thursday',
'friday' => 'Friday',
'saturday' => 'Saturday',
'sunday' => 'Sunday'
];
$day_of_week_english = $days_map[$variation['day_of_week']];
// Calcola l'orario di fine
$start_time = new DateTime($variation['start_time']);
$end_time = clone $start_time;
if ($variation['typical_duration']) {
$end_time->modify("+{$variation['typical_duration']} minutes");
} else {
$end_time->modify("+60 minutes"); // Default: 1 ora se la durata non è specificata
}
// Genera un propagation_id univoco
$propagation_id = uniqid('prop_', true);
// Genera le sessioni
$current_date = new DateTime($start_date);
$end_date_dt = new DateTime($end_date);
$end_date_dt->setTime(23, 59, 59); // Include l'ultimo giorno
// Prepara la query per verificare se una sessione esiste già
$checkStmt = $pdo->prepare("
SELECT id
FROM class_sessions
WHERE class_type_id = ? AND session_date = ?
");
// Prepara la query di inserimento
$stmt = $pdo->prepare("
INSERT INTO class_sessions (class_id, school_id, class_type_id, session_date, start_time, end_time, teacher_id, max_capacity, notes, status, propagation_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'scheduled', ?)
");
$sessions_created = 0;
$sessions_skipped = 0;
while ($current_date <= $end_date_dt) {
$day_of_week = $current_date->format('l');
$current_date_str = $current_date->format('Y-m-d');
if (!in_array($current_date_str, $off_dates) && $day_of_week === $day_of_week_english) {
$session_date = $current_date->format('Y-m-d');
$start_time_str = $start_time->format('H:i:s');
$end_time_str = $end_time->format('H:i:s');
// Verifica se una sessione esiste già per questa variazione e data
$checkStmt->execute([$class_type_id, $session_date]);
if ($checkStmt->fetch()) {
$sessions_skipped++;
continue; // Salta se esiste già
}
try {
$stmt->execute([
$variation['class_id'],
$variation['school_id'],
$class_type_id,
$session_date,
$start_time_str,
$end_time_str,
$variation['teacher_id'],
$variation['max_capacity'],
$variation['notes'],
$propagation_id
]);
$sessions_created++;
} catch (PDOException $e) {
$error = "Errore durante la propagazione delle sessioni: " . $e->getMessage();
break;
}
}
$current_date->modify('+1 day');
}
if (!isset($error)) {
$success_message = "Propagate $sessions_created sessioni con successo! (Saltate $sessions_skipped sessioni già esistenti) (ID Propagazione: $propagation_id)";
echo "<script>
document.addEventListener('DOMContentLoaded', function() {
var successModalElement = document.getElementById('successPropagationModal');
var successModal = new bootstrap.Modal(successModalElement, { backdrop: true });
document.getElementById('successPropagationMessage').innerText = '$success_message';
successModal.show();
setTimeout(function() {
successModal.hide();
// Rimuove il backdrop manualmente
document.querySelector('.modal-backdrop')?.remove();
document.body.classList.remove('modal-open');
document.body.style.overflow = 'auto'; // Ripristina lo scroll
// Reindirizza dopo la chiusura del modale
window.location.href = 'school_dashboard.php';
}, 3000); // Chiude il modale dopo 3 secondi
});
</script>";
}
if (!isset($error)) {
$success_message = "Propagate $sessions_created sessioni con successo! (ID Propagazione: $propagation_id)";
echo "<script>
document.addEventListener('DOMContentLoaded', function() {
var successModal = new bootstrap.Modal(document.getElementById('successPropagationModal'), {});
document.getElementById('successPropagationMessage').innerText = '$success_message';
successModal.show();
});
</script>";
}
}
}
}
// Rimozione di una propagazione
if ($action === 'remove_propagation') {
$propagation_id = $_POST['propagation_id'] ?? '';
$class_type_id = $_POST['class_type_id'] ?? 0;
if (empty($propagation_id) || $class_type_id <= 0) {
$error = "ID di propagazione o variazione non validi.";
} else {
// Verifica che la variazione appartenga alla scuola
$stmt = $pdo->prepare("SELECT id FROM class_types WHERE id = ? AND school_id = ?");
$stmt->execute([$class_type_id, $school_id]);
if (!$stmt->fetch()) {
$error = "Variazione non trovata.";
} else {
// Elimina tutte le sessioni associate a questa propagazione
$stmt = $pdo->prepare("
DELETE FROM class_sessions
WHERE propagation_id = ? AND class_type_id = ?
");
$stmt->execute([$propagation_id, $class_type_id]);
$deleted_rows = $stmt->rowCount();
$success_message = "Propagazione rimossa con successo! ($deleted_rows sessioni eliminate)";
}
}
}
// Cancellazione di una sessione
if ($action === 'delete_session') {
$id = $_POST['id'] ?? 0;
// Verifica che la sessione appartenga alla scuola
$stmt = $pdo->prepare("
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 cs.id = ? AND c.school_id = ?
");
$stmt->execute([$id, $school_id]);
if ($stmt->fetch()) {
$stmt = $pdo->prepare("DELETE FROM class_sessions WHERE id = ?");
$success = $stmt->execute([$id]);
if ($success) {
$success_message = "Sessione eliminata con successo!";
} else {
$error = "Errore durante l'eliminazione della sessione.";
}
} else {
$error = "Sessione non trovata.";
}
}
// Modifica di una sessione
if ($action === 'edit_session') {
$id = $_POST['id'] ?? 0;
$class_type_id = $_POST['class_type_id'] ?? 0;
$session_date = $_POST['session_date'] ?? '';
$start_time = $_POST['start_time'] ?? '';
$end_time = $_POST['end_time'] ?? '';
$teacher_id = !empty($_POST['teacher_id']) ? (int)$_POST['teacher_id'] : null;
$status = in_array($_POST['status'], ['scheduled', 'completed', 'cancelled']) ? $_POST['status'] : 'scheduled';
if (empty($session_date) || empty($start_time) || empty($end_time)) {
$error = "I campi obbligatori non sono stati compilati.";
} elseif (strtotime($end_time) <= strtotime($start_time)) {
$error = "L'orario di fine non può essere precedente o uguale all'orario di inizio.";
} else {
// Verifica che la sessione appartenga alla scuola
$stmt = $pdo->prepare("
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 cs.id = ? AND c.school_id = ?
");
$stmt->execute([$id, $school_id]);
if (!$stmt->fetch()) {
$error = "Sessione non trovata.";
} else {
$stmt = $pdo->prepare("
UPDATE class_sessions
SET session_date = ?, start_time = ?, end_time = ?, teacher_id = ?, status = ?
WHERE id = ?
");
$success = $stmt->execute([
$session_date,
$start_time,
$end_time,
$teacher_id,
$status,
$id
]);
if ($success) {
$success_message = "Sessione aggiornata con successo!";
} else {
$error = "Errore durante l'aggiornamento della sessione.";
}
}
}
}
// Non Reindirizza per evitare il doppio invio del form
}
}
// Recupera tutte le classi della scuola con le loro variazioni
$stmt = $pdo->prepare("
SELECT c.*, cc.name AS category_name
FROM classes c
LEFT JOIN class_categories cc ON c.category_id = cc.id
WHERE c.school_id = ?
ORDER BY c.created_at DESC
");
$stmt->execute([$school_id]);
$classes = $stmt->fetchAll();
// Recupera le variazioni per ogni classe
$class_variations = [];
foreach ($classes as $class) {
$stmt = $pdo->prepare("
SELECT ct.*, t.first_name AS teacher_first_name, t.last_name AS teacher_last_name
FROM class_types ct
LEFT JOIN teachers t ON ct.teacher_id = t.id
WHERE ct.class_id = ? AND ct.school_id = ?
ORDER BY ct.day_of_week, ct.start_time
");
$stmt->execute([$class['id'], $school_id]);
$class_variations[$class['id']] = $stmt->fetchAll();
}
// Recupera la data selezionata per le sessioni della giornata (default: oggi)
$selected_date = $_GET['session_date'] ?? date('Y-m-d');
$selected_date_dt = new DateTime($selected_date);
$day_of_week_english = $selected_date_dt->format('l'); // Giorno della settimana in inglese (es. Monday)
// Mappa i giorni della settimana per il confronto
$days_map_reverse = [
'Monday' => 'monday',
'Tuesday' => 'tuesday',
'Wednesday' => 'wednesday',
'Thursday' => 'thursday',
'Friday' => 'friday',
'Saturday' => 'saturday',
'Sunday' => 'sunday'
];
$day_of_week = $days_map_reverse[$day_of_week_english];
// Recupera le sessioni per la data selezionata
$stmt = $pdo->prepare("
SELECT cs.*,
ct.level, ct.day_of_week, ct.start_time, ct.room_name, ct.teacher_id,
c.name AS class_name, c.photo AS class_photo,
ct.photo AS variation_photo,
t.first_name AS teacher_first_name, t.last_name AS teacher_last_name
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 teachers t ON cs.teacher_id = t.id
WHERE cs.session_date = ?
AND ct.day_of_week = ?
AND c.school_id = ?
ORDER BY cs.start_time
");
$stmt->execute([$selected_date, $day_of_week, $school_id]);
$daily_sessions = $stmt->fetchAll();
?>
<!doctype html>
<html lang="en">
<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'); ?>
<?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">
<!-- Sezione Informazioni Scuola -->
<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 Scuola" class="rounded-circle" style="width: 100px; height: 100px; object-fit: cover;">
</div>
<div class="flex-grow-1">
<h5 class="mb-1"><?php echo htmlspecialchars($school['name']); ?></h5>
<p class="mb-1">
<strong>Indirizzo:</strong>
<?php
$address_parts = array_filter([
$school['address_street'],
$school['address_city'],
$school['address_postal_code'],
$school['address_province'],
$school['address_country']
]);
echo htmlspecialchars(implode(', ', $address_parts)) ?: 'Non specificato';
?>
</p>
<p class="mb-1"><strong>Email:</strong> <?php echo htmlspecialchars($school['email'] ?: 'Non specificato'); ?></p>
<p class="mb-1"><strong>Telefono:</strong> <?php echo htmlspecialchars($school['phone'] ?: 'Non specificato'); ?></p>
<p class="mb-1"><strong>Sito Web:</strong>
<?php if ($school['website']): ?>
<a href="<?php echo htmlspecialchars($school['website']); ?>" target="_blank"><?php echo htmlspecialchars($school['website']); ?></a>
<?php else: ?>
Non specificato
<?php endif; ?>
</p>
<p class="mb-0"><strong>Descrizione:</strong> <?php echo htmlspecialchars($school['description'] ?: 'Non specificata'); ?></p>
</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>
</div>
</div>
<!-- Sezione Pulsantiera -->
<div class="row mb-4">
<div class="col-12">
<div class="d-flex flex-wrap justify-content-center gap-3">
<!-- Pulsante Situazione Clienti -->
<a href="clients_situation.php" class="btn btn-primary d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-user me-2" style="font-size: 20px;"></i>
<span class="fs-6">Situazione Clienti</span>
</a>
<!-- Pulsante Ordini -->
<a href="orders.php" class="btn btn-success d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-cart me-2" style="font-size: 20px;"></i>
<span class="fs-6">Ordini</span>
</a>
<!-- Pulsante Finanze -->
<a href="finances.php" class="btn btn-warning d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-dollar me-2" style="font-size: 20px;"></i>
<span class="fs-6">Finanze</span>
</a>
<a href="products.php" class="btn btn-dark d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-package me-2" style="font-size: 20px;"></i>
<span class="fs-6">Prodotti</span>
</a>
<!-- Pulsante Abbonamenti -->
<a href="add_user.php" class="btn btn-info d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-calendar me-2" style="font-size: 20px;"></i>
<span class="fs-6">Aggiungi Utente</span>
</a>
<!-- Pulsante Day Off -->
<a href="day_off.php" class="btn btn-danger d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-calendar-x me-2" style="font-size: 20px;"></i>
<span class="fs-6">Giorni di Chiusura</span>
</a>
<!-- Pulsante Impostazioni -->
<a href="school_settings.php" class="btn btn-dark d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-cog me-2" style="font-size: 20px;"></i>
<span class="fs-6">Impostazioni</span>
</a>
</div>
</div>
</div>
<!-- Sezione Classi -->
<div class="card radius-10">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0">Classi della scuola</h6>
</div>
<div class="ms-auto">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addClassModal">
Aggiungi Classe
</button>
</div>
</div>
</div>
<div class="card-body">
<?php if (isset($error)): ?>
<div class="alert alert-danger" role="alert">
<?php echo $error; ?>
</div>
<?php endif; ?>
<div class="table-responsive">
<table id="classesTable" class="table table-striped table-bordered">
<thead>
<tr>
<th></th> <!-- Colonna per il pulsante collassabile -->
<th>Categoria</th>
<th>Nome</th>
<th>Descrizione</th>
<th>Foto</th>
<th>Stato</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($classes as $class): ?>
<!-- Riga della classe generale -->
<tr>
<td>
<button class="btn btn-sm btn-outline-primary toggle-variations" type="button" data-bs-toggle="collapse" data-bs-target="#variations-<?php echo $class['id']; ?>" aria-expanded="false" aria-controls="variations-<?php echo $class['id']; ?>">
<i class="bx bx-chevron-down toggle-icon"></i>
</button>
</td>
<td><?php echo htmlspecialchars($class['category_name']); ?></td>
<td><?php echo htmlspecialchars($class['name']); ?></td>
<td><?php echo htmlspecialchars($class['description'] ?? ''); ?></td>
<td>
<?php if ($class['photo']): ?>
<img src="<?php echo htmlspecialchars($class['photo']); ?>" alt="Foto Classe" style="max-width: 50px; max-height: 50px;">
<?php else: ?>
Nessuna foto
<?php endif; ?>
</td>
<td>
<span class="badge <?php echo $class['status'] === 'active' ? 'bg-success' : 'bg-danger'; ?>">
<?php echo $class['status'] === 'active' ? 'Attivo' : 'Inattivo'; ?>
</span>
</td>
<td>
<button type="button" class="btn btn-sm btn-warning" data-bs-toggle="modal" data-bs-target="#editClassModal"
onclick='fillEditModal(<?php echo json_encode([
"id" => $class['id'],
"category_id" => $class['category_id'],
"name" => htmlspecialchars($class['name'], ENT_QUOTES),
"description" => htmlspecialchars($class['description'] ?? '', ENT_QUOTES),
"requirements" => htmlspecialchars($class['requirements'] ?? '', ENT_QUOTES),
"status" => $class['status']
]); ?>)'
data-bs-toggle="tooltip" data-bs-placement="top" title="Modifica">
<i class="bx bx-edit"></i>
</button>
<form action="" method="POST" style="display:inline;" onsubmit="return confirm('Sei sicuro di voler eliminare questa classe?');">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?php echo $class['id']; ?>">
<button type="submit" class="btn btn-sm btn-danger" data-bs-toggle="tooltip" data-bs-placement="top" title="Elimina">
<i class="bx bx-trash"></i>
</button>
</form>
<button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#addVariationModal"
onclick='fillAddVariationModal(<?php echo json_encode([
"class_id" => $class['id']
]); ?>)'
data-bs-toggle="tooltip" data-bs-placement="top" title="Aggiungi Variazione">
<i class="bx bx-plus"></i> Variazione
</button>
</td>
</tr>
<!-- Riga collassabile per le variazioni -->
<tr>
<td colspan="7" class="p-0">
<div class="collapse" id="variations-<?php echo $class['id']; ?>">
<div class="card card-body border-0">
<?php if (empty($class_variations[$class['id']])): ?>
<p class="text-muted mb-0">Nessuna variazione disponibile per questa classe.</p>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered mb-0">
<thead>
<tr>
<th>Livello</th>
<th>Durata (min)</th>
<th>Posti Massimi</th>
<th>Giorno</th>
<th>Orario</th>
<th>Sala</th>
<th>Insegnante</th>
<th>Stato</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($class_variations[$class['id']] as $variation): ?>
<tr>
<td><?php echo htmlspecialchars($variation['level']); ?></td>
<td><?php echo htmlspecialchars($variation['typical_duration'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($variation['max_capacity']); ?></td>
<td><?php echo htmlspecialchars(ucfirst($variation['day_of_week'])); ?></td>
<td><?php echo htmlspecialchars($variation['start_time']); ?></td>
<td><?php echo htmlspecialchars($variation['room_name'] ?? 'Non specificata'); ?></td>
<td>
<?php if ($variation['teacher_id']): ?>
<button type="button" class="btn btn-sm btn-info" data-bs-toggle="modal" data-bs-target="#assignTeacherModal"
onclick='fillAssignTeacherModal(<?php echo json_encode([
"class_type_id" => $variation['id'],
"teacher_id" => $variation['teacher_id']
]); ?>)'>
<?php echo htmlspecialchars($variation['teacher_first_name'] . ' ' . $variation['teacher_last_name']); ?>
</button>
<?php else: ?>
<button type="button" class="btn btn-sm btn-secondary" data-bs-toggle="modal" data-bs-target="#assignTeacherModal"
onclick='fillAssignTeacherModal(<?php echo json_encode([
"class_type_id" => $variation['id'],
"teacher_id" => null
]); ?>)'>
Non assegnato
</button>
<?php endif; ?>
</td>
<td>
<span class="badge <?php echo $variation['status'] === 'active' ? 'bg-success' : 'bg-danger'; ?>">
<?php echo $variation['status'] === 'active' ? 'Attivo' : 'Inattivo'; ?>
</span>
</td>
<td>
<button type="button" class="btn btn-sm btn-warning" data-bs-toggle="modal" data-bs-target="#editVariationModal"
onclick='fillEditVariationModal(<?php echo json_encode([
"id" => $variation['id'],
"class_id" => $variation['class_id'],
"level" => $variation['level'],
"typical_duration" => $variation['typical_duration'] ?? '',
"max_capacity" => $variation['max_capacity'],
"day_of_week" => $variation['day_of_week'],
"start_time" => $variation['start_time'],
"room_name" => htmlspecialchars($variation['room_name'] ?? '', ENT_QUOTES),
"notes" => htmlspecialchars($variation['notes'] ?? '', ENT_QUOTES),
"status" => $variation['status']
]); ?>)'
data-bs-toggle="tooltip" data-bs-placement="top" title="Modifica">
<i class="bx bx-edit"></i>
</button>
<form action="" method="POST" style="display:inline;" onsubmit="return confirm('Sei sicuro di voler eliminare questa variazione?');">
<input type="hidden" name="action" value="delete_variation">
<input type="hidden" name="id" value="<?php echo $variation['id']; ?>">
<input type="hidden" name="class_id" value="<?php echo $variation['class_id']; ?>">
<button type="submit" class="btn btn-sm btn-danger" data-bs-toggle="tooltip" data-bs-placement="top" title="Elimina">
<i class="bx bx-trash"></i>
</button>
</form>
<button type="button" class="btn btn-sm btn-success" data-bs-toggle="modal" data-bs-target="#propagateClassModal"
onclick='fillPropagateModal(<?php echo json_encode([
"class_type_id" => $variation['id']
]); ?>)'
data-bs-toggle="tooltip" data-bs-placement="top" title="Propaga">
<i class="bx bx-broadcast"></i> Propaga
</button>
<a href="class_type_associate.php?class_type_id=<?php echo (int)$variation['id']; ?>"
class="btn btn-sm btn-primary"
data-bs-toggle="tooltip" data-bs-placement="top" title="Associa per riprogrammazione">
<i class="bx bx-link"></i> Associa
</a>
<button type="button" class="btn btn-sm btn-danger" data-bs-toggle="modal" data-bs-target="#removePropagationModal"
onclick='fillRemovePropagationModal(<?php echo json_encode([
"class_type_id" => $variation['id']
]); ?>)'
data-bs-toggle="tooltip" data-bs-placement="top" title="Rimuovi Propagazione">
<i class="bx bx-undo"></i>
</button>
<a href="class_sessions.php?class_type_id=<?php echo $variation['id']; ?>" class="btn btn-sm btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="Lezioni">
<i class="bx bx-calendar-event"></i>
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Sezione Sessioni (Singolo giorno o Intervallo) -->
<div class="card radius-10 mb-4">
<div class="card-header">
<div class="d-flex align-items-center justify-content-between">
<h6 class="mb-0">Sessioni Programmata</h6>
<div class="d-flex gap-2">
<!-- I tuoi filtri data esistenti -->
<form action="" method="GET" class="d-flex flex-wrap align-items-center gap-2">
<div class="d-flex align-items-center gap-2">
<label class="me-2 mb-0 text-nowrap">Dal:</label>
<input type="date" name="start_date" class="form-control form-control-sm" value="<?php echo $_GET['start_date'] ?? date('Y-m-d'); ?>" required>
</div>
<div class="d-flex align-items-center gap-2">
<label class="me-2 mb-0 text-nowrap">Al:</label>
<input type="date" name="end_date" class="form-control form-control-sm" value="<?php echo $_GET['end_date'] ?? ''; ?>">
</div>
<button type="submit" class="btn btn-primary btn-sm">Mostra</button>
<?php if (isset($_GET['start_date'])): ?>
<a href="?" class="btn btn-outline-secondary btn-sm">Oggi</a>
<?php endif; ?>
</form>
<!-- PULSANTE CALENDARIO -->
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#calendarModal">
<i class="bx bx-calendar"></i> Vista Calendario
</button>
</div>
</div>
</div>
<div class="card-body">
<?php
// Determina le date da mostrare
$start_date = $_GET['start_date'] ?? date('Y-m-d');
$end_date = $_GET['end_date'] ?? $start_date;
if ($end_date < $start_date) {
echo '<div class="alert alert-warning">La data di fine non può essere precedente alla data di inizio.</div>';
$end_date = $start_date;
}
// Recupera tutte le sessioni nell'intervallo
// === NUOVA QUERY CON CONTEGGIO E LISTA PRENOTATI ===
$stmt = $pdo->prepare("
SELECT
cs.*,
ct.level, ct.day_of_week, ct.start_time AS ct_start_time, ct.room_name, ct.teacher_id,
c.name AS class_name, c.photo AS class_photo,
ct.photo AS variation_photo,
t.first_name AS teacher_first_name, t.last_name AS teacher_last_name,
-- Contiamo gli studenti prenotati (solo booked, attended, rescheduled)
(SELECT COUNT(*)
FROM session_bookings sb
WHERE sb.session_id = cs.id
AND sb.status IN ('booked', 'attended', 'rescheduled')
) AS booked_count,
-- Capacità massima (da class_sessions o da class_types se null)
COALESCE(cs.max_capacity, ct.max_capacity, 0) AS effective_capacity,
-- Lista studenti prenotati (per il modale)
(SELECT GROUP_CONCAT(
CONCAT(au.first_name, ' ', au.last_name, '|', au.email, '|', COALESCE(au.phone, ''))
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')
) AS booked_students
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 teachers t ON cs.teacher_id = t.id
WHERE cs.session_date BETWEEN ? AND ?
AND c.school_id = ?
ORDER BY cs.session_date, cs.start_time
");
$stmt->execute([$start_date, $end_date, $school_id]);
$range_sessions = $stmt->fetchAll();
?>
<div class="mb-3">
<strong>
<?php if ($start_date === $end_date): ?>
Sessioni del <span class="text-primary"><?php echo date('d/m/Y', strtotime($start_date)); ?></span>
<?php else: ?>
Sessioni dal <span class="text-primary"><?php echo date('d/m/Y', strtotime($start_date)); ?></span>
al <span class="text-primary"><?php echo date('d/m/Y', strtotime($end_date)); ?></span>
(<?php echo count($range_sessions); ?> totali)
<?php endif; ?>
</strong>
</div>
<div class="table-responsive">
<table id="dailySessionsTable" class="table table-striped table-bordered">
<thead>
<tr>
<th>Data</th>
<th>Classe</th>
<th>Livello</th>
<th>Orario</th>
<th>Sala</th>
<th>Insegnante</th>
<th>Stato</th>
<th>Prenotati</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php if (empty($range_sessions)): ?>
<tr>
<td colspan="8" class="text-center text-muted">
Nessuna sessione programmata in questo intervallo.
</td>
</tr>
<?php else: ?>
<?php
$current_date = '';
foreach ($range_sessions as $session):
$session_date = $session['session_date'];
if ($session_date !== $current_date):
$current_date = $session_date;
?>
<tr class="table-info">
<td colspan="8" class="fw-bold text-dark">
<?php echo date('d/m/Y (l)', strtotime($session_date)); ?>
</td>
</tr>
<?php endif; ?>
<tr>
<td><?php echo date('d/m', strtotime($session_date)); ?></td>
<td><?php echo htmlspecialchars($session['class_name']); ?></td>
<td><?php echo ucfirst($session['level']); ?></td>
<td><?php echo substr($session['start_time'], 0, 5); ?> - <?php echo substr($session['end_time'], 0, 5); ?></td>
<td><?php echo htmlspecialchars($session['room_name'] ?? '—'); ?></td>
<td>
<?php echo $session['teacher_id'] ? htmlspecialchars($session['teacher_first_name'] . ' ' . $session['teacher_last_name']) : '<em>Non assegnato</em>'; ?>
</td>
<td>
<span class="badge <?php
echo $session['status'] === 'scheduled' ? 'bg-info' : ($session['status'] === 'completed' ? 'bg-success' : 'bg-danger');
?>">
<?php echo $session['status'] === 'scheduled' ? 'Programmata' : ($session['status'] === 'completed' ? 'Completata' : 'Annullata'); ?>
</span>
</td>
<td>
<?php
$booked = $session['booked_count'];
$capacity = $session['effective_capacity'] > 0 ? $session['effective_capacity'] : '∞';
$color = ($capacity !== '∞' && $booked >= $capacity) ? 'danger' : 'success';
?>
<button type="button" class="btn btn-sm btn-<?php echo $color; ?> position-relative"
data-bs-toggle="modal" data-bs-target="#studentsModal-<?php echo $session['id']; ?>">
<?php echo $booked; ?> / <?php echo $capacity; ?>
<?php if ($booked > 0): ?>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-dark">
<?php echo $booked; ?>
<span class="visually-hidden">prenotati</span>
</span>
<?php endif; ?>
</button>
</td>
<td>
<button type="button" class="btn btn-sm btn-warning" data-bs-toggle="modal" data-bs-target="#editSessionModal"
onclick='fillEditSessionModal(<?php echo json_encode([
"id" => $session['id'],
"class_type_id" => $session['class_type_id'],
"session_date" => $session['session_date'],
"start_time" => $session['start_time'],
"end_time" => $session['end_time'],
"teacher_id" => $session['teacher_id'],
"status" => $session['status']
]); ?>)'>
<i class="bx bx-edit"></i>
</button>
<form action="" method="POST" style="display:inline;" onsubmit="return confirm('Eliminare questa sessione?');">
<input type="hidden" name="action" value="delete_session">
<input type="hidden" name="id" value="<?php echo $session['id']; ?>">
<button type="submit" class="btn btn-sm btn-danger">
<i class="bx bx-trash"></i>
</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Spazio per future sezioni -->
<!-- Puoi aggiungere altre sezioni qui sotto, come statistiche, eventi, ecc. -->
</div>
</div>
<!-- Modale per aggiungere una classe -->
<div class="modal fade" id="addClassModal" tabindex="-1" aria-labelledby="addClassModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addClassModalLabel">Aggiungi Classe</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="POST" enctype="multipart/form-data">
<div class="modal-body">
<input type="hidden" name="action" value="add">
<div class="row">
<div class="col-md-6 mb-3">
<label for="add_category_id" class="form-label">Categoria</label>
<select class="form-control" id="add_category_id" name="category_id" required>
<option value="">Seleziona una categoria</option>
<?php foreach ($categories as $category): ?>
<option value="<?php echo $category['id']; ?>"><?php echo htmlspecialchars($category['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="add_name" class="form-label">Nome</label>
<input type="text" class="form-control" id="add_name" name="name" required>
</div>
</div>
<div class="mb-3">
<label for="add_description" class="form-label">Descrizione</label>
<textarea class="form-control" id="add_description" name="description" rows="3"></textarea>
</div>
<div class="mb-3">
<label for="add_photo" class="form-label">Foto</label>
<input type="file" class="form-control" id="add_photo" name="photo" accept="image/*">
</div>
<div class="mb-3">
<label for="add_requirements" class="form-label">Requisiti</label>
<textarea class="form-control" id="add_requirements" name="requirements" rows="2"></textarea>
</div>
<div class="mb-3">
<label for="add_status" class="form-label">Stato</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="add_status" name="status" value="active" checked>
<label class="form-check-label" for="add_status">Attivo</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="submit" class="btn btn-primary">Aggiungi</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modale per modificare una classe -->
<div class="modal fade" id="editClassModal" tabindex="-1" aria-labelledby="editClassModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editClassModalLabel">Modifica Classe</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="POST" enctype="multipart/form-data">
<div class="modal-body">
<input type="hidden" name="action" value="edit">
<input type="hidden" name="id" id="edit_id">
<div class="row">
<div class="col-md-6 mb-3">
<label for="edit_category_id" class="form-label">Categoria</label>
<select class="form-control" id="edit_category_id" name="category_id" required>
<option value="">Seleziona una categoria</option>
<?php foreach ($categories as $category): ?>
<option value="<?php echo $category['id']; ?>"><?php echo htmlspecialchars($category['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="edit_name" class="form-label">Nome</label>
<input type="text" class="form-control" id="edit_name" name="name" required>
</div>
</div>
<div class="mb-3">
<label for="edit_description" class="form-label">Descrizione</label>
<textarea class="form-control" id="edit_description" name="description" rows="3"></textarea>
</div>
<div class="mb-3">
<label for="edit_photo" class="form-label">Foto</label>
<input type="file" class="form-control" id="edit_photo" name="photo" accept="image/*">
</div>
<div class="mb-3">
<label for="edit_requirements" class="form-label">Requisiti</label>
<textarea class="form-control" id="edit_requirements" name="requirements" rows="2"></textarea>
</div>
<div class="mb-3">
<label for="edit_status" class="form-label">Stato</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="edit_status" name="status" value="active">
<label class="form-check-label" for="edit_status">Attivo</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="submit" class="btn btn-primary">Salva Modifiche</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modale per assegnare un insegnante -->
<div class="modal fade" id="assignTeacherModal" tabindex="-1" aria-labelledby="assignTeacherModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="assignTeacherModalLabel">Assegna Insegnante</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="POST">
<div class="modal-body">
<input type="hidden" name="action" value="assign_teacher">
<input type="hidden" name="class_type_id" id="assign_class_type_id">
<div class="mb-3">
<label for="assign_teacher_id" class="form-label">Seleziona Insegnante</label>
<select class="form-control" id="assign_teacher_id" name="teacher_id">
<option value="">Nessun insegnante (Non assegnato)</option>
<?php foreach ($teachers as $teacher): ?>
<option value="<?php echo $teacher['id']; ?>">
<?php echo htmlspecialchars($teacher['first_name'] . ' ' . $teacher['last_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="submit" class="btn btn-primary">Assegna</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modale per propagare le sessioni -->
<div class="modal fade" id="propagateClassModal" tabindex="-1" aria-labelledby="propagateClassModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="propagateClassModalLabel">Propaga Sessioni</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="POST">
<div class="modal-body">
<input type="hidden" name="action" value="propagate_sessions">
<input type="hidden" name="class_type_id" id="propagate_class_type_id">
<div class="mb-3">
<label for="propagate_start_date" class="form-label">Data Inizio</label>
<input type="date" class="form-control" id="propagate_start_date" name="start_date" required>
</div>
<div class="mb-3">
<label for="propagate_end_date" class="form-label">Data Fine</label>
<input type="date" class="form-control" id="propagate_end_date" name="end_date" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="submit" class="btn btn-success">Propaga</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modale per rimuovere una propagazione -->
<div class="modal fade" id="removePropagationModal" tabindex="-1" aria-labelledby="removePropagationModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="removePropagationModalLabel">Rimuovi Propagazione</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="POST">
<div class="modal-body">
<input type="hidden" name="action" value="remove_propagation">
<input type="hidden" name="class_type_id" id="remove_propagation_class_type_id">
<div class="mb-3">
<label for="remove_propagation_id" class="form-label">ID Propagazione</label>
<input type="text" class="form-control" id="remove_propagation_id" name="propagation_id" required>
<small class="form-text text-muted">Inserisci l'ID della propagazione da rimuovere (lo trovi nel messaggio di successo dopo la propagazione).</small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="submit" class="btn btn-danger">Rimuovi</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modale per aggiungere una variazione -->
<div class="modal fade" id="addVariationModal" tabindex="-1" aria-labelledby="addVariationModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addVariationModalLabel">Aggiungi Variazione</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="POST" enctype="multipart/form-data">
<div class="modal-body">
<input type="hidden" name="action" value="add_variation">
<input type="hidden" name="class_id" id="add_variation_class_id">
<div class="row">
<div class="col-md-4 mb-3">
<label for="add_variation_level" class="form-label">Livello</label>
<select class="form-control" id="add_variation_level" name="level" required>
<option value="beginner">Beginner</option>
<option value="intermediate">Intermediate</option>
<option value="advanced">Advanced</option>
</select>
</div>
<div class="col-md-4 mb-3">
<label for="add_variation_typical_duration" class="form-label">Durata Tipica (min)</label>
<input type="number" class="form-control" id="add_variation_typical_duration" name="typical_duration">
</div>
<div class="col-md-4 mb-3">
<label for="add_variation_max_capacity" class="form-label">Posti Massimi</label>
<input type="number" class="form-control" id="add_variation_max_capacity" name="max_capacity" min="0" required>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="add_variation_day_of_week" class="form-label">Giorno della Settimana</label>
<select class="form-control" id="add_variation_day_of_week" name="day_of_week" required>
<option value="">Seleziona un giorno</option>
<option value="monday">Lunedì</option>
<option value="tuesday">Martedì</option>
<option value="wednesday">Mercoledì</option>
<option value="thursday">Giovedì</option>
<option value="friday">Venerdì</option>
<option value="saturday">Sabato</option>
<option value="sunday">Domenica</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="add_variation_start_time" class="form-label">Orario di Inizio</label>
<input type="time" class="form-control" id="add_variation_start_time" name="start_time" required>
</div>
</div>
<div class="mb-3">
<label for="add_variation_room_name" class="form-label">Sala</label>
<input type="text" class="form-control" id="add_variation_room_name" name="room_name">
</div>
<div class="mb-3">
<label for="add_variation_notes" class="form-label">Note</label>
<textarea class="form-control" id="add_variation_notes" name="notes" rows="2"></textarea>
</div>
<div class="mb-3">
<label for="add_variation_photo" class="form-label">Foto (opzionale)</label>
<input type="file" class="form-control" id="add_variation_photo" name="photo" accept="image/*">
</div>
<div class="mb-3">
<label for="add_variation_status" class="form-label">Stato</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="add_variation_status" name="status" value="active" checked>
<label class="form-check-label" for="add_variation_status">Attivo</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="submit" class="btn btn-primary">Aggiungi</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modale per modificare una variazione -->
<div class="modal fade" id="editVariationModal" tabindex="-1" aria-labelledby="editVariationModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editVariationModalLabel">Modifica Variazione</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="POST" enctype="multipart/form-data">
<div class="modal-body">
<input type="hidden" name="action" value="edit_variation">
<input type="hidden" name="id" id="edit_variation_id">
<input type="hidden" name="class_id" id="edit_variation_class_id">
<div class="row">
<div class="col-md-4 mb-3">
<label for="edit_variation_level" class="form-label">Livello</label>
<select class="form-control" id="edit_variation_level" name="level" required>
<option value="beginner">Beginner</option>
<option value="intermediate">Intermediate</option>
<option value="advanced">Advanced</option>
</select>
</div>
<div class="col-md-4 mb-3">
<label for="edit_variation_typical_duration" class="form-label">Durata Tipica (min)</label>
<input type="number" class="form-control" id="edit_variation_typical_duration" name="typical_duration">
</div>
<div class="col-md-4 mb-3">
<label for="edit_variation_max_capacity" class="form-label">Posti Massimi</label>
<input type="number" class="form-control" id="edit_variation_max_capacity" name="max_capacity" min="0" required>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="edit_variation_day_of_week" class="form-label">Giorno della Settimana</label>
<select class="form-control" id="edit_variation_day_of_week" name="day_of_week" required>
<option value="">Seleziona un giorno</option>
<option value="monday">Lunedì</option>
<option value="tuesday">Martedì</option>
<option value="wednesday">Mercoledì</option>
<option value="thursday">Giovedì</option>
<option value="friday">Venerdì</option>
<option value="saturday">Sabato</option>
<option value="sunday">Domenica</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="edit_variation_start_time" class="form-label">Orario di Inizio</label>
<input type="time" class="form-control" id="edit_variation_start_time" name="start_time" required>
</div>
</div>
<div class="mb-3">
<label for="edit_variation_room_name" class="form-label">Sala</label>
<input type="text" class="form-control" id="edit_variation_room_name" name="room_name">
</div>
<div class="mb-3">
<label for="edit_variation_notes" class="form-label">Note</label>
<textarea class="form-control" id="edit_variation_notes" name="notes" rows="2"></textarea>
</div>
<div class="mb-3">
<label for="edit_variation_photo" class="form-label">Foto (opzionale)</label>
<input type="file" class="form-control" id="edit_variation_photo" name="photo" accept="image/*">
</div>
<div class="mb-3">
<label for="edit_variation_status" class="form-label">Stato</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="edit_variation_status" name="status" value="active">
<label class="form-check-label" for="edit_variation_status">Attivo</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="submit" class="btn btn-primary">Salva Modifiche</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modale per modificare una sessione -->
<div class="modal fade" id="editSessionModal" tabindex="-1" aria-labelledby="editSessionModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editSessionModalLabel">Modifica Sessione</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="POST">
<div class="modal-body">
<input type="hidden" name="action" value="edit_session">
<input type="hidden" name="id" id="edit_session_id">
<input type="hidden" name="class_type_id" id="edit_session_class_type_id">
<div class="mb-3">
<label for="edit_session_date" class="form-label">Data</label>
<input type="date" class="form-control" id="edit_session_date" name="session_date" required>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="edit_session_start_time" class="form-label">Orario di Inizio</label>
<input type="time" class="form-control" id="edit_session_start_time" name="start_time" required>
</div>
<div class="col-md-6 mb-3">
<label for="edit_session_end_time" class="form-label">Orario di Fine</label>
<input type="time" class="form-control" id="edit_session_end_time" name="end_time" required>
</div>
</div>
<div class="mb-3">
<label for="edit_session_teacher_id" class="form-label">Insegnante</label>
<select class="form-control" id="edit_session_teacher_id" name="teacher_id">
<option value="">Nessun insegnante (Non assegnato)</option>
<?php foreach ($teachers as $teacher): ?>
<option value="<?php echo $teacher['id']; ?>">
<?php echo htmlspecialchars($teacher['first_name'] . ' ' . $teacher['last_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label for="edit_session_status" class="form-label">Stato</label>
<select class="form-control" id="edit_session_status" name="status" required>
<option value="scheduled">Programmata</option>
<option value="completed">Completata</option>
<option value="cancelled">Annullata</option>
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="submit" class="btn btn-primary">Salva Modifiche</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modale per il messaggio di successo della propagazione -->
<div class="modal fade" id="successPropagationModal" tabindex="-1" aria-labelledby="successPropagationModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="successPropagationModalLabel">Propagazione Completata</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p id="successPropagationMessage"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Chiudi</button>
</div>
</div>
</div>
</div>
<div class="overlay toggle-icon"></div>
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<!-- Script per inizializzare DataTables e gestire i modali -->
<script>
$(document).ready(function() {
$('#classesTable').DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.10.25/i18n/Italian.json"
},
"ordering": false // Disabilita l'ordinamento per gestire i collapse
});
$('#dailySessionsTable').DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.10.25/i18n/Italian.json"
},
"pageLength": 5,
"lengthMenu": [5, 10, 25, 50]
});
});
function fillEditModal(data) {
document.getElementById('edit_id').value = data.id;
document.getElementById('edit_category_id').value = data.category_id;
document.getElementById('edit_name').value = data.name;
document.getElementById('edit_description').value = data.description;
document.getElementById('edit_requirements').value = data.requirements;
document.getElementById('edit_status').checked = (data.status === 'active');
}
function fillAddVariationModal(data) {
document.getElementById('add_variation_class_id').value = data.class_id;
}
function fillEditVariationModal(data) {
document.getElementById('edit_variation_id').value = data.id;
document.getElementById('edit_variation_class_id').value = data.class_id;
document.getElementById('edit_variation_level').value = data.level;
document.getElementById('edit_variation_typical_duration').value = data.typical_duration;
document.getElementById('edit_variation_max_capacity').value = data.max_capacity;
document.getElementById('edit_variation_day_of_week').value = data.day_of_week;
document.getElementById('edit_variation_start_time').value = data.start_time;
document.getElementById('edit_variation_room_name').value = data.room_name;
document.getElementById('edit_variation_notes').value = data.notes;
document.getElementById('edit_variation_status').checked = (data.status === 'active');
}
function fillAssignTeacherModal(data) {
document.getElementById('assign_class_type_id').value = data.class_type_id;
document.getElementById('assign_teacher_id').value = data.teacher_id || '';
}
function fillPropagateModal(data) {
document.getElementById('propagate_class_type_id').value = data.class_type_id;
}
function fillRemovePropagationModal(data) {
document.getElementById('remove_propagation_class_type_id').value = data.class_type_id;
}
function fillEditSessionModal(data) {
document.getElementById('edit_session_id').value = data.id;
document.getElementById('edit_session_class_type_id').value = data.class_type_id;
document.getElementById('edit_session_date').value = data.session_date;
document.getElementById('edit_session_start_time').value = data.start_time;
document.getElementById('edit_session_end_time').value = data.end_time;
document.getElementById('edit_session_teacher_id').value = data.teacher_id || '';
document.getElementById('edit_session_status').value = data.status;
}
</script>
<!-- MODALE CALENDARIO (GRANDE MA NON FULLSCREEN + FIXATO) -->
<div class="modal fade" id="calendarModal" tabindex="-1" aria-labelledby="calendarModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-scrollable" style="max-width: 95vw;">
<div class="modal-content" style="height: 95vh;">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" id="calendarModalLabel">
Calendario Lezioni
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-0 d-flex flex-column" style="height: 100%;">
<div id="fullcalendar-modal" class="flex-grow-1"></div>
</div>
</div>
</div>
</div>
<!-- FullCalendar CDN -->
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/main.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/main.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/locales/it.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
let calendar = null;
const modalElement = document.getElementById('calendarModal');
const calendarEl = document.getElementById('fullcalendar-modal');
// Funzione per inizializzare o aggiornare il calendario
function initCalendar() {
if (calendar) {
calendar.destroy();
}
calendar = new FullCalendar.Calendar(calendarEl, {
locale: 'it',
initialView: 'timeGridWeek',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek'
},
buttonText: {
today: 'Oggi',
month: 'Mese',
week: 'Settimana'
},
height: '100%',
slotMinTime: '06:00:00',
slotMaxTime: '23:00:00',
events: [
<?php
$from = date('Y-m-d');
$to = date('Y-m-d', strtotime('+90 days'));
$stmt = $pdo->prepare("
SELECT cs.session_date, cs.start_time, cs.end_time, cs.status,
c.name AS class_name, ct.level, ct.room_name,
t.first_name, t.last_name
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 teachers t ON cs.teacher_id = t.id
WHERE cs.session_date BETWEEN ? AND ?
AND c.school_id = ?
");
$stmt->execute([$from, $to, $school_id]);
foreach ($stmt->fetchAll() as $e) {
$title = $e['class_name'];
if ($e['level']) $title .= ' - ' . ucfirst($e['level']);
if ($e['first_name']) $title .= ' (' . $e['first_name'] . ')';
if ($e['room_name']) $title .= ' | ' . $e['room_name'];
$color = '#0d6efd';
if ($e['status'] === 'completed') $color = '#198754';
if ($e['status'] === 'cancelled') $color = '#dc3545';
echo "{
title: '" . addslashes($title) . "',
start: '{$e['session_date']}T{$e['start_time']}',
end: '{$e['session_date']}T{$e['end_time']}',
color: '$color'
}, ";
}
?>
],
eventClick: function(info) {
const date = info.event.start.toISOString().split('T')[0];
window.location.href = '?start_date=' + date + '&end_date=' + date;
}
});
calendar.render();
}
// Apri il modale → inizializza e forza resize
modalElement.addEventListener('shown.bs.modal', function() {
initCalendar();
setTimeout(() => calendar.updateSize(), 100);
});
// Se chiudi e riapri, ricarica
modalElement.addEventListener('hidden.bs.modal', function() {
if (calendar) {
calendar.destroy();
calendar = null;
}
});
});
</script>
<style>
#fullcalendar-modal .fc-header-toolbar {
margin-bottom: 15px;
}
#fullcalendar-modal .fc-button {
border-radius: 6px !important;
}
#fullcalendar-modal .fc-event {
border: none;
border-radius: 6px;
padding: 3px 6px;
font-size: 0.9em;
white-space: normal;
}
</style>
<?php foreach ($range_sessions as $session): ?>
<?php if ($session['booked_count'] > 0): ?>
<div class="modal fade" id="studentsModal-<?php echo $session['id']; ?>" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title">
Prenotati - <?php echo htmlspecialchars($session['class_name']); ?>
<?php echo ucfirst($session['level']); ?>
del <?php echo date('d/m/Y', strtotime($session['session_date'])); ?>
ore <?php echo substr($session['start_time'], 0, 5); ?>
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-sm table-hover">
<thead class="table-light">
<tr>
<th>Nome</th>
<th>Email</th>
<th>Telefono</th>
<th>Stato</th>
</tr>
</thead>
<tbody>
<?php
$students = explode(';;;', $session['booked_students'] ?? '');
foreach ($students as $s):
if (empty(trim($s))) continue;
list($name, $email, $phone) = explode('|', $s . '||');
?>
<tr>
<td><strong><?php echo htmlspecialchars($name); ?></strong></td>
<td><?php echo htmlspecialchars($email); ?></td>
<td><?php echo htmlspecialchars($phone ?: '—'); ?></td>
<td><span class="badge bg-success">Prenotato</span></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
</div>
</div>
</div>
</div>
<?php endif;
endforeach; ?>
</body>
</html>