From b592be5831d2bb372eeb30c31a28b8ffe294e299 Mon Sep 17 00:00:00 2001 From: solocla Date: Tue, 23 Dec 2025 09:39:59 +0100 Subject: [PATCH] future lessons --- .env | 18 +- public/api/_bootstrap.php | 35 ++ public/api/my-lessons.php | 68 ++++ public/userarea/class/mailer.php | 4 +- public/userarea/future_sessions.php | 543 +++++++++++++++++++++++++++ public/userarea/my_lessons.php | 2 +- public/userarea/school_dashboard.php | 3 +- public/userarea/select_school.php | 75 +++- public/userarea/user_dashboard.php | 70 +++- 9 files changed, 790 insertions(+), 28 deletions(-) create mode 100644 public/api/_bootstrap.php create mode 100644 public/api/my-lessons.php create mode 100644 public/userarea/future_sessions.php diff --git a/.env b/.env index 3a96daf..eaf6c4d 100644 --- a/.env +++ b/.env @@ -23,13 +23,13 @@ REDIS_PASSWORD=null REDIS_PORT=6379 MAIL_MAILER=mail -MAIL_FROM_NAME=Vanguard -MAIL_FROM_ADDRESS=vanguard@test.dev -MAIL_HOST=smtp.mailtrap.io -MAIL_PORT=2525 -MAIL_USERNAME=null -MAIL_PASSWORD=null -MAIL_ENCRYPTION=null +MAIL_FROM_NAME=YogaSoul +MAIL_FROM_ADDRESS=info@yogasoul.it +MAIL_HOST=mail.yogasoul.it +MAIL_PORT=465 +MAIL_USERNAME=info@yogasoul.it +MAIL_PASSWORD=!Testolina88 +MAIL_ENCRYPTION=ssl PUSHER_APP_ID= PUSHER_APP_KEY= @@ -37,4 +37,6 @@ PUSHER_APP_SECRET= PUSHER_APP_CLUSTER=mt1 MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" -MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" \ No newline at end of file +MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" + +EXPOSE_API=true \ No newline at end of file diff --git a/public/api/_bootstrap.php b/public/api/_bootstrap.php new file mode 100644 index 0000000..c959cdc --- /dev/null +++ b/public/api/_bootstrap.php @@ -0,0 +1,35 @@ +getConnection(); + +// ============================== +// AUTH VANGUARD +// ============================== +require_once $BASE_PATH . '/../../extra/auth.php'; + +// ============================== +// AUTH API (TOKEN) +// ============================== +$user = Auth::guard('api')->user(); + +if (!$user) { + http_response_code(401); + echo json_encode(['error' => 'Unauthorized']); + exit; +} diff --git a/public/api/my-lessons.php b/public/api/my-lessons.php new file mode 100644 index 0000000..ad1be53 --- /dev/null +++ b/public/api/my-lessons.php @@ -0,0 +1,68 @@ +format('Y-m-01'); +$endOfMonth = (clone $monthDate)->modify('+1 month')->format('Y-m-d'); + +// ============================== +// DATI UTENTE +// ============================== +$userId = $user->id; +$schoolId = $user->school_id ?? null; + +if (!$schoolId) { + http_response_code(400); + echo json_encode(['error' => 'No school selected']); + exit; +} + +// ============================== +// QUERY (IDENTICA ALLA WEB) +// ============================== +$stmt = $db->prepare(" + SELECT + sb.id AS booking_id, + sb.status, + cs.session_date, + cs.start_time, + cs.end_time, + cs.room_name, + c.name AS class_name, + ct.level, + o.available_entries, + o.available_recoveries + 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 + JOIN orders o ON sb.order_id = o.id + WHERE sb.user_id = ? + AND cs.school_id = ? + AND cs.session_date >= ? + AND cs.session_date < ? + ORDER BY cs.session_date ASC, cs.start_time ASC +"); + +$stmt->execute([ + $userId, + $schoolId, + $startOfMonth, + $endOfMonth +]); + +$lessons = $stmt->fetchAll(PDO::FETCH_ASSOC); + +// ============================== +// OUTPUT +// ============================== +echo json_encode([ + 'month' => $month, + 'count' => count($lessons), + 'lessons' => $lessons +]); diff --git a/public/userarea/class/mailer.php b/public/userarea/class/mailer.php index 851e4cf..da37be5 100644 --- a/public/userarea/class/mailer.php +++ b/public/userarea/class/mailer.php @@ -5,9 +5,9 @@ use PHPMailer\PHPMailer\Exception; use Dotenv\Dotenv; // Carica le variabili di ambiente -require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; // Assicurati che PHPMailer e Dotenv siano installati con Composer +require_once dirname(__DIR__, 3) . '/vendor/autoload.php'; // Assicurati che PHPMailer e Dotenv siano installati con Composer -$dotenv = Dotenv::createImmutable(dirname(__DIR__, 2)); // Se la cartella `class` è a 2 livelli sopra la root +$dotenv = Dotenv::createImmutable(dirname(__DIR__, 3)); // Se la cartella `class` è a 2 livelli sopra la root $dotenv->load(); function sendEmail($to, $subject, $body, $attachments = [], $cc = [], $bcc = []) diff --git a/public/userarea/future_sessions.php b/public/userarea/future_sessions.php new file mode 100644 index 0000000..1c7fcb7 --- /dev/null +++ b/public/userarea/future_sessions.php @@ -0,0 +1,543 @@ +getConnection(); + +if (!isset($iduserlogin)) { + die("Errore: ID utente non definito."); +} + +$stmt = $pdo->prepare("SELECT id, name, logo FROM schools WHERE owner_id = ?"); +$stmt->execute([$iduserlogin]); +$school = $stmt->fetch(); +if (!$school) { + die("Errore: Nessuna scuola trovata."); +} +$school_id = $school['id']; +$school_name = $school['name']; + +// === GESTIONE AZIONI === +$feedback = ''; +$showEmailModal = false; +$emailData = null; + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $action = $_POST['action'] ?? ''; + + // Cancellazione lezione + if ($action === 'delete_session') { + $session_id = (int)($_POST['session_id'] ?? 0); + $send_email = !empty($_POST['send_email']); + + $stmt = $pdo->prepare(" + SELECT cs.id, cs.session_date, cs.start_time, cs.end_time, + c.name AS class_name, ct.level + 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([$session_id, $school_id]); + $session = $stmt->fetch(); + + if ($session) { + $recipients = []; + if ($send_email) { + $stmt2 = $pdo->prepare(" + SELECT au.email, au.first_name + FROM session_bookings sb + JOIN auth_users au ON sb.user_id = au.id + WHERE sb.session_id = ? AND sb.status IN ('booked','attended','rescheduled') + "); + $stmt2->execute([$session_id]); + $recipients = $stmt2->fetchAll(PDO::FETCH_ASSOC); + } + + + + // Se devo inviare email e ci sono destinatari -> apro modale (NON cancello ancora) + if ($send_email && !empty($recipients)) { + $showEmailModal = true; + $emailData = [ + 'session_id' => $session_id, + 'class_name' => $session['class_name'], + 'level' => $session['level'] ?? '', + 'date' => date('d/m/Y', strtotime($session['session_date'])), + 'time' => substr($session['start_time'], 0, 5) . ' - ' . substr($session['end_time'], 0, 5), + 'recipients' => $recipients + ]; + } else { + // Altrimenti cancello subito + $stmt = $pdo->prepare("DELETE FROM class_sessions WHERE id = ? AND id IN ( + 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 c.school_id = ? + )"); + $stmt->execute([$session_id, $school_id]); + + $feedback = '
+ Lezione cancellata con successo! + +
'; + } + } + } + + // Invio email cancellazione + elseif ($action === 'send_cancellation_email') { + $session_id = (int)($_POST['session_id'] ?? 0); + $body_text = $_POST['email_body'] ?? ''; + + $stmt = $pdo->prepare(" + SELECT c.name AS class_name, ct.level, cs.session_date, cs.start_time, cs.end_time + 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([$session_id, $school_id]); + $session = $stmt->fetch(); + + $class_info = $session['class_name'] . ($session['level'] ? ' (' . ucfirst($session['level']) . ')' : ''); + $date = $session ? date('d/m/Y', strtotime($session['session_date'])) : ''; + $time = $session ? substr($session['start_time'], 0, 5) . '-' . substr($session['end_time'], 0, 5) : ''; + + $stmt = $pdo->prepare(" + SELECT au.email, au.first_name + FROM session_bookings sb + JOIN auth_users au ON sb.user_id = au.id + WHERE sb.session_id = ? AND sb.status IN ('booked','attended','rescheduled') + "); + $stmt->execute([$session_id]); + $recipients = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $subject = "Lezione cancellata - {$school_name}"; + $sent = 0; + + foreach ($recipients as $r) { + $personal_body = str_replace( + ['{nome}', '{classe}', '{data}', '{ora}'], + [$r['first_name'] ?: 'Gentile utente', $class_info, $date, $time], + $body_text + ); + $result = sendEmail($r['email'], $subject, $personal_body); + if ($result['success']) $sent++; + } + + // Cancella la lezione DOPO invio email + $stmtDel = $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 cs.id = ? AND c.school_id = ? +"); + $stmtDel->execute([$session_id, $school_id]); + + + $feedback = "
Email inviate a {$sent} partecipanti.
"; + } elseif ($action === 'skip_cancellation_email') { + $session_id = (int)($_POST['session_id'] ?? 0); + + $stmt = $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 cs.id = ? AND c.school_id = ? + "); + $stmt->execute([$session_id, $school_id]); + + $feedback = "
+ Lezione cancellata (email non inviata). + +
"; + } + + + // Marca come persa + elseif ($action === 'mark_lost') { + $booking_id = (int)($_POST['booking_id'] ?? 0); + $stmt = $pdo->prepare("UPDATE session_bookings SET status = 'lost' WHERE id = ? AND session_id IN (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 c.school_id = ?)"); + $stmt->execute([$booking_id, $school_id]); + $feedback = '
Presenza segnata come persa.
'; + } + + // Cancella prenotazione + elseif ($action === 'cancel_booking') { + $booking_id = (int)($_POST['booking_id'] ?? 0); + $stmt = $pdo->prepare("DELETE FROM session_bookings WHERE id = ? AND session_id IN (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 c.school_id = ?)"); + $stmt->execute([$booking_id, $school_id]); + $feedback = '
Prenotazione rimossa.
'; + } +} + +// Recupero lezioni future +$stmt = $pdo->prepare(" + SELECT + cs.id AS session_id, + cs.session_date, + cs.start_time, + cs.end_time, + c.name AS class_name, + ct.level, + ct.room_name, + ct.max_capacity, + t.first_name, + t.last_name, + (SELECT COUNT(*) FROM session_bookings sb WHERE sb.session_id = cs.id AND sb.status IN ('booked','attended','rescheduled')) AS booked_count, + (SELECT GROUP_CONCAT(CONCAT(sb.id,'|||',au.first_name,' ',au.last_name,'|||',au.email,'|||',COALESCE(au.phone,''),'|||',sb.status) 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','lost')) AS booked_students_details + 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 >= CURDATE() AND c.school_id = ? + ORDER BY cs.session_date, cs.start_time +"); +$stmt->execute([$school_id]); +$sessions = $stmt->fetchAll(); + +$grouped = []; +foreach ($sessions as $s) { + $date = new DateTime($s['session_date']); + $month_key = $date->format('Y-m'); + $month_name = ucfirst(strftime('%B %Y', $date->getTimestamp())); + $grouped[$month_key]['name'] = $month_name; + $grouped[$month_key]['sessions'][] = $s; +} +?> + + + + + + + + Lezioni Future - <?php echo htmlspecialchars($school_name); ?> + + + + + +
+ + + +
+
+ +
+
+
+
+ Logo +
+
+

