added cancellation rules and page
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class CreateBookingclassCancellations extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change(): void
|
||||
{
|
||||
// Storico delle lezioni cancellate dagli allievi.
|
||||
// Nessuna pagina esistente legge questa tabella: non cambia il resto del sistema.
|
||||
$this->table('bookingclass_cancellations', ['id' => 'idcancellation'])
|
||||
->addColumn('idbookingclass', 'integer')
|
||||
->addColumn('idserviceschedule', 'integer', ['null' => true])
|
||||
->addColumn('bookingstart', 'datetime')
|
||||
->addColumn('status', 'string', ['limit' => 30])
|
||||
->addColumn('idservice', 'integer')
|
||||
->addColumn('iduser', 'integer', ['signed' => false])
|
||||
->addColumn('idorder', 'integer', ['null' => true])
|
||||
->addColumn('prevbookingstart', 'datetime', ['null' => true])
|
||||
->addColumn('is_reprogrammed', 'char', ['limit' => 1, 'default' => 'N'])
|
||||
->addColumn('is_gift', 'char', ['limit' => 1, 'default' => 'N'])
|
||||
->addColumn('booking_created_at', 'timestamp', ['null' => true])
|
||||
->addColumn('cancelled_at', 'datetime')
|
||||
->addColumn('cancelled_by', 'integer', ['signed' => false])
|
||||
->addColumn('reprogrammed_incremented', 'char', ['limit' => 1, 'default' => 'N'])
|
||||
->addColumn('idschool', 'integer', ['signed' => false, 'default' => 1])
|
||||
->addIndex(['iduser'])
|
||||
->addIndex(['idorder'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
require_once('include/headscript.php');
|
||||
|
||||
/**
|
||||
* Storico delle lezioni cancellate dagli allievi (tabella bookingclass_cancellations).
|
||||
* Sola consultazione: questa pagina non modifica nessun dato.
|
||||
*/
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
function e($value): string
|
||||
{
|
||||
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
// Preavviso leggibile: minuti, ore o giorni
|
||||
function formatPreavviso(?int $minutes): string
|
||||
{
|
||||
if ($minutes === null) return '-';
|
||||
if ($minutes < 60) return $minutes . ' min';
|
||||
if ($minutes < 48 * 60) return floor($minutes / 60) . ' ore';
|
||||
return floor($minutes / 1440) . ' giorni';
|
||||
}
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
c.idcancellation,
|
||||
c.iduser,
|
||||
c.idorder,
|
||||
c.is_gift,
|
||||
c.reprogrammed_incremented,
|
||||
c.cancelled_at,
|
||||
COALESCE(ss.dateschedule, c.bookingstart) AS lesson_date,
|
||||
TIMESTAMPDIFF(MINUTE, c.cancelled_at, COALESCE(ss.dateschedule, c.bookingstart)) AS preavviso_min,
|
||||
u.first_name,
|
||||
u.last_name,
|
||||
u.email,
|
||||
s.servicename,
|
||||
o.reprogrammed,
|
||||
o.maxreschedule
|
||||
FROM bookingclass_cancellations c
|
||||
LEFT JOIN auth_users u ON u.id = c.iduser
|
||||
LEFT JOIN service s ON s.idservice = c.idservice
|
||||
LEFT JOIN serviceschedule ss ON ss.idserviceschedule = c.idserviceschedule
|
||||
LEFT JOIN orderbook o ON o.idorderbook = c.idorder
|
||||
ORDER BY c.cancelled_at DESC";
|
||||
|
||||
$rows = $pdo->query($sql)->fetchAll();
|
||||
|
||||
// Contatori ultimi 7 / 30 giorni
|
||||
$limit7 = strtotime('-7 days');
|
||||
$limit30 = strtotime('-30 days');
|
||||
$count7 = 0;
|
||||
$count30 = 0;
|
||||
foreach ($rows as $r) {
|
||||
$t = strtotime($r['cancelled_at']);
|
||||
if ($t >= $limit7) $count7++;
|
||||
if ($t >= $limit30) $count30++;
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="it">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>YogiBook - Cancellazioni</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta content="YogiBook" name="description" />
|
||||
<meta content="Advanced Creative Solutions" name="author" />
|
||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
||||
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css">
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
||||
|
||||
<style>
|
||||
.admin-card {
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.admin-card .card-body {
|
||||
padding: 26px 30px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: #6b7280;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.section-lead {
|
||||
color: #9ca3af;
|
||||
font-size: 14px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.counter {
|
||||
border-radius: 8px;
|
||||
padding: 8px 14px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
background: #fbe4c4;
|
||||
color: #8a5a1a;
|
||||
}
|
||||
|
||||
.counter.counter-30 {
|
||||
background: #c4e1fb;
|
||||
color: #1a4f7a;
|
||||
}
|
||||
|
||||
#cancTable thead th {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
#cancTable td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.user-email {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.badge-soft {
|
||||
display: inline-block;
|
||||
border-radius: 6px;
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.badge-late {
|
||||
background: #fbc7c4;
|
||||
color: #a12820;
|
||||
}
|
||||
|
||||
.badge-ok {
|
||||
background: #cdfbc4;
|
||||
color: #1a7f2e;
|
||||
}
|
||||
|
||||
.badge-gift {
|
||||
background: #e2d3f5;
|
||||
color: #4c2c92;
|
||||
}
|
||||
|
||||
.badge-neutral {
|
||||
background: #eef0f3;
|
||||
color: #4b5563;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="layout-wrapper">
|
||||
<header id="page-topbar" class="isvertical-topbar">
|
||||
<div class="navbar-header">
|
||||
<div class="d-flex">
|
||||
<?php include('include/logoarea.php'); ?>
|
||||
<button type="button" class="btn btn-sm px-3 font-size-24 header-item waves-effect vertical-menu-btn">
|
||||
<i class="bx bx-menu align-middle"></i>
|
||||
</button>
|
||||
<div class="page-title-box align-self-center d-none d-md-block">
|
||||
<h4 class="page-title mb-0">Cancellazioni</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<?php include('include/languageselection.php'); ?>
|
||||
<?php include('include/profiletopbar.php'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<?php include('include/sidebar.php'); ?>
|
||||
<header class="ishorizontal-topbar">
|
||||
<div class="navbar-header">
|
||||
<div class="d-flex"></div>
|
||||
</div>
|
||||
<div class="topnav">
|
||||
<div class="container-fluid">
|
||||
<nav class="navbar navbar-light navbar-expand-lg topnav-menu"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="page-content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card admin-card">
|
||||
<div class="card-body">
|
||||
<div class="section-title">Lezioni cancellate dagli allievi</div>
|
||||
<p class="section-lead">Storico delle cancellazioni, dalla più recente. Usa la ricerca per filtrare per nome, lezione o data.</p>
|
||||
|
||||
<div class="d-flex align-items-center gap-3 flex-wrap mb-3">
|
||||
<span class="counter"><i class="fas fa-calendar-week me-1"></i> Ultimi 7 giorni: <strong><?php echo $count7; ?></strong></span>
|
||||
<span class="counter counter-30"><i class="fas fa-calendar-alt me-1"></i> Ultimi 30 giorni: <strong><?php echo $count30; ?></strong></span>
|
||||
<span class="counter badge-neutral"><i class="fas fa-list me-1"></i> Totale: <strong><?php echo count($rows); ?></strong></span>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="cancTable" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Allievo</th>
|
||||
<th>Lezione</th>
|
||||
<th>Data lezione</th>
|
||||
<th>Cancellata il</th>
|
||||
<th>Preavviso</th>
|
||||
<th>Ordine</th>
|
||||
<th>Conta come riprog.</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r) :
|
||||
$nome = trim(($r['first_name'] ?? '') . ' ' . ($r['last_name'] ?? ''));
|
||||
if ($nome === '') $nome = 'Utente #' . (int) $r['iduser'];
|
||||
$lessonTs = $r['lesson_date'] ? strtotime($r['lesson_date']) : null;
|
||||
$cancTs = strtotime($r['cancelled_at']);
|
||||
$preMin = $r['preavviso_min'] !== null ? (int) $r['preavviso_min'] : null;
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php echo e($nome); ?>
|
||||
<?php if (!empty($r['email'])) : ?>
|
||||
<span class="user-email"><?php echo e($r['email']); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo e($r['servicename'] ?? '-'); ?></td>
|
||||
<td data-order="<?php echo $lessonTs ? date('Y-m-d H:i', $lessonTs) : ''; ?>">
|
||||
<?php echo $lessonTs ? e(date('d/m/Y H:i', $lessonTs)) : '-'; ?>
|
||||
</td>
|
||||
<td data-order="<?php echo e(date('Y-m-d H:i:s', $cancTs)); ?>">
|
||||
<?php echo e(date('d/m/Y H:i', $cancTs)); ?>
|
||||
</td>
|
||||
<td data-order="<?php echo $preMin ?? 0; ?>">
|
||||
<?php if ($preMin !== null && $preMin < 24 * 60) : ?>
|
||||
<span class="badge-soft badge-late"><?php echo e(formatPreavviso($preMin)); ?></span>
|
||||
<?php else : ?>
|
||||
<span class="badge-soft badge-ok"><?php echo e(formatPreavviso($preMin)); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo $r['idorder'] !== null ? '#' . (int) $r['idorder'] : '-'; ?></td>
|
||||
<td>
|
||||
<?php if ($r['is_gift'] === 'Y' || $r['idorder'] === null) : ?>
|
||||
<span class="badge-soft badge-gift">Omaggio</span>
|
||||
<?php elseif ($r['reprogrammed_incremented'] === 'Y') : ?>
|
||||
<span class="badge-soft badge-neutral">
|
||||
Sì<?php if ($r['reprogrammed'] !== null) : ?> (<?php echo (int) $r['reprogrammed']; ?>/<?php echo (int) $r['maxreschedule']; ?>)<?php endif; ?>
|
||||
</span>
|
||||
<?php else : ?>
|
||||
<span class="badge-soft badge-neutral">No</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include('include/footer.php'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/libs/metismenujs/metismenujs.min.js"></script>
|
||||
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
||||
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
||||
<script src="assets/js/app.js"></script>
|
||||
|
||||
<script>
|
||||
$('#cancTable').DataTable({
|
||||
paging: true,
|
||||
pageLength: 50,
|
||||
searching: true,
|
||||
ordering: true,
|
||||
order: [
|
||||
[3, 'desc']
|
||||
],
|
||||
language: {
|
||||
url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json"
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+109
-8
@@ -51,6 +51,9 @@ $userName = trim(($u['first_name'] ?? '') . ' ' . ($u['last_name'] ?? ''));
|
||||
$stmt = $conn->prepare("
|
||||
SELECT
|
||||
bc.idbookingclass,
|
||||
bc.idorder,
|
||||
bc.status,
|
||||
bc.bookingstart,
|
||||
s.servicename,
|
||||
ss.dateschedule
|
||||
FROM bookingclass bc
|
||||
@@ -77,18 +80,116 @@ $classDateTxt = $classDateRaw ? date("d-m-Y H:i", strtotime($classDateRaw)) : '
|
||||
$cancelDateTxt = date("d-m-Y H:i");
|
||||
|
||||
/***********************
|
||||
* 3) DELETE (safe)
|
||||
* 3) CONTROLLI (stesse regole di userpanel.php)
|
||||
***********************/
|
||||
$stmt = $conn->prepare("DELETE FROM bookingclass WHERE idbookingclass = ? AND iduser = ?");
|
||||
$stmt->bind_param("ii", $id, $userId);
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
$err = $stmt->error;
|
||||
$stmt->close();
|
||||
die("Errore durante la cancellazione del record: " . htmlspecialchars($err));
|
||||
// Solo prenotazioni confermate: pending e lista d'attesa hanno i loro percorsi
|
||||
if (($bk['status'] ?? '') !== 'booked') {
|
||||
header("Location: userpanel.php?deleted=0&err=status");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Finestra oraria
|
||||
$classTime = new DateTime($classDateRaw ?: $bk['bookingstart']);
|
||||
$currentTime = new DateTime();
|
||||
|
||||
// Lezione già iniziata o passata: non si cancella
|
||||
if ($classTime <= $currentTime) {
|
||||
header("Location: userpanel.php?deleted=0&err=window");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Lezione di oggi: fino alle 17:00 entro le 00:01, dopo le 17:00 entro le 12:00
|
||||
if ($classTime->format('Y-m-d') === $currentTime->format('Y-m-d')) {
|
||||
$classHour = (int) $classTime->format('H');
|
||||
$classMinute = (int) $classTime->format('i');
|
||||
$isBefore1700 = ($classHour < 17) || ($classHour === 17 && $classMinute === 0);
|
||||
$deadline = new DateTime($classTime->format($isBefore1700 ? 'Y-m-d 00:01:00' : 'Y-m-d 12:00:00'));
|
||||
if ($currentTime > $deadline) {
|
||||
header("Location: userpanel.php?deleted=0&err=window");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/***********************
|
||||
* 3b) STORICO + RIPROGRAMMAZIONE + CANCELLAZIONE
|
||||
* Tutto in una transazione: o riesce tutto o niente.
|
||||
***********************/
|
||||
$idOrder = $bk['idorder'] !== null ? (int) $bk['idorder'] : null;
|
||||
$ord = null;
|
||||
$incremented = 'N';
|
||||
|
||||
try {
|
||||
$conn->begin_transaction();
|
||||
|
||||
// Limite riprogrammazioni (stessa regola del pulsante Riprogramma).
|
||||
// FOR UPDATE: blocca la riga dell'ordine contro doppi click.
|
||||
if ($idOrder !== null) {
|
||||
$stmt = $conn->prepare("SELECT reprogrammed, maxreschedule FROM orderbook WHERE idorderbook = ? FOR UPDATE");
|
||||
$stmt->bind_param("i", $idOrder);
|
||||
$stmt->execute();
|
||||
$ord = $stmt->get_result()->fetch_assoc();
|
||||
$stmt->close();
|
||||
|
||||
if ($ord) {
|
||||
if ((int) $ord['reprogrammed'] >= (int) $ord['maxreschedule']) {
|
||||
throw new RuntimeException('limit');
|
||||
}
|
||||
$incremented = 'Y';
|
||||
}
|
||||
}
|
||||
|
||||
// Copia nello storico (prima di eliminare)
|
||||
$stmt = $conn->prepare("
|
||||
INSERT INTO bookingclass_cancellations
|
||||
(idbookingclass, idserviceschedule, bookingstart, status, idservice, iduser, idorder,
|
||||
prevbookingstart, is_reprogrammed, is_gift, booking_created_at,
|
||||
cancelled_at, cancelled_by, reprogrammed_incremented)
|
||||
SELECT idbookingclass, idserviceschedule, bookingstart, status, idservice, iduser, idorder,
|
||||
prevbookingstart, is_reprogrammed, is_gift, created_at,
|
||||
NOW(), ?, ?
|
||||
FROM bookingclass
|
||||
WHERE idbookingclass = ? AND iduser = ?
|
||||
");
|
||||
$stmt->bind_param("isii", $userId, $incremented, $id, $userId);
|
||||
$stmt->execute();
|
||||
$copied = $stmt->affected_rows;
|
||||
$stmt->close();
|
||||
if ($copied !== 1) {
|
||||
throw new RuntimeException('notfound');
|
||||
}
|
||||
|
||||
// La cancellazione conta come una riprogrammazione
|
||||
if ($incremented === 'Y') {
|
||||
$stmt = $conn->prepare("UPDATE orderbook SET reprogrammed = reprogrammed + 1 WHERE idorderbook = ?");
|
||||
$stmt->bind_param("i", $idOrder);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
// Eliminazione della prenotazione
|
||||
$stmt = $conn->prepare("DELETE FROM bookingclass WHERE idbookingclass = ? AND iduser = ?");
|
||||
$stmt->bind_param("ii", $id, $userId);
|
||||
$stmt->execute();
|
||||
$deleted = $stmt->affected_rows;
|
||||
$stmt->close();
|
||||
if ($deleted !== 1) {
|
||||
throw new RuntimeException('notfound');
|
||||
}
|
||||
|
||||
$conn->commit();
|
||||
} catch (Throwable $e) {
|
||||
try {
|
||||
$conn->rollback();
|
||||
} catch (Throwable $ignored) {
|
||||
}
|
||||
|
||||
$code = in_array($e->getMessage(), ['limit', 'notfound'], true) ? $e->getMessage() : 'db';
|
||||
if ($code === 'db') {
|
||||
error_log("delete_lesson #{$id} utente #{$userId}: " . $e->getMessage());
|
||||
}
|
||||
header("Location: userpanel.php?deleted=0&err=" . $code);
|
||||
exit();
|
||||
}
|
||||
// Connessione $bkngstm gestita globalmente: non la chiudiamo qui
|
||||
|
||||
/***********************
|
||||
|
||||
@@ -178,6 +178,12 @@
|
||||
<span class="menu-item">Utenti DB</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="cancellazioni.php" class="">
|
||||
<i class="bx bx-slider-alt icon nav-icon"></i>
|
||||
<span class="menu-item">Cancellazioni</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Template (demo) -->
|
||||
<li class="menu-title" data-key="t-applications">Template</li>
|
||||
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
[2026-02-18 13:43:57] ERROR sending. booking_id=29 user_id=2 to=info@claudiosironi.com :: SMTP Error: Could not connect to SMTP host. Failed to connect to server
|
||||
[2026-02-18 13:46:10] ERROR sending. booking_id=30 user_id=2 to=info@claudiosironi.com :: SMTP Error: Could not connect to SMTP host. Failed to connect to server
|
||||
[2026-10-14 08:44:28] SMTP in uso host=mail.yogasoul.it porta=465 enc=ssl user=info@yogasoul.it
|
||||
[2026-10-14 08:44:30] OK inviata. booking_id=70 user_id=2 to=info@claudiosironi.com lezione='Aerial Yoga - base' prevista='21-10-2026 18:30' cancellata='14-10-2026 08:44'
|
||||
[2026-10-14 08:46:52] SMTP in uso host=mail.yogasoul.it porta=465 enc=ssl user=info@yogasoul.it
|
||||
[2026-10-14 08:46:54] OK inviata. booking_id=60 user_id=2 to=info@claudiosironi.com lezione='Aerial Yoga - base' prevista='29-10-2026 20:15' cancellata='14-10-2026 08:46'
|
||||
|
||||
+17
-1
@@ -504,6 +504,7 @@ $italianMonths = [
|
||||
html: `
|
||||
<strong>Confermi di voler cancellare questa lezione?</strong><br><br>
|
||||
<strong>RICORDA:</strong> dovrai riprogrammarla entro la scadenza del tuo abbonamento per non perderla!<br><br>
|
||||
La cancellazione conta come <strong>una delle riprogrammazioni</strong> disponibili per il tuo pacchetto.<br><br>
|
||||
<span style="font-size:20px;color:#d33;font-weight:bold;">
|
||||
Scadenza: ${expirydate}
|
||||
</span>
|
||||
@@ -651,7 +652,22 @@ $italianMonths = [
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php if (isset($_GET['deleted'])) { ?>
|
||||
<?php if (($_GET['deleted'] ?? '') === '0') {
|
||||
$cancelErrors = [
|
||||
'window' => 'Non è più possibile cancellare questa lezione: il tempo per la cancellazione è scaduto.',
|
||||
'limit' => 'Hai raggiunto il numero massimo di riprogrammazioni per questo pacchetto.',
|
||||
'status' => 'Questa prenotazione non può essere cancellata da qui.',
|
||||
'notfound' => 'Prenotazione non trovata.',
|
||||
];
|
||||
$cancelMsg = $cancelErrors[$_GET['err'] ?? ''] ?? 'Si è verificato un errore: la lezione non è stata cancellata. Riprova o contattaci.';
|
||||
?>
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<i class="fas fa-ban me-2"></i>
|
||||
<?php echo e($cancelMsg); ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php if (($_GET['deleted'] ?? '') === '1') { ?>
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<i class="mdi mdi-check-all me-2"></i>
|
||||
Lezione cancellata con successo! Grazie per aver liberato il posto!
|
||||
|
||||
Reference in New Issue
Block a user