1969 lines
116 KiB
PHP
1969 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 = ?
|
|
");
|
|
$stmt->execute([$iduserlogin]);
|
|
$school = $stmt->fetch();
|
|
if (!$school) {
|
|
die("Errore: Nessuna scuola trovata per l'utente loggato.");
|
|
}
|
|
$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
|
|
$stmt = $pdo->prepare("SELECT id, first_name, last_name FROM teachers WHERE user_id = ? AND status = 'active' ORDER BY first_name, last_name");
|
|
$stmt->execute([$iduserlogin]);
|
|
$teachers = $stmt->fetchAll();
|
|
|
|
// 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="#" 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>
|