branch waiting list with update
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class AddWaitingListSupport extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function change(): void
|
||||||
|
{
|
||||||
|
$table = $this->table('bookingclass');
|
||||||
|
$table
|
||||||
|
->addColumn('created_at', 'timestamp', [
|
||||||
|
'default' => 'CURRENT_TIMESTAMP',
|
||||||
|
'null' => false,
|
||||||
|
'after' => 'cancellation_token',
|
||||||
|
])
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class AddWaitingListEnabledToOption extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function change(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->addColumn('waitinglist_enabled', 'char', [
|
||||||
|
'limit' => 1,
|
||||||
|
'default' => 'N',
|
||||||
|
'null' => false,
|
||||||
|
'after' => 'maxbeforetimecancell',
|
||||||
|
])
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
-2
@@ -74,8 +74,8 @@ if (!empty($scheduleIds)) {
|
|||||||
FROM bookingclass
|
FROM bookingclass
|
||||||
LEFT JOIN auth_users ON bookingclass.iduser = auth_users.id
|
LEFT JOIN auth_users ON bookingclass.iduser = auth_users.id
|
||||||
WHERE bookingclass.idserviceschedule IN ($ph)
|
WHERE bookingclass.idserviceschedule IN ($ph)
|
||||||
AND bookingclass.status IN ('booked', 'pending')
|
AND bookingclass.status IN ('booked', 'pending', 'waiting')
|
||||||
ORDER BY auth_users.last_name, auth_users.first_name";
|
ORDER BY bookingclass.created_at, auth_users.last_name, auth_users.first_name";
|
||||||
$stmtBookings = $pdo->prepare($sqlBookings);
|
$stmtBookings = $pdo->prepare($sqlBookings);
|
||||||
$stmtBookings->execute(array_values($scheduleIds));
|
$stmtBookings->execute(array_values($scheduleIds));
|
||||||
foreach ($stmtBookings->fetchAll() as $b) {
|
foreach ($stmtBookings->fetchAll() as $b) {
|
||||||
@@ -575,8 +575,10 @@ $italianMonths = [
|
|||||||
// separa confermati (booked) da in attesa (pending)
|
// separa confermati (booked) da in attesa (pending)
|
||||||
$bookings = array_filter($allRows, fn($b) => $b['status'] === 'booked');
|
$bookings = array_filter($allRows, fn($b) => $b['status'] === 'booked');
|
||||||
$pendings = array_filter($allRows, fn($b) => $b['status'] === 'pending');
|
$pendings = array_filter($allRows, fn($b) => $b['status'] === 'pending');
|
||||||
|
$waitings = array_filter($allRows, fn($b) => $b['status'] === 'waiting');
|
||||||
$countPersons = count($bookings); // contatore = solo confermati
|
$countPersons = count($bookings); // contatore = solo confermati
|
||||||
$countPending = count($pendings);
|
$countPending = count($pendings);
|
||||||
|
$countWaiting = count($waitings);
|
||||||
$maxcap = (int) $sch['maxcapacity'];
|
$maxcap = (int) $sch['maxcapacity'];
|
||||||
$isFull = $maxcap > 0 && $countPersons >= $maxcap;
|
$isFull = $maxcap > 0 && $countPersons >= $maxcap;
|
||||||
$colorclass = $sch['colorclass'] ?: '#e6f3ff';
|
$colorclass = $sch['colorclass'] ?: '#e6f3ff';
|
||||||
@@ -599,6 +601,12 @@ $italianMonths = [
|
|||||||
<?php echo $countPending; ?> in attesa
|
<?php echo $countPending; ?> in attesa
|
||||||
</span>
|
</span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if ($countWaiting > 0) : ?>
|
||||||
|
<span class="capacity-pill" style="background:#fbeef3;color:#d1698a;">
|
||||||
|
<i class="fas fa-list-ol" style="font-size:11px;"></i>
|
||||||
|
<?php echo $countWaiting; ?> in coda
|
||||||
|
</span>
|
||||||
|
<?php endif; ?>
|
||||||
</h3>
|
</h3>
|
||||||
<p class="class-meta"><i class="far fa-clock me-1"></i><?php echo e($whenFmt); ?></p>
|
<p class="class-meta"><i class="far fa-clock me-1"></i><?php echo e($whenFmt); ?></p>
|
||||||
<p class="class-meta"><i class="fas fa-location-dot me-1"></i>via Valassina 62/B Seregno - Sala Contesto Yoga</p>
|
<p class="class-meta"><i class="fas fa-location-dot me-1"></i>via Valassina 62/B Seregno - Sala Contesto Yoga</p>
|
||||||
@@ -676,6 +684,36 @@ $italianMonths = [
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($countWaiting > 0) : ?>
|
||||||
|
<div class="bookings-header" style="margin-top:18px;">
|
||||||
|
<span class="title" style="color:#d1698a;"><i class="fas fa-list-ol me-1"></i> Lista d'attesa (<?php echo $countWaiting; ?>)</span>
|
||||||
|
</div>
|
||||||
|
<div class="booking-list">
|
||||||
|
<?php $qpos = 1;
|
||||||
|
foreach ($waitings as $b) :
|
||||||
|
$idbc = (int) $b['idbookingclass'];
|
||||||
|
$fullName = trim($b['first_name'] . ' ' . $b['last_name']);
|
||||||
|
$ini = initials($b['first_name'] ?? '', $b['last_name'] ?? '');
|
||||||
|
$avColor = avatarColor($fullName);
|
||||||
|
?>
|
||||||
|
<div class="booking-item" style="background:#fdf4f8;border-color:#f0d6e2;" data-iduser="<?php echo (int) $b['iduser']; ?>">
|
||||||
|
<div class="avatar" style="background: <?php echo $avColor; ?>;"><?php echo e($ini); ?></div>
|
||||||
|
<div class="booking-info">
|
||||||
|
<span class="booking-name">
|
||||||
|
<span style="display:inline-block;min-width:22px;font-weight:800;color:#d1698a;"><?php echo $qpos; ?>°</span>
|
||||||
|
<?php echo e($fullName); ?>
|
||||||
|
</span>
|
||||||
|
<span class="status-chip" style="background:#fbeef3;color:#d1698a;">In coda</span>
|
||||||
|
</div>
|
||||||
|
<div class="booking-actions">
|
||||||
|
<button class="mini-btn remove" onclick="handleRemoveClick(<?php echo $idbc; ?>)"><i class="fas fa-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php $qpos++;
|
||||||
|
endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="add-box">
|
<div class="add-box">
|
||||||
<strong class="d-block mb-2" style="font-size:14px;"><i class="fas fa-user-plus me-1" style="color:#1ebf73;"></i> Aggiungi partecipante</strong>
|
<strong class="d-block mb-2" style="font-size:14px;"><i class="fas fa-user-plus me-1" style="color:#1ebf73;"></i> Aggiungi partecipante</strong>
|
||||||
<form class="add-booking-form" action="inserisci_record.php" method="post">
|
<form class="add-booking-form" action="inserisci_record.php" method="post">
|
||||||
|
|||||||
+17
-4
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once('include/headscript.php');
|
require_once('include/headscript.php');
|
||||||
require_once __DIR__ . '/class/mailer.php';
|
require_once __DIR__ . '/class/mailer.php';
|
||||||
|
require_once('include/waitinglist.php');
|
||||||
|
|
||||||
use PHPMailer\PHPMailer\PHPMailer;
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
use PHPMailer\PHPMailer\Exception;
|
use PHPMailer\PHPMailer\Exception;
|
||||||
@@ -55,11 +56,20 @@ if ($rowUser = $resUser->fetch_assoc()) {
|
|||||||
}
|
}
|
||||||
$stmtUser->close();
|
$stmtUser->close();
|
||||||
|
|
||||||
|
// Decide lo stato: pending se c'è posto, waiting se la classe è piena
|
||||||
|
$bookingStatus = decideBookingStatus($conn, $idnewbooking);
|
||||||
|
|
||||||
|
if ($bookingStatus === 'full') {
|
||||||
|
// Classe piena e lista d'attesa disattivata: non inseriamo nulla
|
||||||
|
header("Location: userpanel.php?full=Y");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
// Inserisce la nuova prenotazione in bookingclass
|
// Inserisce la nuova prenotazione in bookingclass
|
||||||
$insertQuery = "INSERT INTO bookingclass (idserviceschedule, iduser, prevbookingstart, idprevserviceschedule, idservice, idorder, bookingstart, status)
|
$insertQuery = "INSERT INTO bookingclass (idserviceschedule, iduser, prevbookingstart, idprevserviceschedule, idservice, idorder, bookingstart, status)
|
||||||
VALUES (?, ?, NULL, '0', ?, ?, ?, 'pending')";
|
VALUES (?, ?, NULL, '0', ?, ?, ?, ?)";
|
||||||
$stmt = $conn->prepare($insertQuery);
|
$stmt = $conn->prepare($insertQuery);
|
||||||
$stmt->bind_param("iiiis", $idnewbooking, $iduser, $idservicenew, $idorder, $newtime);
|
$stmt->bind_param("iiiiss", $idnewbooking, $iduser, $idservicenew, $idorder, $newtime, $bookingStatus);
|
||||||
if (!$stmt->execute()) {
|
if (!$stmt->execute()) {
|
||||||
$stmt->close();
|
$stmt->close();
|
||||||
die("Errore durante l'inserimento della nuova prenotazione: " . $conn->error);
|
die("Errore durante l'inserimento della nuova prenotazione: " . $conn->error);
|
||||||
@@ -78,9 +88,12 @@ $stmt->close();
|
|||||||
|
|
||||||
// Connessione $bkngstm gestita globalmente: non la chiudiamo qui
|
// Connessione $bkngstm gestita globalmente: non la chiudiamo qui
|
||||||
|
|
||||||
|
// Parametro di ritorno diverso se finito in lista d'attesa
|
||||||
|
$redirectFlag = ($bookingStatus === 'waiting') ? 'waiting=Y' : 'reprogram=Y';
|
||||||
|
|
||||||
// Se non abbiamo un'email valida, salta l'invio ma completa comunque il flusso
|
// Se non abbiamo un'email valida, salta l'invio ma completa comunque il flusso
|
||||||
if ($emailuser === '') {
|
if ($emailuser === '') {
|
||||||
header("Location: userpanel.php?reprogram=Y");
|
header("Location: userpanel.php?$redirectFlag");
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,5 +181,5 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Esegui il reindirizzamento
|
// Esegui il reindirizzamento
|
||||||
header("Location: userpanel.php?reprogram=Y");
|
header("Location: userpanel.php?$redirectFlag");
|
||||||
exit();
|
exit();
|
||||||
|
|||||||
@@ -507,7 +507,7 @@ $conn->close();
|
|||||||
|
|
||||||
$mysqli = new mysqli($servername, $username, $password, $dbname);
|
$mysqli = new mysqli($servername, $username, $password, $dbname);
|
||||||
$eventId = $bookedclass->getColumnVal("idserviceschedule");
|
$eventId = $bookedclass->getColumnVal("idserviceschedule");
|
||||||
$bookingQuery = "SELECT iduser FROM bookingclass WHERE bookingclass.idserviceschedule = ? AND bookingclass.status='booked'";
|
$bookingQuery = "SELECT iduser FROM bookingclass WHERE bookingclass.idserviceschedule = ? AND bookingclass.status IN ('booked','pending')";
|
||||||
$stmt = $mysqli->prepare($bookingQuery);
|
$stmt = $mysqli->prepare($bookingQuery);
|
||||||
$stmt->bind_param("i", $eventId);
|
$stmt->bind_param("i", $eventId);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
@@ -538,7 +538,7 @@ $conn->close();
|
|||||||
<?php } elseif ($freeplace > 0) { ?>
|
<?php } elseif ($freeplace > 0) { ?>
|
||||||
<div class="custom-date-box" style="background-color:#1ebf73">
|
<div class="custom-date-box" style="background-color:#1ebf73">
|
||||||
<?php } else { ?>
|
<?php } else { ?>
|
||||||
<div class="custom-date-box" style="background-color:#9C9C9C">
|
<div class="custom-date-box" style="background-color:#d1698a">
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<div class="custom-day"><?php echo $dayInItalian; ?></div>
|
<div class="custom-day"><?php echo $dayInItalian; ?></div>
|
||||||
<div class="custom-month"><?php echo $monthInItalian; ?></div>
|
<div class="custom-month"><?php echo $monthInItalian; ?></div>
|
||||||
@@ -548,7 +548,7 @@ $conn->close();
|
|||||||
<?php } elseif ($freeplace > 0) { ?>
|
<?php } elseif ($freeplace > 0) { ?>
|
||||||
<div class="custom-event-details" style="border-left-color:<?php echo ($bookedclass->getColumnVal("colorclass")); ?>">
|
<div class="custom-event-details" style="border-left-color:<?php echo ($bookedclass->getColumnVal("colorclass")); ?>">
|
||||||
<?php } else { ?>
|
<?php } else { ?>
|
||||||
<div class="custom-event-details" style="background-color:#CDCDCD;border-left-color:#9C9C9C">
|
<div class="custom-event-details" style="background-color:#fbeef3;border-left-color:#d1698a">
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<h2 class="custom-heading"><?php echo ($bookedclass->getColumnVal("servicename")); ?> -<?php echo $countPersons; ?>/<?php echo ($bookedclass->getColumnVal("maxcapacity")); ?></h2>
|
<h2 class="custom-heading"><?php echo ($bookedclass->getColumnVal("servicename")); ?> -<?php echo $countPersons; ?>/<?php echo ($bookedclass->getColumnVal("maxcapacity")); ?></h2>
|
||||||
<p class="custom-paragraph">Quando: <?php echo $newDateFormat; ?></p>
|
<p class="custom-paragraph">Quando: <?php echo $newDateFormat; ?></p>
|
||||||
@@ -560,9 +560,13 @@ $conn->close();
|
|||||||
<button class="booking-button"><i class="fa fa-check"></i> Sei già prenotata/o</button>
|
<button class="booking-button"><i class="fa fa-check"></i> Sei già prenotata/o</button>
|
||||||
<?php } elseif ($freeplace > 0) { ?>
|
<?php } elseif ($freeplace > 0) { ?>
|
||||||
<a href="rebookandgo.php?idpreviousbooking=<?php echo $idpreviousbooking; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>"><button class="booking-button"><i class="fas fa-arrow-circle-right"></i> Riprogramma Classe</button></a>
|
<a href="rebookandgo.php?idpreviousbooking=<?php echo $idpreviousbooking; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>"><button class="booking-button"><i class="fas fa-arrow-circle-right"></i> Riprogramma Classe</button></a>
|
||||||
|
<?php } else { ?>
|
||||||
|
<?php if ($optionquery->getColumnVal("waitinglist_enabled") === 'Y') { ?>
|
||||||
|
<a href="rebookandgo.php?idpreviousbooking=<?php echo $idpreviousbooking; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>"><button class="booking-button" style="background-color:#d1698a;color:#fff;"><i class="fas fa-hourglass-half"></i> Mettiti in lista d'attesa</button></a>
|
||||||
<?php } else { ?>
|
<?php } else { ?>
|
||||||
<button class="booking-button"><i class="fa fa-stop"></i> Classe Piena</button>
|
<button class="booking-button"><i class="fa fa-stop"></i> Classe Piena</button>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -742,7 +742,7 @@ $conn->close();
|
|||||||
?>
|
?>
|
||||||
<a href="bookandgo.php?idpreviousbooking=<?php echo '0'; ?>&idorder=<?php echo $idorder; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>" ?><button class="booking-button"><i class="fas fa-arrow-circle-right"></i> Riprogramma Classe</button></a>
|
<a href="bookandgo.php?idpreviousbooking=<?php echo '0'; ?>&idorder=<?php echo $idorder; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>" ?><button class="booking-button"><i class="fas fa-arrow-circle-right"></i> Riprogramma Classe</button></a>
|
||||||
<?php } else { ?>
|
<?php } else { ?>
|
||||||
<button class="booking-button"><i class="fa fa-stop"></i> Classe Piena</button>
|
<a href="bookandgo.php?idpreviousbooking=0&idorder=<?php echo $idorder; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>"><button class="booking-button" style="background-color:#f0ad4e;color:#fff;"><i class="fas fa-hourglass-half"></i> Mettiti in lista d'attesa</button></a>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
$conn = new mysqli($servername, $username, $password, $dbname);
|
||||||
|
require_once('include/headscript.php'); // per avere le credenziali DB, se sono lì
|
||||||
|
|
||||||
|
// Se le credenziali sono in headscript.php, sposta la connessione DOPO il require.
|
||||||
|
// Adatta questa parte a come sono definite $servername ecc. nelle tue altre pagine.
|
||||||
|
|
||||||
|
if ($conn->connect_error) {
|
||||||
|
die("Connessione fallita: " . $conn->connect_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||||
|
header("Location: riepilogo.php?message=error_delete");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$idorder = (int) $_GET['id'];
|
||||||
|
|
||||||
|
$conn->begin_transaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Cancella tutte le prenotazioni di questo ordine
|
||||||
|
$stmt1 = $conn->prepare("DELETE FROM bookingclass WHERE idorder = ?");
|
||||||
|
$stmt1->bind_param("i", $idorder);
|
||||||
|
$stmt1->execute();
|
||||||
|
$stmt1->close();
|
||||||
|
|
||||||
|
// 2. Cancella l'ordine
|
||||||
|
$stmt2 = $conn->prepare("DELETE FROM orderbook WHERE idorderbook = ?");
|
||||||
|
$stmt2->bind_param("i", $idorder);
|
||||||
|
$stmt2->execute();
|
||||||
|
$stmt2->close();
|
||||||
|
|
||||||
|
$conn->commit();
|
||||||
|
header("Location: riepilogo.php?message=success_delete");
|
||||||
|
exit();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$conn->rollback();
|
||||||
|
header("Location: riepilogo.php?message=error_delete");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn->close();
|
||||||
@@ -120,6 +120,12 @@
|
|||||||
<span class="menu-item" data-key="t-email">Sommario Ordini</span>
|
<span class="menu-item" data-key="t-email">Sommario Ordini</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="optionsschool.php" class="">
|
||||||
|
<i class="bx bx-receipt icon nav-icon"></i>
|
||||||
|
<span class="menu-item" data-key="t-email">Opzioni Scuola</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="menu-title" data-key="t-applications">Template</li>
|
<li class="menu-title" data-key="t-applications">Template</li>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper per la gestione della lista d'attesa (waiting list).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La scuola ha attivato la lista d'attesa?
|
||||||
|
* Legge l'unico record della tabella option.
|
||||||
|
*/
|
||||||
|
function isWaitingListEnabled(mysqli $conn): bool
|
||||||
|
{
|
||||||
|
$res = $conn->query("SELECT waitinglist_enabled FROM `option` LIMIT 1");
|
||||||
|
if ($res && ($row = $res->fetch_assoc())) {
|
||||||
|
return $row['waitinglist_enabled'] === 'Y';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capienza, posti impegnati (booked + pending) e posti liberi di una classe.
|
||||||
|
*
|
||||||
|
* @return array{maxcapacity:int, occupied:int, free:int}
|
||||||
|
*/
|
||||||
|
function getClassOccupancy(mysqli $conn, int $idserviceschedule): array
|
||||||
|
{
|
||||||
|
// Capienza (da service via serviceschedule)
|
||||||
|
$cap = 0;
|
||||||
|
$stmt = $conn->prepare(
|
||||||
|
"SELECT s.maxcapacity
|
||||||
|
FROM serviceschedule ss
|
||||||
|
JOIN service s ON ss.idservice = s.idservice
|
||||||
|
WHERE ss.idserviceschedule = ?"
|
||||||
|
);
|
||||||
|
$stmt->bind_param("i", $idserviceschedule);
|
||||||
|
$stmt->execute();
|
||||||
|
$res = $stmt->get_result();
|
||||||
|
if ($rowCap = $res->fetch_assoc()) {
|
||||||
|
$cap = (int) $rowCap['maxcapacity'];
|
||||||
|
}
|
||||||
|
$stmt->close();
|
||||||
|
|
||||||
|
// Posti impegnati: booked + pending
|
||||||
|
$occupied = 0;
|
||||||
|
$stmt = $conn->prepare(
|
||||||
|
"SELECT COUNT(*) AS occupied
|
||||||
|
FROM bookingclass
|
||||||
|
WHERE idserviceschedule = ?
|
||||||
|
AND status IN ('booked', 'pending')"
|
||||||
|
);
|
||||||
|
$stmt->bind_param("i", $idserviceschedule);
|
||||||
|
$stmt->execute();
|
||||||
|
$res = $stmt->get_result();
|
||||||
|
if ($rowOcc = $res->fetch_assoc()) {
|
||||||
|
$occupied = (int) $rowOcc['occupied'];
|
||||||
|
}
|
||||||
|
$stmt->close();
|
||||||
|
|
||||||
|
$free = $cap - $occupied;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'maxcapacity' => $cap,
|
||||||
|
'occupied' => $occupied,
|
||||||
|
'free' => $free < 0 ? 0 : $free,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decide lo stato di una nuova prenotazione:
|
||||||
|
* - 'pending' -> c'è posto (flusso normale, insegnante approva)
|
||||||
|
* - 'waiting' -> classe piena E waiting list attiva
|
||||||
|
* - 'full' -> classe piena E waiting list disattivata (NON prenotabile)
|
||||||
|
*/
|
||||||
|
function decideBookingStatus(mysqli $conn, int $idserviceschedule): string
|
||||||
|
{
|
||||||
|
$occ = getClassOccupancy($conn, $idserviceschedule);
|
||||||
|
|
||||||
|
if ($occ['free'] > 0) {
|
||||||
|
return 'pending';
|
||||||
|
}
|
||||||
|
|
||||||
|
return isWaitingListEnabled($conn) ? 'waiting' : 'full';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posizione (1-based) di un utente nella coda waiting di una classe.
|
||||||
|
* 0 se non è in coda.
|
||||||
|
*/
|
||||||
|
function getWaitingPosition(mysqli $conn, int $idserviceschedule, int $iduser): int
|
||||||
|
{
|
||||||
|
$stmt = $conn->prepare(
|
||||||
|
"SELECT COUNT(*) AS pos
|
||||||
|
FROM bookingclass
|
||||||
|
WHERE idserviceschedule = ?
|
||||||
|
AND status = 'waiting'
|
||||||
|
AND created_at <= (
|
||||||
|
SELECT created_at FROM bookingclass
|
||||||
|
WHERE idserviceschedule = ? AND iduser = ? AND status = 'waiting'
|
||||||
|
ORDER BY created_at ASC LIMIT 1
|
||||||
|
)"
|
||||||
|
);
|
||||||
|
$stmt->bind_param("iii", $idserviceschedule, $idserviceschedule, $iduser);
|
||||||
|
$stmt->execute();
|
||||||
|
$res = $stmt->get_result();
|
||||||
|
$pos = 0;
|
||||||
|
if ($row = $res->fetch_assoc()) {
|
||||||
|
$pos = (int) $row['pos'];
|
||||||
|
}
|
||||||
|
$stmt->close();
|
||||||
|
return $pos;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
|
$conn = new mysqli($servername, $username, $password, $dbname);
|
||||||
|
if ($conn->connect_error) {
|
||||||
|
header("Location: userpanel.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$iduserlogin = (int) $iduserlogin;
|
||||||
|
$idbookingclass = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
||||||
|
|
||||||
|
if ($idbookingclass > 0) {
|
||||||
|
// Cancella solo se è una riga waiting DELL'utente loggato (sicurezza)
|
||||||
|
$stmt = $conn->prepare(
|
||||||
|
"DELETE FROM bookingclass
|
||||||
|
WHERE idbookingclass = ? AND iduser = ? AND status = 'waiting'"
|
||||||
|
);
|
||||||
|
$stmt->bind_param("ii", $idbookingclass, $iduserlogin);
|
||||||
|
$stmt->execute();
|
||||||
|
$stmt->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn->close();
|
||||||
|
header("Location: userpanel.php?leftwaiting=Y");
|
||||||
|
exit();
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
header("Location: options.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn = new mysqli($servername, $username, $password, $dbname);
|
||||||
|
if ($conn->connect_error) {
|
||||||
|
header("Location: options.php?message=error");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checkbox non spuntata = nessun invio -> default 'N'
|
||||||
|
$waitingEnabled = (isset($_POST['waitinglist_enabled']) && $_POST['waitinglist_enabled'] === 'Y') ? 'Y' : 'N';
|
||||||
|
$maxCancel = isset($_POST['maxbeforetimecancell']) ? (string) (int) $_POST['maxbeforetimecancell'] : '0';
|
||||||
|
|
||||||
|
// Aggiorna l'unico record di option (idption = 1)
|
||||||
|
$stmt = $conn->prepare("UPDATE `option` SET waitinglist_enabled = ?, maxbeforetimecancell = ? WHERE idption = 1");
|
||||||
|
$stmt->bind_param("ss", $waitingEnabled, $maxCancel);
|
||||||
|
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
$stmt->close();
|
||||||
|
$conn->close();
|
||||||
|
header("Location: optionsschool.php?message=success");
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
$stmt->close();
|
||||||
|
$conn->close();
|
||||||
|
header("Location: optionsschool.php?message=error");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
<?php
|
||||||
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
|
$conn = new mysqli($servername, $username, $password, $dbname);
|
||||||
|
if ($conn->connect_error) {
|
||||||
|
die("Connessione fallita: " . $conn->connect_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
function e($value): string
|
||||||
|
{
|
||||||
|
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = $_GET['message'] ?? 'n';
|
||||||
|
|
||||||
|
// Carica l'unico record di option
|
||||||
|
$opt = $conn->query("SELECT * FROM `option` LIMIT 1")->fetch_assoc();
|
||||||
|
$conn->close();
|
||||||
|
|
||||||
|
$waitingEnabled = ($opt['waitinglist_enabled'] ?? 'N') === 'Y';
|
||||||
|
$maxCancel = $opt['maxbeforetimecancell'] ?? '0';
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="it">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>YogiBook - Opzioni</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<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">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 18px 0;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2937;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-help {
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-switch .form-check-input {
|
||||||
|
width: 3em;
|
||||||
|
height: 1.5em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-bar {
|
||||||
|
margin-top: 24px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</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">Opzioni</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">
|
||||||
|
<?php if ($message === 'success') : ?>
|
||||||
|
<div class="alert alert-success" role="alert">Impostazioni salvate con successo.</div>
|
||||||
|
<?php elseif ($message === 'error') : ?>
|
||||||
|
<div class="alert alert-danger" role="alert">Errore durante il salvataggio.</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card admin-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="section-title">Impostazioni prenotazioni</div>
|
||||||
|
<p class="section-lead">Configura il comportamento del sistema di prenotazione.</p>
|
||||||
|
|
||||||
|
<form action="options_save.php" method="POST">
|
||||||
|
|
||||||
|
<div class="option-row">
|
||||||
|
<div>
|
||||||
|
<div class="option-label">Lista d'attesa</div>
|
||||||
|
<div class="option-help">Se attiva, quando una classe è piena gli utenti possono mettersi in coda. Alla liberazione di un posto verranno gestiti in ordine di arrivo.</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" type="checkbox" role="switch" id="waitinglist_enabled" name="waitinglist_enabled" value="Y" <?php echo $waitingEnabled ? 'checked' : ''; ?>>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="option-row">
|
||||||
|
<div>
|
||||||
|
<div class="option-label">Ore minime per l'annullamento</div>
|
||||||
|
<div class="option-help">Quante ore prima dell'inizio di una lezione è ancora possibile annullarla.</div>
|
||||||
|
</div>
|
||||||
|
<div style="width:120px;">
|
||||||
|
<input type="number" min="0" class="form-control" name="maxbeforetimecancell" value="<?php echo e($maxCancel); ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="save-bar">
|
||||||
|
<button type="submit" class="btn btn-success"><i class="fas fa-save me-1"></i> Salva impostazioni</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</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>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
+33
-2
@@ -172,8 +172,23 @@ if ($result_dayoff->num_rows > 0) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funzione per confermare la cancellazione
|
// Funzione per confermare la cancellazione di un ordine e delle sue prenotazioni
|
||||||
function confirmDelete(id, deletePageUrl) {
|
window.confirmDeleteOrder = function(id) {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Sei sicuro?",
|
||||||
|
text: "Verranno cancellati l'ordine e TUTTE le prenotazioni collegate a questa persona. L'azione è irreversibile!",
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: "#d33",
|
||||||
|
cancelButtonColor: "#3085d6",
|
||||||
|
confirmButtonText: "Sì, cancella tutto!",
|
||||||
|
cancelButtonText: "Annulla"
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
window.location.href = `deleteorder.php?id=${id}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Sei sicuro?",
|
title: "Sei sicuro?",
|
||||||
text: "Questa prenotazione verrà cancellata definitivamente! Ricordati poi di riprogrammare la tua lezione!",
|
text: "Questa prenotazione verrà cancellata definitivamente! Ricordati poi di riprogrammare la tua lezione!",
|
||||||
@@ -371,6 +386,7 @@ if ($result_dayoff->num_rows > 0) {
|
|||||||
<th>Numero Ticket</th>
|
<th>Numero Ticket</th>
|
||||||
<th>Scadenza</th>
|
<th>Scadenza</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
|
<th>Azioni</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -388,6 +404,12 @@ if ($result_dayoff->num_rows > 0) {
|
|||||||
<td><?php echo $order["nticket"]; ?></td>
|
<td><?php echo $order["nticket"]; ?></td>
|
||||||
<td class="expiry-date" data-order-id="<?php echo $order['idorderbook']; ?>"><?php echo $order["expireon"]; ?></td>
|
<td class="expiry-date" data-order-id="<?php echo $order['idorderbook']; ?>"><?php echo $order["expireon"]; ?></td>
|
||||||
<td><?php echo $order["status"]; ?></td>
|
<td><?php echo $order["status"]; ?></td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-sm btn-danger"
|
||||||
|
onclick="confirmDeleteOrder(<?php echo $order['idorderbook']; ?>)">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -407,6 +429,15 @@ if ($result_dayoff->num_rows > 0) {
|
|||||||
<script src="assets/libs/simplebar/simplebar.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/libs/eva-icons/eva.min.js"></script>
|
||||||
<script src="assets/js/app.js"></script>
|
<script src="assets/js/app.js"></script>
|
||||||
|
<?php if ($message == 'success_delete') { ?>
|
||||||
|
<script>
|
||||||
|
Swal.fire('Fatto!', 'Ordine e prenotazioni cancellati.', 'success');
|
||||||
|
</script>
|
||||||
|
<?php } elseif ($message == 'error_delete') { ?>
|
||||||
|
<script>
|
||||||
|
Swal.fire('Errore!', 'Errore durante la cancellazione.', 'error');
|
||||||
|
</script>
|
||||||
|
<?php } ?>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
+11
-5
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once('include/headscript.php');
|
require_once('include/headscript.php');
|
||||||
require_once __DIR__ . '/class/mailer.php';
|
require_once __DIR__ . '/class/mailer.php';
|
||||||
|
require_once('include/waitinglist.php');
|
||||||
|
|
||||||
use PHPMailer\PHPMailer\PHPMailer;
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
use PHPMailer\PHPMailer\Exception;
|
use PHPMailer\PHPMailer\Exception;
|
||||||
@@ -53,12 +54,15 @@ $stmt->bind_param("i", $idpreviousbooking);
|
|||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$stmt->close();
|
$stmt->close();
|
||||||
|
|
||||||
// Inserisci la nuova prenotazione (pending)
|
// Decide lo stato: pending se c'è posto, waiting se la classe è piena
|
||||||
|
$bookingStatus = decideBookingStatus($conn, $idnewbooking);
|
||||||
|
|
||||||
|
// Inserisci la nuova prenotazione
|
||||||
$stmt = $conn->prepare(
|
$stmt = $conn->prepare(
|
||||||
"INSERT INTO bookingclass (idserviceschedule, iduser, prevbookingstart, idprevserviceschedule, idservice, idorder, bookingstart, status)
|
"INSERT INTO bookingclass (idserviceschedule, iduser, prevbookingstart, idprevserviceschedule, idservice, idorder, bookingstart, status)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')"
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
|
||||||
);
|
);
|
||||||
$stmt->bind_param("iisiiss", $idnewbooking, $iduser, $prevBookingStart, $idPrevServiceSchedule, $idservicenew, $globalidorder, $newtime);
|
$stmt->bind_param("iisiisss", $idnewbooking, $iduser, $prevBookingStart, $idPrevServiceSchedule, $idservicenew, $globalidorder, $newtime, $bookingStatus);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$stmt->close();
|
$stmt->close();
|
||||||
|
|
||||||
@@ -83,9 +87,11 @@ $stmtUser->close();
|
|||||||
|
|
||||||
$newtimeformat = date("d-m-Y H:i", strtotime($newtime));
|
$newtimeformat = date("d-m-Y H:i", strtotime($newtime));
|
||||||
|
|
||||||
|
$redirectFlag = ($bookingStatus === 'waiting') ? 'waiting=Y' : 'reprogram=Y';
|
||||||
|
|
||||||
// Se manca l'email, completa comunque il flusso senza inviare
|
// Se manca l'email, completa comunque il flusso senza inviare
|
||||||
if ($emailuser === '') {
|
if ($emailuser === '') {
|
||||||
header("Location: userpanel.php?reprogram=Y");
|
header("Location: userpanel.php?$redirectFlag");
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,5 +144,5 @@ try {
|
|||||||
error_log("Errore invio mail riprogrammazione (iduser $iduser): " . $mail->ErrorInfo);
|
error_log("Errore invio mail riprogrammazione (iduser $iduser): " . $mail->ErrorInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
header("Location: userpanel.php?reprogram=Y");
|
header("Location: userpanel.php?$redirectFlag");
|
||||||
exit();
|
exit();
|
||||||
|
|||||||
@@ -75,6 +75,40 @@ $stmtPending->execute([
|
|||||||
]);
|
]);
|
||||||
$pendingRows = $stmtPending->fetchAll();
|
$pendingRows = $stmtPending->fetchAll();
|
||||||
|
|
||||||
|
// Lezioni in lista d'attesa (waiting) dell'utente, nel mese visualizzato
|
||||||
|
$sqlWaiting = "SELECT bookingclass.*, service.servicename, service.colorclass, service.maxcapacity, serviceschedule.dateschedule
|
||||||
|
FROM bookingclass
|
||||||
|
LEFT JOIN service ON bookingclass.idservice = service.idservice
|
||||||
|
LEFT JOIN serviceschedule ON bookingclass.idserviceschedule = serviceschedule.idserviceschedule
|
||||||
|
WHERE bookingclass.iduser = :iduser
|
||||||
|
AND bookingclass.status = 'waiting'
|
||||||
|
AND serviceschedule.dateschedule BETWEEN :monthStart AND DATE_ADD(:monthEnd, INTERVAL 1 DAY)
|
||||||
|
ORDER BY serviceschedule.dateschedule";
|
||||||
|
$stmtWaiting = $pdo->prepare($sqlWaiting);
|
||||||
|
$stmtWaiting->execute([
|
||||||
|
':iduser' => $iduserlogin,
|
||||||
|
':monthStart' => $currentMonthStart,
|
||||||
|
':monthEnd' => $currentMonthEnd,
|
||||||
|
]);
|
||||||
|
$waitingRows = $stmtWaiting->fetchAll();
|
||||||
|
|
||||||
|
// Posizione in coda per ciascuna lezione waiting (1-based, ordine per created_at)
|
||||||
|
$waitingPositions = [];
|
||||||
|
foreach ($waitingRows as $wrow) {
|
||||||
|
$sqlPos = "SELECT COUNT(*) AS pos
|
||||||
|
FROM bookingclass
|
||||||
|
WHERE idserviceschedule = :sched
|
||||||
|
AND status = 'waiting'
|
||||||
|
AND created_at <= :mycreated";
|
||||||
|
$stmtPos = $pdo->prepare($sqlPos);
|
||||||
|
$stmtPos->execute([
|
||||||
|
':sched' => (int) $wrow['idserviceschedule'],
|
||||||
|
':mycreated' => $wrow['created_at'],
|
||||||
|
]);
|
||||||
|
$rowPos = $stmtPos->fetch();
|
||||||
|
$waitingPositions[(int) $wrow['idbookingclass']] = (int) ($rowPos['pos'] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* 3) Somma dei ticket acquistati dall'utente
|
* 3) Somma dei ticket acquistati dall'utente
|
||||||
* ---------------------------------------------------------------------- */
|
* ---------------------------------------------------------------------- */
|
||||||
@@ -541,6 +575,27 @@ $italianMonths = [
|
|||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
<?php if (isset($_GET['waiting'])) { ?>
|
||||||
|
<div class="alert alert-warning alert-dismissible fade show" role="alert">
|
||||||
|
<i class="fas fa-hourglass-half me-2"></i>
|
||||||
|
La classe era piena: sei stata/o inserita/o in <strong>lista d'attesa</strong>. Se si libera un posto verrai avvisata/o.
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if (isset($_GET['leftwaiting'])) { ?>
|
||||||
|
<div class="alert alert-info alert-dismissible fade show" role="alert">
|
||||||
|
<i class="fas fa-check me-2"></i>
|
||||||
|
Sei uscita/o dalla lista d'attesa.
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if (isset($_GET['full'])) { ?>
|
||||||
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
|
<i class="fas fa-ban me-2"></i>
|
||||||
|
La classe è al completo e la lista d'attesa non è attiva. Prova con un altro orario.
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php } ?>
|
||||||
<?php if (isset($_GET['deleted'])) { ?>
|
<?php if (isset($_GET['deleted'])) { ?>
|
||||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
<i class="mdi mdi-check-all me-2"></i>
|
<i class="mdi mdi-check-all me-2"></i>
|
||||||
@@ -636,6 +691,58 @@ $italianMonths = [
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($waitingRows)) : ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xl-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 style="color:#8a6d00;margin-bottom:14px;">
|
||||||
|
<i class="fas fa-hourglass-half me-1"></i> In lista d'attesa
|
||||||
|
</h5>
|
||||||
|
<?php foreach ($waitingRows as $wrow) :
|
||||||
|
$wDateObj = new DateTime($wrow['dateschedule']);
|
||||||
|
$wDay = $wDateObj->format("d");
|
||||||
|
$wMonth = $italianMonths[$wDateObj->format("F")];
|
||||||
|
$wWhen = $wDateObj->format("d-m-Y H:i");
|
||||||
|
$wColor = $wrow['colorclass'] ?? '#1ebf73';
|
||||||
|
$wName = $wrow['servicename'] ?? '';
|
||||||
|
$wPos = $waitingPositions[(int) $wrow['idbookingclass']] ?? 0;
|
||||||
|
?>
|
||||||
|
<div class="custom-card pending-card">
|
||||||
|
<div class="custom-date-box" style="background:#9C9C9C;">
|
||||||
|
<div class="custom-day"><?php echo e($wDay); ?></div>
|
||||||
|
<div class="custom-month"><?php echo e($wMonth); ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="custom-event-details" style="border-left-color:<?php echo e($wColor); ?>">
|
||||||
|
<h2 class="custom-heading">
|
||||||
|
<?php echo e($wName); ?>
|
||||||
|
<span style="display:inline-block;background:#eee;color:#555;font-size:11px;font-weight:700;padding:2px 9px;border-radius:20px;margin-left:6px;vertical-align:middle;">In coda</span>
|
||||||
|
</h2>
|
||||||
|
<p class="custom-paragraph">Quando: <?php echo e($wWhen); ?></p>
|
||||||
|
<p class="custom-paragraph">Luogo: via Valassina 62/B Seregno - Sala Contesto Yoga</p>
|
||||||
|
<?php if ($wPos > 0) : ?>
|
||||||
|
<p class="custom-paragraph" style="font-weight:700;color:#8a6d00;">
|
||||||
|
<i class="fas fa-list-ol me-1"></i> La tua posizione in coda: <?php echo e($wPos); ?>
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<p class="custom-paragraph" style="font-size:13px;color:#9ca3af;">
|
||||||
|
Se si libera un posto verrai avvisata/o. Non serve fare nulla.
|
||||||
|
</p>
|
||||||
|
<div style="margin-top:8px;">
|
||||||
|
<button class="custom-action-button" style="background:#fbeef3;color:#d1698a;"
|
||||||
|
onclick="confirmLeaveWaiting(<?php echo (int) $wrow['idbookingclass']; ?>)">
|
||||||
|
<i class="fas fa-times-circle"></i> Esci dalla lista d'attesa
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xl-12">
|
<div class="col-xl-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@@ -741,6 +848,23 @@ $italianMonths = [
|
|||||||
const outlookCalendarLink = `webcal://outlook.live.com/calendar/0/deeplink/compose?path=/calendar/action/compose&subject=${encodeURIComponent(eventName)}&startdt=${encodeURIComponent(eventDate)}`;
|
const outlookCalendarLink = `webcal://outlook.live.com/calendar/0/deeplink/compose?path=/calendar/action/compose&subject=${encodeURIComponent(eventName)}&startdt=${encodeURIComponent(eventDate)}`;
|
||||||
window.open(outlookCalendarLink, '_blank');
|
window.open(outlookCalendarLink, '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function confirmLeaveWaiting(id) {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Uscire dalla lista d'attesa?",
|
||||||
|
text: "Verrai rimossa/o dalla coda per questa lezione.",
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: "#d1698a",
|
||||||
|
cancelButtonColor: "#3085d6",
|
||||||
|
confirmButtonText: "Sì, esci",
|
||||||
|
cancelButtonText: "Annulla"
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
window.location.href = "leavewaiting.php?id=" + id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user