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 -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 : 'assets/images/default-school-logo.png'; ?>)
+
+
+
Lezioni Future -
+
Gestione completa: lista prenotati, P/C, cancellazione con avviso email.
+
+
+
+
+
+
+
+
+
+
+
+
Nessuna lezione programmata nel futuro.
+
+
+
+
+
+
+
+
+
+
+
+ | Data |
+ Classe |
+ Livello |
+ Orario |
+ Sala |
+ Insegnante |
+ Prenotati |
+ Azioni |
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ Non assegnato'; ?> |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $parts[0] ?? 0,
+ 'name' => $parts[1] ?? '',
+ 'email' => $parts[2] ?? '',
+ 'phone' => $parts[3] ?? '—',
+ 'status' => $parts[4] ?? 'booked'
+ ];
+ }
+ }
+ ?>
+
+
+
+
+
+
+
+
+
Nessuno prenotato.
+
+
+
+
+ | Nome |
+ Email |
+ Telefono |
+ Stato |
+ Azioni |
+
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Confermi di segnare come persa la lezione per ?
+
+
+
+
+
+
+
+
+
+
+
+
Confermi di rimuovere dalla lezione?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Confermi la cancellazione della lezione:
+
+ - Classe:
+ - Data:
+ - Orario: -
+ - Prenotati:
+
+ 0): ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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:
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)) {
= htmlspecialchars($sname) ?>
-
-
- = htmlspecialchars($scity) ?>
-
+
+
+
+ = htmlspecialchars($addrLine1) ?>
+
+
+
= htmlspecialchars($addrLine2) ?>
+
+
+