Lezioni Future -

+

Gestione completa: lista prenotati, P/C, cancellazione con avviso email.

+
+ +
+
+
+ + + + +
+
+
Nessuna lezione programmata nel futuro.
+
+
+ + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
DataClasseLivelloOrarioSalaInsegnantePrenotatiAzioni
Non assegnato'; ?> + + + +
+
+
+
+ + + +
+
+ + + + $parts[0] ?? 0, + 'name' => $parts[1] ?? '', + 'email' => $parts[2] ?? '', + 'phone' => $parts[3] ?? '—', + 'status' => $parts[4] ?? 'booked' + ]; + } + } + ?> + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/public/userarea/my_lessons.php b/public/userarea/my_lessons.php index e34ec24..895dc99 100644 --- a/public/userarea/my_lessons.php +++ b/public/userarea/my_lessons.php @@ -5,7 +5,7 @@ if (!isset($iduserlogin)) header('Location: login.php'); $dbHandler = DBHandlerSelect::getInstance(); $pdo = $dbHandler->getConnection(); -$school_id = session('school_id'); +$school_id = $_SESSION['school_id']; if (!$school_id) die("Nessuna scuola selezionata"); $stmt = $pdo->prepare("SELECT first_name FROM auth_users WHERE id = ?"); diff --git a/public/userarea/school_dashboard.php b/public/userarea/school_dashboard.php index e98d2ef..5f9949c 100644 --- a/public/userarea/school_dashboard.php +++ b/public/userarea/school_dashboard.php @@ -828,7 +828,8 @@ $daily_sessions = $stmt->fetchAll();

