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