Descrizione:

- Modifica Profilo + Calendario Lezioni + Modifica Profilo
diff --git a/public/userarea/select_school.php b/public/userarea/select_school.php index 990ad0f..af17b6e 100644 --- a/public/userarea/select_school.php +++ b/public/userarea/select_school.php @@ -125,7 +125,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['school_id'])) { |-------------------------------------------------------------------------- */ $stmt = $pdo->prepare(" - SELECT s.id, s.name, s.logo, s.address_city + SELECT + s.id, + s.name, + s.logo, + s.address_street, + s.address_postal_code, + s.address_city, + s.address_province, + s.address_country FROM user_schools us JOIN schools s ON us.school_id = s.id WHERE us.user_id = ? @@ -133,6 +141,7 @@ $stmt = $pdo->prepare(" AND s.status = 'active' ORDER BY s.name "); + $stmt->execute([$iduserlogin]); $userSchools = $stmt->fetchAll(); // --- VALIDAZIONE school_id: se non appartiene all'utente, la resetto --- @@ -180,7 +189,15 @@ if (count($userSchools) > 1 && !empty($_SESSION['school_id']) && !empty($_SESSIO */ if (empty($userSchools)) { $stmt = $pdo->query(" - SELECT id, name, logo, address_city + SELECT + id, + name, + logo, + address_street, + address_postal_code, + address_city, + address_province, + address_country FROM schools WHERE status = 'active' ORDER BY name @@ -346,12 +363,46 @@ if (empty($userSchools)) {
@@ -371,11 +422,17 @@ if (empty($userSchools)) {
- -

- -

+ +
+
+ +
+ +
+ +
+