fixed finances my lesson etc

This commit is contained in:
Claudio 2025-12-07 21:47:43 +01:00
parent 8c5b9a0d85
commit 70d01f160e
13 changed files with 2176 additions and 509 deletions

View File

@ -0,0 +1,332 @@
<?php
include('include/headscript.php');
if (!isset($iduserlogin)) die("Errore: utente non loggato.");
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
$stmt = $pdo->prepare("SELECT id, name FROM schools WHERE owner_id = ?");
$stmt->execute([$iduserlogin]);
$school = $stmt->fetch();
if (!$school) die("Scuola non trovata.");
$school_id = $school['id'];
// === FILTRI ===
$year = $_GET['year'] ?? date('Y');
$month = $_GET['month'] ?? null;
$start_date = $month ? "$year-$month-01" : "$year-01-01";
$end_date = $month ? date('Y-m-t', strtotime($start_date)) : "$year-12-31";
$where_date = "AND o.created_at BETWEEN ? AND ?";
$params = [$school_id, $start_date . ' 00:00:00', $end_date . ' 23:59:59'];
// === STATISTICHE FILTRATE ===
$stmt = $pdo->prepare("
SELECT
COUNT(*) as total_orders,
SUM(price) as total_revenue,
SUM(CASE WHEN payment_method = 'stripe' THEN price ELSE 0 END) as stripe_revenue,
SUM(CASE WHEN payment_method = 'paypal' THEN price ELSE 0 END) as paypal_revenue,
SUM(CASE WHEN payment_method = 'manual' THEN price ELSE 0 END) as manual_revenue
FROM orders o
WHERE o.school_id = ? AND o.status = 'completed' $where_date
");
$stmt->execute($params);
$stats = $stmt->fetch();
// === RICAVI MENSILI (per grafico) ===
$monthly = [];
$start = new DateTime($month ? $start_date : "$year-01-01");
$end = new DateTime($end_date);
$interval = new DateInterval('P1M');
$period = new DatePeriod($start, $interval, $end->modify('+1 month'));
foreach ($period as $dt) {
$m = $dt->format('Y-m');
$label = $dt->format('M Y');
$stmt = $pdo->prepare("
SELECT COALESCE(SUM(price), 0) as revenue
FROM orders
WHERE school_id = ? AND status = 'completed'
AND DATE_FORMAT(created_at, '%Y-%m') = ?
");
$stmt->execute([$school_id, $m]);
$monthly[] = ['label' => $label, 'revenue' => (float)$stmt->fetchColumn()];
}
// === DISTRIBUZIONE METODI PAGAMENTO (per torta) ===
$payment_data = [
'Stripe' => $stats['stripe_revenue'] ?? 0,
'PayPal' => $stats['paypal_revenue'] ?? 0,
'Manuale' => $stats['manual_revenue'] ?? 0
];
// === TOP 5 PRODOTTI ===
$stmt = $pdo->prepare("
SELECT p.name, pv.name as variation, COUNT(*) as vendite, SUM(o.price) as incasso
FROM orders o
JOIN products p ON o.product_id = p.id
LEFT JOIN product_variations pv ON o.variation_id = pv.id
WHERE o.school_id = ? AND o.status = 'completed' $where_date
GROUP BY o.product_id, o.variation_id
ORDER BY incasso DESC LIMIT 5
");
$stmt->execute($params);
$top_products = $stmt->fetchAll();
// === ULTIMI ORDINI ===
$stmt = $pdo->prepare("
SELECT o.*, u.first_name, u.last_name, u.email, p.name as product_name, pv.name as variation_name
FROM orders o
JOIN auth_users u ON o.user_id = u.id
JOIN products p ON o.product_id = p.id
LEFT JOIN product_variations pv ON o.variation_id = pv.id
WHERE o.school_id = ? $where_date
ORDER BY o.created_at DESC
");
$stmt->execute($params);
$recent_orders = $stmt->fetchAll();
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Finanze - <?php echo htmlspecialchars($school['name']); ?></title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.7/css/dataTables.bootstrap5.min.css">
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="container-fluid px-4">
<!-- FILTRO -->
<div class="card radius-15 shadow mb-4">
<div class="card-body">
<form method="GET" class="row g-3 align-items-end">
<div class="col-md-3">
<label>Anno</label>
<select name="year" class="form-select" onchange="this.form.submit()">
<?php for ($y = date('Y'); $y >= date('Y') - 5; $y--): ?>
<option value="<?php echo $y; ?>" <?php echo $y == $year ? 'selected' : ''; ?>><?php echo $y; ?></option>
<?php endfor; ?>
</select>
</div>
<div class="col-md-3">
<label>Mese (opzionale)</label>
<select name="month" class="form-select" onchange="this.form.submit()">
<option value="">Tutti i mesi</option>
<?php for ($m = 1; $m <= 12; $m++):
$mm = str_pad($m, 2, '0', STR_PAD_LEFT);
$name = date('F', mktime(0, 0, 0, $m, 1));
?>
<option value="<?php echo $mm; ?>" <?php echo $mm == $month ? 'selected' : ''; ?>>
<?php echo ucfirst($name); ?>
</option>
<?php endfor; ?>
</select>
</div>
<div class="col-md-3">
<button type="button" class="btn btn-outline-secondary" onclick="window.location='finances.php'">Reset</button>
</div>
</form>
</div>
</div>
<!-- TOTALE FILTRATO -->
<div class="text-center mb-5">
<h2 class="text-primary">Finanze <?php echo $month ? date('F Y', strtotime("$year-$month-01")) : "Anno $year"; ?></h2>
<h1 class="display-3 fw-bold text-success">
<?php echo number_format($stats['total_revenue'] ?? 0, 2); ?>
</h1>
</div>
<div class="row g-4 mb-5">
<div class="col-lg-4">
<div class="card h-100 shadow-sm border-0">
<div class="card-body text-center">
<h5 class="text-primary">Ordini</h5>
<h3 class="fw-bold"><?php echo $stats['total_orders'] ?? 0; ?></h3>
</div>
</div>
</div>
<div class="col-lg-8">
<div class="card h-100 shadow-sm border-0">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Distribuzione Pagamenti</h5>
</div>
<div class="card-body">
<canvas id="paymentChart"></canvas>
</div>
</div>
</div>
</div>
<div class="row g-4">
<div class="col-lg-8">
<div class="card shadow">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Andamento Ricavi</h5>
</div>
<div class="card-body">
<canvas id="revenueChart" height="120"></canvas>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card shadow h-100">
<div class="card-header bg-success text-white">
<h5 class="mb-0">Top 5 Prodotti</h5>
</div>
<div class="card-body">
<table class="table table-sm">
<tbody>
<?php foreach ($top_products as $tp): ?>
<tr>
<td>
<strong><?php echo htmlspecialchars($tp['name']); ?></strong>
<?php if ($tp['variation']): ?><br><small><?php echo htmlspecialchars($tp['variation']); ?></small><?php endif; ?>
</td>
<td class="text-end text-success fw-bold">
<?php echo number_format($tp['incasso'], 2); ?>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($top_products)): ?>
<tr>
<td class="text-center text-muted">Nessun dato</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- TABELLA ORDINI -->
<div class="card shadow mt-5">
<div class="card-header bg-dark text-white">
<h5 class="mb-0">Tutti gli ordini del periodo</h5>
</div>
<div class="card-body p-0">
<table id="ordersTable" class="table table-striped table-hover mb-0">
<thead class="table-dark">
<tr>
<th>Data</th>
<th>Ordine</th>
<th>Cliente</th>
<th>Prodotto</th>
<th class="text-end">Importo</th>
<th>Metodo</th>
</tr>
</thead>
<tbody>
<?php foreach ($recent_orders as $o): ?>
<tr>
<td><?php echo date('d/m/Y H:i', strtotime($o['created_at'])); ?></td>
<td>#<?php echo $o['order_number']; ?></td>
<td><?php echo htmlspecialchars($o['first_name'] . ' ' . $o['last_name']); ?></td>
<td><?php echo htmlspecialchars($o['product_name'] . ($o['variation_name'] ? ' - ' . $o['variation_name'] : '')); ?></td>
<td class="text-end text-success fw-bold"><?php echo number_format($o['price'], 2); ?></td>
<td>
<span class="badge bg-<?php echo $o['payment_method'] == 'stripe' ? 'primary' : ($o['payment_method'] == 'paypal' ? 'info' : 'secondary'); ?>">
<?php echo strtoupper($o['payment_method']); ?>
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.7/js/dataTables.bootstrap5.min.js"></script>
<script>
// Grafico a barre ricavi
new Chart(document.getElementById('revenueChart'), {
type: 'bar',
data: {
labels: [<?php echo "'" . implode("','", array_column($monthly, 'label')) . "'"; ?>],
datasets: [{
label: 'Ricavi',
data: [<?php echo implode(',', array_column($monthly, 'revenue')); ?>],
backgroundColor: 'rgba(0, 123, 255, 0.7)',
borderRadius: 6
}]
},
options: {
responsive: true,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
ticks: {
callback: v => '€' + v
}
}
}
}
});
// Grafico a torta pagamenti
new Chart(document.getElementById('paymentChart'), {
type: 'doughnut',
data: {
labels: ['Stripe', 'PayPal', 'Manuale'],
datasets: [{
data: [<?php echo ($stats['stripe_revenue'] ?? 0) . ',' . ($stats['paypal_revenue'] ?? 0) . ',' . ($stats['manual_revenue'] ?? 0); ?>],
backgroundColor: ['#0d6efd', '#0dcaf0', '#ffc107']
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'bottom'
}
}
}
});
// DataTable
$('#ordersTable').DataTable({
language: {
url: "//cdn.datatables.net/plug-ins/1.10.25/i18n/Italian.json"
},
pageLength: 25,
order: [
[0, 'desc']
],
responsive: true
});
</script>
</body>
</html>

View File

@ -6,55 +6,60 @@ $db = DBHandlerSelect::getInstance()->getConnection();
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL | E_STRICT);
// This should be equal to: PATH_TO_VANGUARD_FOLDER/extra/auth.php
include('../../extra/auth.php');
//require_once __DIR__ . '/extra/auth.php';
// Here we just check if user is not
// logged in, and in that case we redirect
// the user to vanguard login page.
include('../../extra/auth.php');
if (! Auth::check()) {
redirectTo('../../public/login');
}
$user = Auth::user();
$iduserlogin = $user->present()->id;
$nameuser = $user->present()->first_name;
$surnameuser = $user->present()->last_name;
$emailuser = $user->present()->email;
$avatar = $user->present()->avatar;
$iduserlogin = $user->present()->id;
$nameuser = $user->present()->first_name;
$surnameuser = $user->present()->last_name;
$emailuser = $user->present()->email;
$avatar = $user->present()->avatar;
$kindofrole = $user->present()->role_id; // <-- Questo è il ruolo (es. 1=admin, 2=teacher, 3=student, ecc.)
$kindofrole = $user->present()->role_id;
//$user = "1";
//$iduserlogin="1";
//$nameuser="Claudio";
//$emailuser="info@claudiosironi.com";
?>
<?php
// --- INIZIO: Reindirizzamento intelligente per studenti senza profilo ---
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
$_SESSION["iduserlogin"] = $iduserlogin;
$iduserlog = $_SESSION["iduserlogin"];
$_SESSION["nameuser"] = $nameuser;
$_SESSION["surnameuser"] = $surnameuser;
$_SESSION["emailuser"] = $emailuser;
$_SESSION["photouser"] = $avatar;
// Definisci qui l'ID del ruolo STUDENTE (cambialo se è diverso!)
define('ROLE_STUDENTE', 2); // Cambia 3 con il ruolo corretto del tuo studente
// Escludi alcune pagine dove NON vuoi il redirect (es. login, logout, profile)
$current_page = basename($_SERVER['PHP_SELF']);
$no_redirect_pages = ['login.php', 'logout.php', 'student_profile.php', 'register.php'];
if (
$kindofrole == ROLE_STUDENTE &&
!in_array($current_page, $no_redirect_pages) &&
!isset($_SESSION['student_profile_completed'])
) {
// Controlla se esiste il record in tabella students
$stmt = $db->prepare("SELECT id FROM students WHERE user_id = ? LIMIT 1");
$stmt->execute([$iduserlogin]);
$student_exists = $stmt->fetch();
if (!$student_exists) {
// Non ha completato il profilo → reindirizza
$_SESSION['student_profile_pending'] = true;
header("Location: student_profile.php");
exit;
} else {
// Ha già completato → segna per non controllare più
$_SESSION['student_profile_completed'] = true;
}
}
// --- FINE: Reindirizzamento intelligente ---
$_SESSION["iduserlogin"] = $iduserlogin;
$_SESSION["nameuser"] = $nameuser;
$_SESSION["surnameuser"] = $surnameuser;
$_SESSION["emailuser"] = $emailuser;
$_SESSION["photouser"] = $avatar;
$photouser = $_SESSION["photouser"];
?>
<?php //include files
//require_once(__DIR__ . '/../../languages/en/general.php');
//include("generalsettings.php");
?>

View File

@ -51,7 +51,7 @@
</a>
</li>
<li>
<a href="school-settings.php">
<a href="school_settings.php">
<div class="parent-icon"><i class="bx bx-cog"></i></div>
<div class="menu-title">Impostazioni</div>
</a>

View File

@ -329,7 +329,7 @@ $cart_count = array_sum(array_column($_SESSION['cart'], 'quantity'));
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-user fs-5"></i><span>Profile</span></a></li>
<li><a class="dropdown-item d-flex align-items-center" href="student_profile.php"><i class="bx bx-user fs-5"></i><span>Profilo Utente</span></a></li>
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-cog fs-5"></i><span>Settings</span></a></li>
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-home-circle fs-5"></i><span>Dashboard</span></a></li>
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-dollar-circle fs-5"></i><span>Earnings</span></a></li>

View File

@ -0,0 +1,257 @@
<?php
include('include/headscript.php');
if (!isset($iduserlogin)) header('Location: login.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
// Scuola corrente
$school_id = session('school_id');
if (!$school_id) die("Nessuna scuola selezionata");
// Dati utente
$stmt = $pdo->prepare("SELECT first_name FROM auth_users WHERE id = ?");
$stmt->execute([$iduserlogin]);
$user = $stmt->fetch();
// === LEZIONI FUTURE DELL'UTENTE (prenotate) ===
$stmt = $pdo->prepare("
SELECT
sb.id as booking_id,
sb.booked_at,
sb.status,
cs.session_date,
cs.start_time,
cs.end_time,
c.name as class_name,
ct.level,
ct.day_of_week,
t.first_name as teacher_name,
o.id as order_id,
o.available_entries,
o.total_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
LEFT JOIN teachers t ON cs.teacher_id = t.id
JOIN orders o ON sb.order_id = o.id
WHERE sb.user_id = ?
AND cs.school_id = ?
AND cs.session_date >= CURDATE()
ORDER BY cs.session_date ASC, cs.start_time ASC
");
$stmt->execute([$iduserlogin, $school_id]);
$bookings = $stmt->fetchAll();
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Le mie lezioni - Yogiboook</title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<style>
:root {
--pastel-blue: #94bacc;
--pastel-green: #a3d9b1;
--pastel-pink: #f8bbd0;
}
.lesson-card {
background: white;
border-radius: 18px;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
border-left: 5px solid var(--pastel-blue);
}
.lesson-card:hover {
transform: translateY(-8px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15);
}
.status-badge {
padding: 0.4em 1em;
border-radius: 50px;
font-size: 0.85rem;
font-weight: 600;
}
.btn-reschedule {
background: linear-gradient(45deg, #ff9a9e, #fad0c4);
border: none;
color: white;
border-radius: 25px;
padding: 0.5rem 1.2rem;
font-size: 0.9rem;
}
.btn-cancel {
background: #e74c3c;
color: white;
border-radius: 25px;
padding: 0.5rem 1rem;
font-size: 0.85rem;
}
</style>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content" style="background: linear-gradient(to bottom, #f8fdff, #f0f8ff);">
<div class="container-fluid px-4 pt-4">
<div class="text-center mb-5">
<h1 class="display-5 fw-bold text-primary">
Le tue lezioni future
</h1>
<p class="lead text-muted">
<?php echo $user['first_name']; ?>, ecco tutte le lezioni che hai prenotato
</p>
</div>
<?php if (empty($bookings)): ?>
<div class="text-center py-5">
<i class="bx bx-calendar-x bx-lg text-muted"></i>
<h4 class="text-muted mt-4">Nessuna lezione prenotata</h4>
<p class="text-muted">Quando acquisterai un carnet o un abbonamento, potrai prenotare qui le tue lezioni!</p>
<a href="products.php" class="btn btn-primary btn-lg mt-3">Vai ai corsi</a>
</div>
<?php else: ?>
<div class="row g-4">
<?php foreach ($bookings as $b): ?>
<div class="col-lg-6 col-xl-4">
<div class="card lesson-card h-100">
<div class="card-body p-4">
<!-- Data e ora -->
<div class="d-flex justify-content-between align-items-start mb-3">
<div>
<h5 class="mb-1"><?php echo date('d', strtotime($b['session_date'])); ?></h5>
<p class="text-muted mb-0"><?php echo ucfirst(strftime('%B %Y', strtotime($b['session_date']))); ?></p>
</div>
<span class="status-badge <?php
echo $b['status'] == 'booked' ? 'bg-success' : ($b['status'] == 'cancelled' ? 'bg-danger' : 'bg-warning');
?>">
<?php echo $b['status'] == 'booked' ? 'Prenotata' : ($b['status'] == 'cancelled' ? 'Annullata' : 'In attesa'); ?>
</span>
</div>
<!-- Dettagli lezione -->
<h4 class="mb-2"><?php echo htmlspecialchars($b['class_name']); ?></h4>
<p class="text-primary mb-2">
<?php echo ucfirst($b['level'] ?? 'Tutti i livelli'); ?>
<?php if ($b['day_of_week']): ?> • <?php echo ucfirst($b['day_of_week']); ?><?php endif; ?>
</p>
<div class="mb-3">
<p class="mb-1">
<i class="bx bx-time"></i>
<?php echo date('H:i', strtotime($b['start_time'])); ?> - <?php echo date('H:i', strtotime($b['end_time'])); ?>
</p>
<?php if ($b['teacher_name']): ?>
<p class="mb-1">
<i class="bx bx-user"></i> Con <?php echo htmlspecialchars($b['teacher_name']); ?>
</p>
<?php endif; ?>
</div>
<!-- Ingressi rimanenti -->
<div class="alert alert-light border mb-3 py-2">
<small class="d-block">
<strong>Ingressi:</strong>
<span class="text-success"><?php echo $b['available_entries']; ?></span>/<?php echo $b['total_entries']; ?>
<?php if ($b['available_recoveries'] > 0): ?>
<strong>Recuperi:</strong> <?php echo $b['available_recoveries']; ?>
<?php endif; ?>
</small>
</div>
<!-- Pulsanti azione -->
<div class="d-flex gap-2">
<?php if ($b['status'] == 'booked' && strtotime($b['session_date']) > time() + 86400): // più di 24h prima
?>
<button class="btn btn-reschedule" onclick="reschedule(<?php echo $b['booking_id']; ?>)">
Riprogramma
</button>
<button class="btn btn-cancel btn-sm" onclick="cancelBooking(<?php echo $b['booking_id']; ?>)">
Annulla
</button>
<?php else: ?>
<button class="btn btn-secondary btn-sm" disabled>
Non modificabile
</button>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
function reschedule(bookingId) {
Swal.fire({
title: 'Riprogrammare lezione?',
text: "Vuoi scegliere un nuovo orario per questa lezione?",
icon: 'question',
showCancelButton: true,
confirmButtonText: 'Sì, riprogramma',
cancelButtonText: 'Annulla'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = 'reschedule.php?booking=' + bookingId;
}
});
}
function cancelBooking(bookingId) {
Swal.fire({
title: 'Annullare prenotazione?',
text: "L'ingresso ti verrà restituito come recupero",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#e74c3c',
confirmButtonText: 'Sì, annulla',
cancelButtonText: 'No, tienila'
}).then((result) => {
if (result.isConfirmed) {
fetch('cancel_booking.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'booking_id=' + bookingId
}).then(r => r.json()).then(data => {
if (data.success) {
Swal.fire('Annullata!', 'La lezione è stata annullata e hai ricevuto un recupero.', 'success')
.then(() => location.reload());
} else {
Swal.fire('Errore', data.message, 'error');
}
});
}
});
}
</script>
</body>
</html>

227
public/userarea/orders.php Normal file
View File

@ -0,0 +1,227 @@
<?php
include('include/headscript.php');
if (!isset($iduserlogin)) die("Errore: utente non loggato.");
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
// Recupera la scuola
$stmt = $pdo->prepare("SELECT id, name FROM schools WHERE owner_id = ?");
$stmt->execute([$iduserlogin]);
$school = $stmt->fetch();
if (!$school) die("Scuola non trovata.");
$school_id = $school['id'];
// Recupera tutti gli ordini con tutti i dati necessari
$stmt = $pdo->prepare("
SELECT
o.id,
o.order_number,
o.created_at,
o.price,
o.status,
o.payment_method,
o.total_entries,
o.available_entries,
o.expiration_date,
u.first_name,
u.last_name,
u.email,
p.name AS product_name,
pv.name AS variation_name,
c.name AS class_name,
ct.level,
ct.day_of_week
FROM orders o
JOIN auth_users u ON o.user_id = u.id
JOIN products p ON o.product_id = p.id
LEFT JOIN product_variations pv ON o.variation_id = pv.id
LEFT JOIN classes c ON o.class_id = c.id
LEFT JOIN class_types ct ON o.class_type_id = ct.id
WHERE o.school_id = ?
ORDER BY o.created_at DESC
");
$stmt->execute([$school_id]);
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ordini - <?php echo htmlspecialchars($school['name']); ?></title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<!-- DataTables CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.7/css/dataTables.bootstrap5.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.5.0/css/responsive.bootstrap5.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.4.2/css/buttons.bootstrap5.min.css">
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="container-fluid px-1">
<div class="card radius-15 shadow-lg mb-4">
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
<h4 class="mb-0">
Gestione Ordini
<span class="badge bg-light text-dark ms-2"><?php echo count($orders); ?></span>
</h4>
<div>
<button class="btn btn-light btn-sm" onclick="table.buttons().export()">
Esporta
</button>
</div>
</div>
</div>
<div class="card radius-15 shadow">
<div class="card-body p-0">
<div class="table-responsive">
<table id="ordersTable" class="table table-striped table-hover" style="width:100%">
<thead class="table-dark">
<tr>
<th>Data</th>
<th>Ordine #</th>
<th>Cliente</th>
<th>Email</th>
<th>Prodotto</th>
<th>Variazione</th>
<th>Prezzo</th>
<th>Ingressi</th>
<th>Scadenza</th>
<th>Stato</th>
<th>Pagamento</th>
<th>Lezione</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($orders as $o): ?>
<tr>
<td data-order="<?php echo $o['created_at']; ?>">
<strong><?php echo date('d/m/Y', strtotime($o['created_at'])); ?></strong><br>
<small class="text-muted"><?php echo date('H:i', strtotime($o['created_at'])); ?></small>
</td>
<td><strong>#<?php echo $o['order_number']; ?></strong></td>
<td><?php echo htmlspecialchars($o['first_name'] . ' ' . $o['last_name']); ?></td>
<td>
<a href="mailto:<?php echo htmlspecialchars($o['email']); ?>">
<?php echo htmlspecialchars($o['email']); ?>
</a>
</td>
<td><?php echo htmlspecialchars($o['product_name']); ?></td>
<td><?php echo htmlspecialchars($o['variation_name'] ?: '-'); ?></td>
<td><strong><?php echo number_format($o['price'], 2); ?></strong></td>
<td>
<?php echo $o['total_entries'] ? $o['available_entries'] . '/' . $o['total_entries'] : 'Illimitati'; ?>
</td>
<td>
<?php if ($o['expiration_date']): ?>
<span class="text-danger fw-bold"><?php echo date('d/m/Y', strtotime($o['expiration_date'])); ?></span>
<?php else: ?>
<em>Nessuna</em>
<?php endif; ?>
</td>
<td>
<span class="badge <?php echo $o['status'] == 'completed' ? 'bg-success' : ($o['status'] == 'pending' ? 'bg-warning' : 'bg-secondary'); ?>">
<?php echo ucfirst($o['status']); ?>
</span>
</td>
<td>
<span class="badge bg-info"><?php echo strtoupper($o['payment_method']); ?></span>
</td>
<td>
<?php if ($o['class_name']): ?>
<small>
<strong><?php echo htmlspecialchars($o['class_name']); ?></strong><br>
<?php echo ucfirst($o['level'] ?? ''); ?>
(<?php echo ucfirst($o['day_of_week'] ?? 'qualsiasi'); ?>)
</small>
<?php else: ?>
<em>Tutte le classi</em>
<?php endif; ?>
</td>
<td>
<div class="btn-group" role="group">
<button type="button" class="btn btn-sm btn-outline-primary">Dettaglio</button>
<button type="button" class="btn btn-sm btn-outline-success">Prenotazioni</button>
<button type="button" class="btn btn-sm btn-outline-warning">Email</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<!-- DataTables + Plugin -->
<script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.7/js/dataTables.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.5.0/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.5.0/js/responsive.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.bootstrap5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.html5.min.js"></script>
<script>
$(document).ready(function() {
$('#ordersTable').DataTable({
language: {
url: "//cdn.datatables.net/plug-ins/1.10.25/i18n/Italian.json"
},
pageLength: 25,
lengthMenu: [10, 25, 50, 100],
order: [
[0, 'desc']
],
responsive: true,
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
text: 'Esporta Excel',
className: 'btn btn-success btn-sm'
},
{
extend: 'csvHtml5',
text: 'Esporta CSV',
className: 'btn btn-info btn-sm'
}
],
columnDefs: [{
targets: '_all',
className: 'text-center'
},
{
targets: 12,
orderable: false
}
]
});
});
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -29,6 +29,25 @@ if (!$school) {
$school_id = $school['id'];
$school_name = $school['name'];
// === RECUPERA IMPOSTAZIONI SCUOLA (valori predefiniti) ===
$stmt = $pdo->prepare("SELECT * FROM school_settings WHERE school_id = ?");
$stmt->execute([$school_id]);
$school_settings = $stmt->fetch() ?: [
'allow_freeze_global' => 1,
'freeze_max_days_global' => 30,
'auto_propagate_on_purchase' => 1,
'allow_full_access_rebooking' => 1,
'allowed_product_types' => 'subscription,carnet,drop_in'
];
// === PREPARA I TIPI DI PRODOTTO CONSENTITI ===
$allowed_types = array_filter(explode(',', $school_settings['allowed_product_types'] ?? 'subscription,carnet,drop_in'));
$types_map = [
'subscription' => 'Abbonamento',
'carnet' => 'Carnet',
'drop_in' => 'Lezione Singola'
];
// Recupera i prodotti della scuola con variazioni, classi e variazioni associate
$stmt = $pdo->prepare("
SELECT p.*,
@ -446,6 +465,18 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
font-style: italic;
/* Rende il nome del prodotto in corsivo per le variazioni */
}
.precompiled-field {
background-color: #fff8c4 !important;
/* giallo chiaro, elegante */
border: 1px solid #ffe08c;
}
.precompiled-field:focus {
background-color: #fffce6 !important;
/* un po' più chiaro quando scrivi */
box-shadow: 0 0 0 0.2rem rgba(255, 200, 0, 0.25);
}
</style>
</head>
@ -690,10 +721,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<div class="col-md-6">
<label class="form-label">Tipo <span class="text-danger">*</span></label>
<select class="form-select" name="type" required>
<option value="carnet">Carnet</option>
<option value="subscription">Abbonamento</option>
<option value="drop_in">Lezione Singola</option>
<select class="form-select precompiled-field" name="type" required>
<?php foreach ($allowed_types as $type): ?>
<?php if (isset($types_map[$type])): ?>
<option value="<?php echo $type; ?>">
<?php echo $types_map[$type]; ?>
</option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
@ -732,29 +767,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<div class="col-md-6">
<label class="form-label">Permetti congelamento</label>
<select class="form-select" name="allow_freeze">
<option value="0">No</option>
<option value="1"></option>
<select class="form-select precompiled-field" name="allow_freeze">
<option value="0" <?php echo !$school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>No</option>
<option value="1" <?php echo $school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>Sì</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Giorni max congelamento</label>
<input type="number" class="form-control" name="freeze_max_days">
<input type="number" class="form-control precompiled-field" name="freeze_max_days"
value="<?php echo $school_settings['freeze_max_days_global']; ?>">
</div>
<div class="col-md-6">
<label class="form-label">Accesso completo a tutte le classi</label>
<select class="form-select" id="add_product_is_full_access" name="is_full_access" onchange="toggleClassTypesSection(this.value, 'add')">
<option value="0">No</option>
<option value="1"></option>
<select class="form-select precompiled-field" id="add_product_is_full_access" name="is_full_access" onchange="toggleClassTypesSection(this.value, 'add')">
<option value="0" <?php echo !$school_settings['allow_full_access_rebooking'] ? 'selected' : ''; ?>>No</option>
<option value="1" <?php echo $school_settings['allow_full_access_rebooking'] ? 'selected' : ''; ?>>Sì</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Propaga automaticamente all'ordine</label>
<select class="form-select" name="auto_propagate_to_order">
<option value="0">No</option>
<option value="1"></option>
<select class="form-select precompiled-field" name="auto_propagate_to_order">
<option value="0" <?php echo !$school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>No</option>
<option value="1" <?php echo $school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>Sì</option>
</select>
</div>
@ -858,21 +894,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
</div>
<div class="col-md-6 mb-3">
<label for="add_variation_allow_freeze" class="form-label">Permetti Congelamento</label>
<select class="form-control" id="add_variation_allow_freeze" name="allow_freeze">
<option value="0">No</option>
<option value="1"></option>
<select class="form-select precompiled-field" name="allow_freeze">
<option value="0" <?php echo !$school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>No</option>
<option value="1" <?php echo $school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>Sì</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="add_variation_freeze_max_days" class="form-label">Giorni Massimi di Congelamento</label>
<input type="number" class="form-control" id="add_variation_freeze_max_days" name="freeze_max_days">
<input type="number" class="form-control precompiled-field" name="freeze_max_days"
value="<?php echo $school_settings['freeze_max_days_global']; ?>">
<small class="form-text text-muted">Lascia vuoto se non applicabile.</small>
</div>
<div class="col-md-6 mb-3">
<label for="add_variation_auto_propagate" class="form-label">Propaga in Automatico all'Ordine</label>
<select class="form-control" id="add_variation_auto_propagate" name="auto_propagate_to_order">
<option value="0">No</option>
<option value="1"></option>
<select class="form-select precompiled-field" name="auto_propagate_to_order">
<option value="0" <?php echo !$school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>No</option>
<option value="1" <?php echo $school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>Sì</option>
</select>
<small class="form-text text-muted">Se , la variazione verrà aggiunta automaticamente agli ordini futuri.</small>
</div>
@ -934,11 +971,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<input type="text" class="form-control" id="edit_product_variation_name" name="variation_name">
</div>
<div class="col-md-6 mb-3">
<label for="edit_product_type" class="form-label">Tipo</label>
<select class="form-control" id="edit_product_type" name="type" required>
<option value="carnet">Carnet</option>
<option value="subscription">Abbonamento</option>
<option value="drop_in">Lezione Singola</option>
<label class="form-label">Tipo <span class="text-danger">*</span></label>
<select class="form-select precompiled-field" name="type" required>
<?php foreach ($allowed_types as $type): ?>
<?php if (isset($types_map[$type])): ?>
<option value="<?php echo $type; ?>">
<?php echo $types_map[$type]; ?>
</option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6 mb-3" id="edit_price_section">

View File

@ -1,135 +1,204 @@
<?php
require_once 'include/headscript.php'; // Include il file con la connessione al database
require_once 'include/headscript.php';
// Connessione al database
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
// Funzioni di colore per terminale (se lo lanci da CLI)
function green($text)
{
return "\033[32m$text\033[0m";
}
function yellow($text)
{
return "\033[33m$text\033[0m";
}
function red($text)
{
return "\033[31m$text\033[0m";
}
function cyan($text)
{
return "\033[36m$text\033[0m";
}
function magenta($text)
{
return "\033[35m$text\033[0m";
}
echo cyan("=== AVVIO PROPAGAZIONE AUTOMATICA - " . date('Y-m-d H:i:s') . " ===\n");
try {
// Inizia una transazione
$pdo->beginTransaction();
// Seleziona gli ordini con status 'completed' e lezioni disponibili
$stmt = $pdo->prepare("
SELECT o.id, o.user_id, o.class_type_id, o.available_entries, o.school_id
FROM orders o
WHERE o.status = 'completed' AND o.available_entries > 0
");
$stmt->execute();
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
$totalBookings = 0;
$totalOrders = 0;
$bookings_created = 0;
$orders_propagated = 0;
$orderSql = "
SELECT o.id, o.order_number, o.user_id, o.school_id, o.available_entries,
o.product_id, o.variation_id, o.activation_date,
p.name as product_name,
pv.name as variation_name,
u.email as user_email
FROM orders o
INNER JOIN products p ON o.product_id = p.id
LEFT JOIN product_variations pv ON o.variation_id = pv.id AND pv.id IS NOT NULL
LEFT JOIN auth_users u ON o.user_id = u.id
WHERE o.status = 'completed'
AND o.available_entries > 0
AND (p.auto_propagate_to_order = 1 OR pv.auto_propagate_to_order = 1)
AND (o.activation_date IS NULL OR o.activation_date <= CURDATE())
ORDER BY o.created_at ASC
";
$orderStmt = $pdo->prepare($orderSql);
$orderStmt->execute();
$orders = $orderStmt->fetchAll(PDO::FETCH_ASSOC);
echo yellow("Trovati " . count($orders) . " ordini da propagare automaticamente.\n\n");
foreach ($orders as $order) {
$order_id = $order['id'];
$user_id = $order['user_id'];
$class_type_id = $order['class_type_id'];
$available_entries = $order['available_entries'];
$school_id = $order['school_id'];
$totalOrders++;
$orderId = $order['id'];
$orderNumber = $order['order_number'];
$userId = $order['user_id'];
$userEmail = $order['user_email'];
$schoolId = $order['school_id'];
$remaining = (int)$order['available_entries'];
$productName = $order['variation_name'] ?? $order['product_name'];
$activation = $order['activation_date'] ?: 'immediata';
// Recupera i giorni di chiusura della scuola
$offStmt = $pdo->prepare("
SELECT start_date, end_date
FROM day_off
WHERE school_id = ? AND (
(start_date >= CURDATE()) OR
(end_date >= CURDATE()) OR
(start_date <= CURDATE() AND end_date >= CURDATE())
)
");
$offStmt->execute([$school_id]);
$off_periods = $offStmt->fetchAll(PDO::FETCH_ASSOC);
echo magenta("──────────────────────────────────────────────────────\n");
echo green("ELABORAZIONE ORDINE #$orderNumber (ID: $orderId)\n");
echo green("Utente: $userEmail (ID: $userId) | Scuola ID: $schoolId\n");
echo green("Prodotto: $productName | Ingressi da propagare: $remaining | Attivazione: $activation\n");
// Crea un array di date di chiusura
$off_dates = [];
foreach ($off_periods as $period) {
$start_date = new DateTime($period['start_date']);
$end_date = new DateTime($period['end_date']);
$interval = new DateInterval('P1D');
$date_range = new DatePeriod($start_date, $interval, $end_date->modify('+1 day'));
foreach ($date_range as $date) {
$off_dates[] = $date->format('Y-m-d');
}
// Recupera class_type consentiti
$ctSql = "SELECT DISTINCT class_type_id FROM product_class_types WHERE product_id = ? AND (variation_id IS NULL OR variation_id = ? OR variation_id = ?)";
$ctStmt = $pdo->prepare($ctSql);
$ctStmt->execute([$order['product_id'], $order['variation_id'], $order['variation_id']]);
$classTypeIds = $ctStmt->fetchAll(PDO::FETCH_COLUMN);
if (empty($classTypeIds)) {
echo red("Nessun class_type associato al prodotto → SKIP\n");
continue;
}
// Trova le prossime sessioni disponibili per questo class_type_id
$sessionStmt = $pdo->prepare("
SELECT id, session_date
FROM class_sessions
WHERE class_type_id = ? AND session_date >= CURDATE() AND status = 'scheduled'
ORDER BY session_date ASC, start_time ASC
LIMIT ?
");
$sessionStmt->execute([$class_type_id, $available_entries]);
// Nomi delle classi per debug - VERSIONE MIGLIORE
$placeholders = str_repeat('?,', count($classTypeIds) - 1) . '?';
$namesSql = "
SELECT ct.id, CONCAT(c.name, ' - ', ct.level, ' ',
CASE ct.day_of_week
WHEN 'monday' THEN 'Lun'
WHEN 'tuesday' THEN 'Mar'
WHEN 'wednesday' THEN 'Mer'
WHEN 'thursday' THEN 'Gio'
WHEN 'friday' THEN 'Ven'
WHEN 'saturday' THEN 'Sab'
WHEN 'sunday' THEN 'Dom'
END, ' ', TIME_FORMAT(ct.start_time, '%H:%i')
) as name
FROM class_types ct
JOIN classes c ON ct.class_id = c.id
WHERE ct.id IN ($placeholders)
ORDER BY name
";
$namesStmt = $pdo->prepare($namesSql);
$namesStmt->execute($classTypeIds);
$classNames = $namesStmt->fetchAll(PDO::FETCH_KEY_PAIR);
echo cyan("Classi consentite (" . count($classTypeIds) . "): " . implode(', ', array_values($classNames)) . "\n");
// Giorni di chiusura
$offStmt = $pdo->prepare("SELECT start_date, end_date FROM day_off WHERE school_id = ? AND end_date >= CURDATE()");
$offStmt->execute([$schoolId]);
$offDates = [];
foreach ($offStmt->fetchAll() as $off) {
$start = new DateTime($off['start_date']);
$end = new DateTime($off['end_date']);
$end->modify('+1 day');
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
foreach ($period as $d) $offDates[$d->format('Y-m-d')] = true;
}
// Tutte le sessioni future
$sessionSql = "
SELECT cs.id, cs.session_date, cs.start_time, cs.max_capacity, cs.class_type_id,
(SELECT COUNT(*) FROM session_bookings sb
WHERE sb.session_id = cs.id
AND sb.status IN ('booked','attended','rescheduled')) as booked
FROM class_sessions cs
WHERE cs.class_type_id IN ($placeholders)
AND cs.school_id = ?
AND cs.session_date >= ?
AND cs.status = 'scheduled'
ORDER BY cs.session_date ASC, cs.start_time ASC
LIMIT 2000
";
$fromDate = $order['activation_date'] ?: date('Y-m-d');
$params = array_merge($classTypeIds, [$schoolId, $fromDate]);
$sessionStmt = $pdo->prepare($sessionSql);
$sessionStmt->execute($params);
$sessions = $sessionStmt->fetchAll(PDO::FETCH_ASSOC);
$bookings_for_order = 0;
echo yellow("Trovate " . count($sessions) . " lezioni future per queste classi.\n");
foreach ($sessions as $session) {
$session_id = $session['id'];
$session_date = $session['session_date'];
$bookedThisOrder = 0;
// Salta se la data è un giorno di chiusura
if (in_array($session_date, $off_dates)) {
foreach ($sessions as $s) {
if ($remaining <= 0) break;
$date = $s['session_date'];
$time = substr($s['start_time'], 0, 5);
$className = $classNames[$s['class_type_id']] ?? 'Sconosciuta';
if (isset($offDates[$date])) {
echo " ⚠️ $date $time$className → GIORNO DI CHIUSURA → saltata\n";
continue;
}
// Verifica la capacità massima della sessione
$capacityStmt = $pdo->prepare("
SELECT max_capacity
FROM class_sessions
WHERE id = ?
");
$capacityStmt->execute([$session_id]);
$max_capacity = $capacityStmt->fetchColumn();
$free = $s['max_capacity'] ? ($s['max_capacity'] - $s['booked']) : 999;
$bookingCountStmt = $pdo->prepare("
SELECT COUNT(*)
FROM session_bookings
WHERE session_id = ? AND status IN ('booked', 'attended', 'rescheduled')
");
$bookingCountStmt->execute([$session_id]);
$current_bookings = $bookingCountStmt->fetchColumn();
if ($max_capacity !== null && $current_bookings >= $max_capacity) {
continue; // Salta se la sessione è piena
if ($free <= 0) {
echo red(" FULL $date $time$className (Posti: {$s['booked']}/{$s['max_capacity']}) → saltata\n");
continue;
}
// Inserisci la prenotazione in session_bookings
$insertStmt = $pdo->prepare("
INSERT INTO session_bookings (
session_id, user_id, status, booked_at, created_at, updated_at
)
VALUES (?, ?, 'booked', NOW(), NOW(), NOW())
");
$insertStmt->execute([
$session_id,
$user_id
]);
$bookings_created++;
$bookings_for_order++;
// PRENOTA!
$insert = $pdo->prepare("INSERT INTO session_bookings
(session_id, user_id, order_id, status, booked_at, created_at, updated_at)
VALUES (?, ?, ?, 'booked', NOW(), NOW(), NOW())");
$insert->execute([$s['id'], $userId, $orderId]);
$totalBookings++;
$bookedThisOrder++;
$remaining--;
echo green(" PRENOTATA $date $time$className | Posto libero: $free → rimanenti da propagare: $remaining\n");
}
// Aggiorna available_entries e lo stato dell'ordine
if ($bookings_for_order > 0) {
$updateStmt = $pdo->prepare("
UPDATE orders
SET available_entries = available_entries - ?,
status = 'propagated'
WHERE id = ?
");
$updateStmt->execute([$bookings_for_order, $order_id]);
$orders_propagated++;
// Aggiornamento ordine
if ($bookedThisOrder > 0) {
$newStatus = ($remaining <= 0) ? 'propagated' : 'completed';
$pdo->prepare("UPDATE orders SET available_entries = ?, status = ? WHERE id = ?")
->execute([$remaining, $newStatus, $orderId]);
echo green("Ordine aggiornato: available_entries = $remaining | status = $newStatus\n");
} else {
echo yellow("Nessuna lezione disponibile al momento → ci riproverà alla prossima esecuzione\n");
}
echo magenta("──────────────────────────────────────────────────────\n\n");
}
// Conferma la transazione
$pdo->commit();
echo "Propagazione completata con successo: $bookings_created prenotazioni create, $orders_propagated ordini aggiornati.";
} catch (PDOException $e) {
// In caso di errore, annulla la transazione
echo cyan("=== PROPAGAZIONE COMPLETATA ===\n");
echo green("Ordini processati: $totalOrders\n");
echo green("Prenotazioni automatiche create: $totalBookings\n");
echo cyan("Fine esecuzione: " . date('Y-m-d H:i:s') . "\n");
} catch (Exception $e) {
$pdo->rollBack();
echo "Errore durante la propagazione: " . $e->getMessage();
echo red("ERRORE CRITICO: " . $e->getMessage() . "\n");
error_log("Auto-propagate error: " . $e->getMessage());
}

View File

@ -843,12 +843,12 @@ $daily_sessions = $stmt->fetchAll();
<span class="fs-6">Situazione Clienti</span>
</a>
<!-- Pulsante Ordini -->
<a href="#" class="btn btn-success d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<a href="orders.php" class="btn btn-success d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-cart me-2" style="font-size: 20px;"></i>
<span class="fs-6">Ordini</span>
</a>
<!-- Pulsante Finanze -->
<a href="#" class="btn btn-warning d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<a href="finances.php" class="btn btn-warning d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-dollar me-2" style="font-size: 20px;"></i>
<span class="fs-6">Finanze</span>
</a>
@ -867,7 +867,7 @@ $daily_sessions = $stmt->fetchAll();
<span class="fs-6">Giorni di Chiusura</span>
</a>
<!-- Pulsante Impostazioni -->
<a href="#" class="btn btn-dark d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<a href="school_settings.php" class="btn btn-dark d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
<i class="bx bx-cog me-2" style="font-size: 20px;"></i>
<span class="fs-6">Impostazioni</span>
</a>
@ -1076,73 +1076,126 @@ $daily_sessions = $stmt->fetchAll();
</div>
</div>
</div>
<!-- Sezione Sessioni della Giornata -->
<!-- Sezione Sessioni (Singolo giorno o Intervallo) -->
<div class="card radius-10 mb-4">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0">Sessioni della Giornata</h6>
</div>
<div class="ms-auto">
<form action="" method="GET" class="d-flex align-items-center">
<label for="session_date" class="me-2">Seleziona Data:</label>
<input type="date" id="session_date" name="session_date" class="form-control" value="<?php echo htmlspecialchars($selected_date); ?>" onchange="this.form.submit()">
<div class="d-flex align-items-center justify-content-between">
<h6 class="mb-0">Sessioni Programmata</h6>
<div class="d-flex gap-2">
<!-- I tuoi filtri data esistenti -->
<form action="" method="GET" class="d-flex flex-wrap align-items-center gap-2">
<div class="d-flex align-items-center gap-2">
<label class="me-2 mb-0 text-nowrap">Dal:</label>
<input type="date" name="start_date" class="form-control form-control-sm" value="<?php echo $_GET['start_date'] ?? date('Y-m-d'); ?>" required>
</div>
<div class="d-flex align-items-center gap-2">
<label class="me-2 mb-0 text-nowrap">Al:</label>
<input type="date" name="end_date" class="form-control form-control-sm" value="<?php echo $_GET['end_date'] ?? ''; ?>">
</div>
<button type="submit" class="btn btn-primary btn-sm">Mostra</button>
<?php if (isset($_GET['start_date'])): ?>
<a href="?" class="btn btn-outline-secondary btn-sm">Oggi</a>
<?php endif; ?>
</form>
<!-- PULSANTE CALENDARIO -->
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#calendarModal">
<i class="bx bx-calendar"></i> Vista Calendario
</button>
</div>
</div>
</div>
<div class="card-body">
<?php
// Determina le date da mostrare
$start_date = $_GET['start_date'] ?? date('Y-m-d');
$end_date = $_GET['end_date'] ?? $start_date;
if ($end_date < $start_date) {
echo '<div class="alert alert-warning">La data di fine non può essere precedente alla data di inizio.</div>';
$end_date = $start_date;
}
// Recupera tutte le sessioni nell'intervallo
$stmt = $pdo->prepare("
SELECT cs.*,
ct.level, ct.day_of_week, ct.start_time, ct.room_name, ct.teacher_id,
c.name AS class_name, c.photo AS class_photo,
ct.photo AS variation_photo,
t.first_name AS teacher_first_name, t.last_name AS teacher_last_name
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 BETWEEN ? AND ?
AND c.school_id = ?
ORDER BY cs.session_date, cs.start_time
");
$stmt->execute([$start_date, $end_date, $school_id]);
$range_sessions = $stmt->fetchAll();
?>
<div class="mb-3">
<strong>
<?php if ($start_date === $end_date): ?>
Sessioni del <span class="text-primary"><?php echo date('d/m/Y', strtotime($start_date)); ?></span>
<?php else: ?>
Sessioni dal <span class="text-primary"><?php echo date('d/m/Y', strtotime($start_date)); ?></span>
al <span class="text-primary"><?php echo date('d/m/Y', strtotime($end_date)); ?></span>
(<?php echo count($range_sessions); ?> totali)
<?php endif; ?>
</strong>
</div>
<div class="table-responsive">
<table id="dailySessionsTable" class="table table-striped table-bordered">
<thead>
<tr>
<th>Data</th>
<th>Classe</th>
<th>Variazione</th>
<th>Livello</th>
<th>Orario</th>
<th>Sala</th>
<th>Insegnante</th>
<th>Foto</th>
<th>Stato</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php if (empty($daily_sessions)): ?>
<?php if (empty($range_sessions)): ?>
<tr>
<td colspan="8" class="text-center text-muted">Nessuna sessione trovata per questa data.</td>
<td colspan="8" class="text-center text-muted">
Nessuna sessione programmata in questo intervallo.
</td>
</tr>
<?php else: ?>
<?php foreach ($daily_sessions as $session): ?>
<?php
$current_date = '';
foreach ($range_sessions as $session):
$session_date = $session['session_date'];
if ($session_date !== $current_date):
$current_date = $session_date;
?>
<tr class="table-info">
<td colspan="8" class="fw-bold text-dark">
<?php echo date('d/m/Y (l)', strtotime($session_date)); ?>
</td>
</tr>
<?php endif; ?>
<tr>
<td><?php echo date('d/m', strtotime($session_date)); ?></td>
<td><?php echo htmlspecialchars($session['class_name']); ?></td>
<td><?php echo ucfirst($session['level']); ?></td>
<td><?php echo substr($session['start_time'], 0, 5); ?> - <?php echo substr($session['end_time'], 0, 5); ?></td>
<td><?php echo htmlspecialchars($session['room_name'] ?? '—'); ?></td>
<td>
<?php echo htmlspecialchars(ucfirst($session['level'])); ?>
(<?php echo htmlspecialchars(ucfirst($session['day_of_week'])); ?>)
<?php echo $session['teacher_id'] ? htmlspecialchars($session['teacher_first_name'] . ' ' . $session['teacher_last_name']) : '<em>Non assegnato</em>'; ?>
</td>
<td>
<?php echo htmlspecialchars($session['start_time']); ?> -
<?php echo htmlspecialchars($session['end_time']); ?>
</td>
<td><?php echo htmlspecialchars($session['room_name'] ?? 'Non specificata'); ?></td>
<td>
<?php if ($session['teacher_id']): ?>
<?php echo htmlspecialchars($session['teacher_first_name'] . ' ' . $session['teacher_last_name']); ?>
<?php else: ?>
Non assegnato
<?php endif; ?>
</td>
<td>
<?php
$photo = $session['variation_photo'] ?? $session['class_photo'];
if ($photo): ?>
<img src="<?php echo htmlspecialchars($photo); ?>" alt="Foto" style="max-width: 50px; max-height: 50px;">
<?php else: ?>
Nessuna foto
<?php endif; ?>
</td>
<td>
<span class="badge <?php echo $session['status'] === 'scheduled' ? 'bg-info' : ($session['status'] === 'completed' ? 'bg-success' : 'bg-danger'); ?>">
<?php echo htmlspecialchars(ucfirst($session['status'])); ?>
<span class="badge <?php
echo $session['status'] === 'scheduled' ? 'bg-info' : ($session['status'] === 'completed' ? 'bg-success' : 'bg-danger');
?>">
<?php echo $session['status'] === 'scheduled' ? 'Programmata' : ($session['status'] === 'completed' ? 'Completata' : 'Annullata'); ?>
</span>
</td>
<td>
@ -1155,14 +1208,13 @@ $daily_sessions = $stmt->fetchAll();
"end_time" => $session['end_time'],
"teacher_id" => $session['teacher_id'],
"status" => $session['status']
]); ?>)'
data-bs-toggle="tooltip" data-bs-placement="top" title="Modifica">
]); ?>)'>
<i class="bx bx-edit"></i>
</button>
<form action="" method="POST" style="display:inline;" onsubmit="return confirm('Sei sicuro di voler eliminare questa sessione?');">
<form action="" method="POST" style="display:inline;" onsubmit="return confirm('Eliminare questa sessione?');">
<input type="hidden" name="action" value="delete_session">
<input type="hidden" name="id" value="<?php echo $session['id']; ?>">
<button type="submit" class="btn btn-sm btn-danger" data-bs-toggle="tooltip" data-bs-placement="top" title="Elimina">
<button type="submit" class="btn btn-sm btn-danger">
<i class="bx bx-trash"></i>
</button>
</form>
@ -1682,6 +1734,135 @@ $daily_sessions = $stmt->fetchAll();
document.getElementById('edit_session_status').value = data.status;
}
</script>
<!-- MODALE CALENDARIO (GRANDE MA NON FULLSCREEN + FIXATO) -->
<div class="modal fade" id="calendarModal" tabindex="-1" aria-labelledby="calendarModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-scrollable" style="max-width: 95vw;">
<div class="modal-content" style="height: 95vh;">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" id="calendarModalLabel">
Calendario Lezioni
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-0 d-flex flex-column" style="height: 100%;">
<div id="fullcalendar-modal" class="flex-grow-1"></div>
</div>
</div>
</div>
</div>
<!-- FullCalendar CDN -->
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/main.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/main.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/locales/it.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
let calendar = null;
const modalElement = document.getElementById('calendarModal');
const calendarEl = document.getElementById('fullcalendar-modal');
// Funzione per inizializzare o aggiornare il calendario
function initCalendar() {
if (calendar) {
calendar.destroy();
}
calendar = new FullCalendar.Calendar(calendarEl, {
locale: 'it',
initialView: 'timeGridWeek',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek'
},
buttonText: {
today: 'Oggi',
month: 'Mese',
week: 'Settimana'
},
height: '100%',
slotMinTime: '06:00:00',
slotMaxTime: '23:00:00',
events: [
<?php
$from = date('Y-m-d');
$to = date('Y-m-d', strtotime('+90 days'));
$stmt = $pdo->prepare("
SELECT cs.session_date, cs.start_time, cs.end_time, cs.status,
c.name AS class_name, ct.level, ct.room_name,
t.first_name, t.last_name
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 BETWEEN ? AND ?
AND c.school_id = ?
");
$stmt->execute([$from, $to, $school_id]);
foreach ($stmt->fetchAll() as $e) {
$title = $e['class_name'];
if ($e['level']) $title .= ' - ' . ucfirst($e['level']);
if ($e['first_name']) $title .= ' (' . $e['first_name'] . ')';
if ($e['room_name']) $title .= ' | ' . $e['room_name'];
$color = '#0d6efd';
if ($e['status'] === 'completed') $color = '#198754';
if ($e['status'] === 'cancelled') $color = '#dc3545';
echo "{
title: '" . addslashes($title) . "',
start: '{$e['session_date']}T{$e['start_time']}',
end: '{$e['session_date']}T{$e['end_time']}',
color: '$color'
}, ";
}
?>
],
eventClick: function(info) {
const date = info.event.start.toISOString().split('T')[0];
window.location.href = '?start_date=' + date + '&end_date=' + date;
}
});
calendar.render();
}
// Apri il modale → inizializza e forza resize
modalElement.addEventListener('shown.bs.modal', function() {
initCalendar();
setTimeout(() => calendar.updateSize(), 100);
});
// Se chiudi e riapri, ricarica
modalElement.addEventListener('hidden.bs.modal', function() {
if (calendar) {
calendar.destroy();
calendar = null;
}
});
});
</script>
<style>
#fullcalendar-modal .fc-header-toolbar {
margin-bottom: 15px;
}
#fullcalendar-modal .fc-button {
border-radius: 6px !important;
}
#fullcalendar-modal .fc-event {
border: none;
border-radius: 6px;
padding: 3px 6px;
font-size: 0.9em;
white-space: normal;
}
</style>
</body>
</html>

View File

@ -0,0 +1,291 @@
<?php
include('include/headscript.php');
if (!isset($iduserlogin)) die("Errore: utente non loggato.");
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
// Recupera la scuola
$stmt = $pdo->prepare("SELECT id, name FROM schools WHERE owner_id = ?");
$stmt->execute([$iduserlogin]);
$school = $stmt->fetch();
if (!$school) die("Scuola non trovata.");
$school_id = $school['id'];
// Recupera i settings (anche se non esistono ancora)
$stmt = $pdo->prepare("SELECT * FROM school_settings WHERE school_id = ?");
$stmt->execute([$school_id]);
$settings = $stmt->fetch();
$is_new = !$settings;
$success_message = $error = "";
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// === Aspetto ===
$header_color = $_POST['header_color'] ?? '#ffffff';
$sidebar_color = $_POST['sidebar_color'] ?? '#ffffff';
$currency_code = strtoupper(trim($_POST['currency_code'] ?? 'EUR'));
$enable_notifications = !empty($_POST['enable_notifications']) ? 1 : 0;
// === Metodi di pagamento (multipli) ===
$payment_methods_array = $_POST['payment_methods'] ?? ['manual'];
$payment_methods = implode(',', array_unique(array_filter($payment_methods_array)));
if (empty($payment_methods)) $payment_methods = 'manual'; // sicurezza
// === Impostazioni prodotti ===
$allow_freeze_global = !empty($_POST['allow_freeze_global']) ? 1 : 0;
$freeze_max_days_global = $allow_freeze_global ? max(0, (int)($_POST['freeze_max_days_global'] ?? 30)) : 0;
$auto_propagate_on_purchase = !empty($_POST['auto_propagate_on_purchase']) ? 1 : 0;
$allow_full_access_rebooking = !empty($_POST['allow_full_access_rebooking']) ? 1 : 0;
// Tipi di prodotto consentiti
$product_types = [];
if (!empty($_POST['allow_subscription'])) $product_types[] = 'subscription';
if (!empty($_POST['allow_carnet'])) $product_types[] = 'carnet';
if (!empty($_POST['allow_drop_in'])) $product_types[] = 'drop_in';
$allowed_product_types = !empty($product_types) ? implode(',', $product_types) : 'none';
// === SALVATAGGIO ===
try {
if ($is_new) {
$stmt = $pdo->prepare("
INSERT INTO school_settings (
school_id, header_color, sidebar_color, payment_methods, currency_code, enable_notifications,
allow_freeze_global, freeze_max_days_global, auto_propagate_on_purchase,
allow_full_access_rebooking, allowed_product_types
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$stmt->execute([
$school_id,
$header_color,
$sidebar_color,
$payment_methods,
$currency_code,
$enable_notifications,
$allow_freeze_global,
$freeze_max_days_global,
$auto_propagate_on_purchase,
$allow_full_access_rebooking,
$allowed_product_types
]);
$success_message = "Impostazioni create con successo!";
} else {
$stmt = $pdo->prepare("
UPDATE school_settings SET
header_color = ?, sidebar_color = ?, payment_methods = ?, currency_code = ?, enable_notifications = ?,
allow_freeze_global = ?, freeze_max_days_global = ?, auto_propagate_on_purchase = ?,
allow_full_access_rebooking = ?, allowed_product_types = ?
WHERE school_id = ?
");
$stmt->execute([
$header_color,
$sidebar_color,
$payment_methods,
$currency_code,
$enable_notifications,
$allow_freeze_global,
$freeze_max_days_global,
$auto_propagate_on_purchase,
$allow_full_access_rebooking,
$allowed_product_types,
$school_id
]);
$success_message = "Impostazioni aggiornate con successo!";
}
// Ricarica i settings aggiornati
$stmt = $pdo->prepare("SELECT * FROM school_settings WHERE school_id = ?");
$stmt->execute([$school_id]);
$settings = $stmt->fetch();
} catch (Exception $e) {
$error = "Errore database: " . $e->getMessage();
}
}
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Impostazioni Scuola - <?php echo htmlspecialchars($school['name']); ?></title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<style>
.card {
border-radius: 15px;
}
.form-check-input:checked {
background-color: #0d6efd;
border-color: #0d6efd;
}
</style>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="container-xl">
<div class="row">
<div class="col-12">
<div class="card shadow">
<div class="card-header bg-primary text-white">
<h4 class="mb-0">Impostazioni Scuola</h4>
</div>
<div class="card-body">
<?php if ($success_message): ?>
<div class="alert alert-success alert-dismissible fade show">
<?php echo $success_message; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<form method="POST">
<!-- Aspetto e Pagamenti -->
<h5 class="text-primary mb-4">Aspetto e Pagamenti</h5>
<div class="row g-3 mb-4">
<div class="col-md-3">
<label>Colore Header</label>
<input type="color" name="header_color" class="form-control form-control-color" value="<?php echo $settings['header_color'] ?? '#ffffff'; ?>">
</div>
<div class="col-md-3">
<label>Colore Sidebar</label>
<input type="color" name="sidebar_color" class="form-control form-control-color" value="<?php echo $settings['sidebar_color'] ?? '#ffffff'; ?>">
</div>
<div class="col-md-3">
<label>Valuta</label>
<input type="text" name="currency_code" class="form-control" value="<?php echo $settings['currency_code'] ?? 'EUR'; ?>" maxlength="3" style="text-transform:uppercase">
</div>
<div class="col-md-3">
<label>Notifiche</label><br>
<div class="form-check form-switch d-inline-block">
<input class="form-check-input" type="checkbox" name="enable_notifications" id="notif" <?php echo ($settings['enable_notifications'] ?? 1) ? 'checked' : ''; ?>>
<label class="form-check-label" for="notif">Attive</label>
</div>
</div>
</div>
<div class="col-12 mb-4">
<label class="form-label">Metodi di pagamento accettati</label>
<div class="row g-3">
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="payment_methods[]" value="manual" id="pay_manual"
<?php echo strpos($settings['payment_methods'] ?? 'manual', 'manual') !== false ? 'checked' : ''; ?>>
<label class="form-check-label fw-bold" for="pay_manual">Pagamento Manuale</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="payment_methods[]" value="stripe" id="pay_stripe"
<?php echo strpos($settings['payment_methods'] ?? '', 'stripe') !== false ? 'checked' : ''; ?>>
<label class="form-check-label fw-bold" for="pay_stripe">Stripe</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="payment_methods[]" value="paypal" id="pay_paypal"
<?php echo strpos($settings['payment_methods'] ?? '', 'paypal') !== false ? 'checked' : ''; ?>>
<label class="form-check-label fw-bold" for="pay_paypal">PayPal</label>
</div>
</div>
</div>
</div>
<hr class="my-5">
<!-- Impostazioni Prodotti -->
<h5 class="text-primary mb-4">Impostazioni Prodotti (valori predefiniti)</h5>
<div class="row g-4 align-items-center">
<div class="col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="allow_freeze_global" id="allow_freeze" <?php echo ($settings['allow_freeze_global'] ?? 1) ? 'checked' : ''; ?>>
<label class="form-check-label" for="allow_freeze">Permetti congelamento abbonamenti</label>
</div>
</div>
<div class="col-md-6">
<label>Giorni massimi di congelamento</label>
<input type="number" name="freeze_max_days_global" class="form-control" value="<?php echo $settings['freeze_max_days_global'] ?? 30; ?>" min="0"
<?php echo ($settings['allow_freeze_global'] ?? 1) ? '' : 'disabled'; ?>>
</div>
</div>
<div class="mt-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="auto_propagate_on_purchase" id="auto_propagate" <?php echo ($settings['auto_propagate_on_purchase'] ?? 1) ? 'checked' : ''; ?>>
<label class="form-check-label" for="auto_propagate">Propaga automaticamente le sessioni dopo l'acquisto</label>
</div>
</div>
<div class="mt-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="allow_full_access_rebooking" id="full_access" <?php echo ($settings['allow_full_access_rebooking'] ?? 1) ? 'checked' : ''; ?>>
<label class="form-check-label" for="full_access">Permetti riprenotazione su qualsiasi lezione</label>
</div>
</div>
<div class="mt-4">
<label class="form-label">Tipi di prodotto consentiti</label>
<div class="row">
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="allow_subscription" id="sub" <?php echo strpos($settings['allowed_product_types'] ?? 'subscription,carnet,drop_in', 'subscription') !== false ? 'checked' : ''; ?>>
<label class="form-check-label" for="sub">Abbonamenti</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="allow_carnet" id="car" <?php echo strpos($settings['allowed_product_types'] ?? '', 'carnet') !== false ? 'checked' : ''; ?>>
<label class="form-check-label" for="car">Carnet</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="allow_drop_in" id="drop" <?php echo strpos($settings['allowed_product_types'] ?? '', 'drop_in') !== false ? 'checked' : ''; ?>>
<label class="form-check-label" for="drop">Lezioni singole</label>
</div>
</div>
</div>
</div>
<div class="text-center mt-5">
<button type="submit" class="btn btn-primary btn-lg px-5">
Salva Impostazioni
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script>
document.getElementById('allow_freeze')?.addEventListener('change', function() {
document.querySelector('input[name="freeze_max_days_global"]').disabled = !this.checked;
});
</script>
</body>
</html>

View File

@ -0,0 +1,328 @@
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
if (!isset($iduserlogin)) {
die("Errore: Utente non loggato.");
}
// Recupera dati da auth_users
$stmt = $pdo->prepare("SELECT first_name, last_name, email FROM auth_users WHERE id = ?");
$stmt->execute([$iduserlogin]);
$user = $stmt->fetch();
if (!$user) {
die("Utente non trovato.");
}
// Recupera (o crea) record studente
$stmt = $pdo->prepare("SELECT * FROM students WHERE user_id = ?");
$stmt->execute([$iduserlogin]);
$student = $stmt->fetch();
$is_new = !$student;
$success_message = $error = '';
// === GESTIONE SALVATAGGIO ===
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$codice_fiscale = trim($_POST['codice_fiscale'] ?? '');
$partita_iva = trim($_POST['partita_iva'] ?? '');
$company_name = trim($_POST['company_name'] ?? '');
$billing_address = trim($_POST['billing_address']);
$billing_postal_code = trim($_POST['billing_postal_code']);
$billing_city = trim($_POST['billing_city']);
$billing_province = strtoupper(trim($_POST['billing_province']));
$billing_country = trim($_POST['billing_country'] ?: 'Italia');
$same_shipping = !empty($_POST['shipping_same_as_billing']);
$shipping_address = $same_shipping ? $billing_address : trim($_POST['shipping_address'] ?? '');
$shipping_postal_code = $same_shipping ? $billing_postal_code : trim($_POST['shipping_postal_code'] ?? '');
$shipping_city = $same_shipping ? $billing_city : trim($_POST['shipping_city'] ?? '');
$shipping_province = $same_shipping ? $billing_province : strtoupper(trim($_POST['shipping_province'] ?? ''));
$shipping_country = $same_shipping ? $billing_country : trim($_POST['shipping_country'] ?? 'Italia');
$emergency_name = trim($_POST['emergency_contact_name'] ?? '');
$emergency_phone = trim($_POST['emergency_contact_phone'] ?? '');
$medical_notes = trim($_POST['medical_notes'] ?? '');
$privacy_consent = !empty($_POST['privacy_consent']);
$marketing_consent = !empty($_POST['marketing_consent']);
// Validazione minima
if (empty($billing_address) || empty($billing_city) || empty($billing_postal_code) || empty($billing_province)) {
$error = "Compila tutti i campi obbligatori dell'indirizzo di fatturazione.";
} elseif (!$privacy_consent) {
$error = "Devi accettare l'informativa privacy per continuare.";
} else {
try {
if ($is_new) {
$stmt = $pdo->prepare("
INSERT INTO students (
user_id, codice_fiscale, partita_iva, company_name,
billing_address, billing_postal_code, billing_city, billing_province, billing_country,
shipping_same_as_billing, shipping_address, shipping_postal_code, shipping_city, shipping_province, shipping_country,
emergency_contact_name, emergency_contact_phone, medical_notes,
privacy_consent, marketing_consent
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
");
$stmt->execute([
$iduserlogin,
$codice_fiscale,
$partita_iva,
$company_name,
$billing_address,
$billing_postal_code,
$billing_city,
$billing_province,
$billing_country,
$same_shipping ? 1 : 0,
$shipping_address,
$shipping_postal_code,
$shipping_city,
$shipping_province,
$shipping_country,
$emergency_name,
$emergency_phone,
$medical_notes,
$privacy_consent ? 1 : 0,
$marketing_consent ? 1 : 0
]);
$success_message = "Profilo completato con successo! Benvenuto";
} else {
$stmt = $pdo->prepare("
UPDATE students SET
codice_fiscale = ?, partita_iva = ?, company_name = ?,
billing_address = ?, billing_postal_code = ?, billing_city = ?, billing_province = ?, billing_country = ?,
shipping_same_as_billing = ?, shipping_address = ?, shipping_postal_code = ?, shipping_city = ?, shipping_province = ?, shipping_country = ?,
emergency_contact_name = ?, emergency_contact_phone = ?, medical_notes = ?,
privacy_consent = ?, marketing_consent = ?
WHERE user_id = ?
");
$stmt->execute([
$codice_fiscale,
$partita_iva,
$company_name,
$billing_address,
$billing_postal_code,
$billing_city,
$billing_province,
$billing_country,
$same_shipping ? 1 : 0,
$shipping_address,
$shipping_postal_code,
$shipping_city,
$shipping_province,
$shipping_country,
$emergency_name,
$emergency_phone,
$medical_notes,
$privacy_consent ? 1 : 0,
$marketing_consent ? 1 : 0,
$iduserlogin
]);
$success_message = "Dati aggiornati con successo!";
}
// Ricarica i dati aggiornati
$stmt = $pdo->prepare("SELECT * FROM students WHERE user_id = ?");
$stmt->execute([$iduserlogin]);
$student = $stmt->fetch();
$is_new = false;
} catch (Exception $e) {
$error = "Errore del database: " . $e->getMessage();
}
}
}
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo $is_new ? 'Completa il tuo profilo' : 'Il mio profilo'; ?> - Yogiboook</title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<style>
.form-check-input:checked {
background-color: #0d6efd;
border-color: #0d6efd;
}
.required-label::after {
content: " *";
color: red;
}
</style>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="container-x1">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card radius-15 shadow-lg">
<div class="card-header bg-primary text-white text-center">
<h4 class="mb-0">
<?php echo $is_new ? 'Completa il tuo profilo studente' : 'I miei dati'; ?>
</h4>
</div>
<div class="card-body p-4">
<?php if ($success_message): ?>
<div class="alert alert-success text-center"><?php echo $success_message; ?></div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<form method="POST" class="needs-validation" novalidate>
<h5 class="mb-4 text-primary">Dati personali</h5>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Nome</label>
<input type="text" class="form-control" value="<?php echo htmlspecialchars($user['first_name'] ?? ''); ?>" disabled>
</div>
<div class="col-md-6">
<label class="form-label">Cognome</label>
<input type="text" class="form-control" value="<?php echo htmlspecialchars($user['last_name'] ?? ''); ?>" disabled>
</div>
<div class="col-md-6">
<label class="form-label">Email</label>
<input type="email" class="form-control" value="<?php echo htmlspecialchars($user['email'] ?? ''); ?>" disabled>
</div>
<div class="col-md-6">
<label class="form-label">Codice Fiscale</label>
<input type="text" class="form-control" name="codice_fiscale" value="<?php echo htmlspecialchars($student['codice_fiscale'] ?? ''); ?>" maxlength="16" style="text-transform:uppercase">
</div>
<div class="col-md-6">
<label class="form-label">Partita IVA <small class="text-muted">(opzionale, per aziende)</small></label>
<input type="text" class="form-control" name="partita_iva" value="<?php echo htmlspecialchars($student['partita_iva'] ?? ''); ?>" maxlength="11">
</div>
<div class="col-md-6">
<label class="form-label">Ragione sociale <small class="text-muted">(se P.IVA)</small></label>
<input type="text" class="form-control" name="company_name" value="<?php echo htmlspecialchars($student['company_name'] ?? ''); ?>">
</div>
</div>
<hr class="my-5">
<h5 class="mb-4 text-primary">Indirizzo di fatturazione <span class="required-label"></span></h5>
<div class="row g-3">
<div class="col-12">
<label class="form-label required-label">Indirizzo</label>
<input type="text" class="form-control" name="billing_address" value="<?php echo htmlspecialchars($student['billing_address'] ?? ''); ?>" required>
</div>
<div class="col-md-3">
<label class="form-label required-label">CAP</label>
<input type="text" class="form-control" name="billing_postal_code" value="<?php echo htmlspecialchars($student['billing_postal_code'] ?? ''); ?>" required>
</div>
<div class="col-md-5">
<label class="form-label required-label">Città</label>
<input type="text" class="form-control" name="billing_city" value="<?php echo htmlspecialchars($student['billing_city'] ?? ''); ?>" required>
</div>
<div class="col-md-2">
<label class="form-label required-label">Provincia</label>
<input type="text" class="form-control" name="billing_province" value="<?php echo htmlspecialchars($student['billing_province'] ?? ''); ?>" maxlength="2" style="text-transform:uppercase" required>
</div>
<div class="col-md-2">
<label class="form-label">Nazione</label>
<input type="text" class="form-control" name="billing_country" value="<?php echo htmlspecialchars($student['billing_country'] ?? 'Italia'); ?>">
</div>
</div>
<div class="form-check mt-4">
<input class="form-check-input" type="checkbox" id="same_shipping" name="shipping_same_as_billing" <?php echo ($student['shipping_same_as_billing'] ?? 1) ? 'checked' : ''; ?>>
<label class="form-check-label fw-bold text-primary" for="same_shipping">
L'indirizzo di spedizione è uguale a quello di fatturazione
</label>
</div>
<div id="shipping_fields" style="display: <?php echo ($student['shipping_same_as_billing'] ?? 1) ? 'none' : 'block'; ?>;">
<hr class="my-4">
<h5 class="mb-3 text-primary">Indirizzo di spedizione</h5>
<div class="row g-3">
<div class="col-12"><input type="text" class="form-control" name="shipping_address" placeholder="Indirizzo" value="<?php echo htmlspecialchars($student['shipping_address'] ?? ''); ?>"></div>
<div class="col-md-3"><input type="text" class="form-control" name="shipping_postal_code" placeholder="CAP" value="<?php echo htmlspecialchars($student['shipping_postal_code'] ?? ''); ?>"></div>
<div class="col-md-5"><input type="text" class="form-control" name="shipping_city" placeholder="Città" value="<?php echo htmlspecialchars($student['shipping_city'] ?? ''); ?>"></div>
<div class="col-md-2"><input type="text" class="form-control" name="shipping_province" placeholder="Prov" maxlength="2" style="text-transform:uppercase" value="<?php echo htmlspecialchars($student['shipping_province'] ?? ''); ?>"></div>
<div class="col-md-2"><input type="text" class="form-control" name="shipping_country" placeholder="Nazione" value="<?php echo htmlspecialchars($student['shipping_country'] ?? 'Italia'); ?>"></div>
</div>
</div>
<hr class="my-5">
<h5 class="mb-4 text-primary">Contatto di emergenza e note mediche</h5>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Nome contatto emergenza</label>
<input type="text" class="form-control" name="emergency_contact_name" value="<?php echo htmlspecialchars($student['emergency_contact_name'] ?? ''); ?>">
</div>
<div class="col-md-6">
<label class="form-label">Telefono emergenza</label>
<input type="text" class="form-control" name="emergency_contact_phone" value="<?php echo htmlspecialchars($student['emergency_contact_phone'] ?? ''); ?>">
</div>
<div class="col-12">
<label class="form-label">Note mediche / allergie / infortuni</label>
<textarea class="form-control" name="medical_notes" rows="3"><?php echo htmlspecialchars($student['medical_notes'] ?? ''); ?></textarea>
</div>
</div>
<hr class="my-5">
<h5 class="mb-4 text-primary">Consensi</h5>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="privacy_consent" name="privacy_consent" required <?php echo ($student['privacy_consent'] ?? false) ? 'checked' : ''; ?>>
<label class="form-check-label" for="privacy_consent">
Accetto l'<a href="privacy.php" target="_blank">informativa privacy</a> (obbligatorio)
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="marketing_consent" name="marketing_consent" <?php echo ($student['marketing_consent'] ?? false) ? 'checked' : ''; ?>>
<label class="form-check-label" for="marketing_consent">
Voglio ricevere newsletter e offerte
</label>
</div>
<div class="text-center mt-5">
<button type="submit" class="btn btn-primary btn-lg px-5">
<?php echo $is_new ? 'Completa registrazione' : 'Salva modifiche'; ?>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script>
// Mostra/nascondi indirizzo spedizione
document.getElementById('same_shipping').addEventListener('change', function() {
document.getElementById('shipping_fields').style.display = this.checked ? 'none' : 'block';
});
</script>
</body>
</html>

View File

@ -1,366 +1,302 @@
<?php include('include/headscript.php'); ?>
<?php
// Ottieni l'istanza del DBHandlerSelect
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
include('include/headscript.php');
// Recupera lo school_id e user_id dalla sessione
$school_id = session('school_id');
// Controlla se l'utente è loggato
if (empty($iduserlogin)) {
header('Location: login.php?error=not_logged_in');
if (!isset($iduserlogin)) {
header('Location: login.php');
exit;
}
$school = null;
// Costruisci manualmente l'URL assoluto per il logo di default
$base_url = rtrim(env('APP_URL'), '/') . '/public/userarea/';
$school_logo_path = $base_url . 'yogibook_logo.png'; // Default logo
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
// === DATI UTENTE ===
$stmt = $pdo->prepare("SELECT first_name, last_name, email, avatar FROM auth_users WHERE id = ?");
$stmt->execute([$iduserlogin]);
$user = $stmt->fetch();
$avatar = $user['avatar'] ? '../upload/users/' . $user['avatar'] : '../assets/images/default-avatar.png';
// === SCUOLA CORRENTE ===
$school_id = session('school_id');
$school_name = 'Nessuna scuola selezionata';
$school_logo_path = null; // niente default
if ($school_id) {
// Usa il modello School per recuperare i dati della scuola
$school = \Vanguard\Models\School::find($school_id);
$stmt = $pdo->prepare("SELECT name, logo FROM schools WHERE id = ?");
$stmt->execute([$school_id]);
$school = $stmt->fetch();
if ($school) {
// Se la scuola esiste, aggiorna il percorso del logo
$school_logo_path = $school->logo ? $base_url . $school->logo : $school_logo_path;
$school_name = $school['name'];
if (!empty($school['logo']) && file_exists("photoschool/" . $school['logo'])) {
$school_logo_path = "photoschool/" . $school['logo'];
}
}
}
// Query per i dati dell'utente
$stmt = $pdo->prepare("SELECT first_name, last_name, avatar FROM auth_users WHERE id = ?");
$stmt->execute([$iduserlogin]);
$user = $stmt->fetch();
// Dopo aver recuperato i dati dell'utente
$avatar = !empty($user['avatar']) ? '../upload/users/' . $user['avatar'] : '../assets/images/default-avatar.png';
// Query per recuperare gli ordini dell'utente per la scuola corrente
// === ORDINI UTENTE ===
$stmt = $pdo->prepare("
SELECT o.order_number, o.created_at, o.price, o.total_entries, o.available_entries, o.available_recoveries, o.expiration_date, o.activation_date,
p.name AS product_name, pv.name AS variation_name, c.name AS class_name, ct.level, ct.day_of_week
SELECT o.*, p.name AS product_name, pv.name AS variation_name,
c.name AS class_name, ct.level, ct.day_of_week
FROM orders o
JOIN products p ON o.product_id = p.id
JOIN product_variations pv ON o.variation_id = pv.id
LEFT JOIN product_variations pv ON o.variation_id = pv.id
LEFT JOIN classes c ON o.class_id = c.id
LEFT JOIN class_types ct ON o.class_type_id = ct.id
LEFT JOIN classes c ON ct.class_id = c.id
WHERE o.user_id = ? AND o.school_id = ?
ORDER BY o.created_at DESC
");
$stmt->execute([$iduserlogin, $school_id]);
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
$orders = $stmt->fetchAll();
// === STATISTICHE RAPIDE ===
$total_spent = array_sum(array_column($orders, 'price'));
$total_entries = array_sum(array_column($orders, 'total_entries'));
$available_entries = array_sum(array_column($orders, 'available_entries'));
$active_orders = count(array_filter($orders, fn($o) => $o['status'] === 'completed' && (!$o['expiration_date'] || strtotime($o['expiration_date']) >= time())));
?>
<!doctype html>
<html lang="en">
<html lang="it">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--favicon-->
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<title>La mia Dashboard - Yogiboook</title>
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<style>
.page-content {
background-color: #f0f4f5;
/* Sfondo pastello chiaro (grigio-azzurro) */
:root {
--pastel-blue: #94bacc;
--pastel-green: #a3d9b1;
--pastel-pink: #f8bbd0;
--pastel-yellow: #fff8c4;
}
.card-pastel {
background-color: rgb(149, 217, 248);
/* Verde menta pastello */
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
/* Ombra leggera */
border: none;
/* Rimuoviamo il bordo predefinito */
}
.avatar-border {
border: 3px solid #a3d9b1;
/* Bordo verde pastello intorno all'avatar */
}
.btn-pastel {
background-color: rgb(148, 186, 204);
/* Colore pulsante coordinato */
border: none;
transition: background-color 0.3s ease;
/* Effetto hover */
}
.btn-pastel:hover {
background-color: rgb(155, 189, 221);
/* Colore più scuro al passaggio del mouse */
}
h5,
h6 {
font-family: 'Poppins', sans-serif;
/* Font moderno e morbido, se disponibile */
color: #333;
/* Colore testo scuro per contrasto */
}
.calendar-header {
display: flex;
flex-wrap: wrap;
/* Permette ai filtri di andare a capo su schermi piccoli */
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
gap: 10px;
/* Spazio tra gli elementi */
}
.lesson-card,
.order-card {
background-color: #ffffff;
border-left: 4px solid #c8e6c9;
/* Verde per le lezioni programmate e ordini */
transition: transform 0.2s ease;
}
.lesson-card:hover,
.order-card:hover {
transform: translateY(-3px);
}
.filter-btn {
background-color: #f8bbd0;
border: none;
background: linear-gradient(135deg, #94bacc, #a3d9b1);
color: white;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.9rem;
margin: 0 5px;
/* Spazio tra i pulsanti */
}
.filter-btn.active {
background-color: #bbdefb;
.card-soft {
background: #ffffff;
border: 1px solid #e0e0e0;
}
.reschedule-btn {
background-color: #c8e6c9;
border: none;
color: white;
font-size: 0.85rem;
padding: 5px 10px;
.stat-card {
background: white;
border-radius: 15px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
}
.lesson-details p,
.order-details p {
margin-bottom: 0.2rem;
/* Spazio ridotto tra le righe */
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
.avatar-circle {
width: 100px;
height: 100px;
object-fit: cover;
border: 4px solid white;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.table-pastel thead {
background-color: var(--pastel-blue);
color: white;
}
.badge-soft {
padding: 0.4em 0.8em;
border-radius: 50px;
font-size: 0.85rem;
/* Testo più piccolo per adattarsi meglio */
}
.order-details .price {
font-weight: bold;
color: #28a745;
/* Verde per il prezzo */
}
</style>
</head>
<body>
<!--wrapper-->
<div class="wrapper">
<!--sidebar wrapper -->
<?php include('include/navbar.php'); ?>
<!--end sidebar wrapper -->
<!--start header -->
<?php include('include/topbar.php'); ?>
<!--end header -->
<!--start page wrapper -->
<div class="page-wrapper">
<div class="page-content">
<div class="page-content" style="background: linear-gradient(to bottom, #f0f8ff, #f8f9fa); min-height: 100vh;">
<!-- Sezione Scuola -->
<div class="card card-pastel radius-10 mb-4">
<div class="card-body text-center">
<?php if ($school): ?>
<h5 class="mb-3">Sei loggato nella scuola: <?php echo htmlspecialchars($school->name); ?></h5>
<img src="<?php echo $school_logo_path; ?>" alt="School Logo" style="max-height: 100px;">
<?php else: ?>
<h5 class="mb-3">Nessuna scuola selezionata</h5>
<img src="<?php echo $school_logo_path; ?>" alt="Default Logo" style="max-height: 100px;">
<?php endif; ?>
</div>
</div>
<!-- Sezione Profilo -->
<div class="card card-pastel radius-10">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0">Stato Utente</h6>
<!-- SCUOLA + BENVENUTO -->
<div class="container-fluid px-4 pt-4">
<div class="card card-pastel radius-20 shadow-lg mb-4 position-relative">
<div class="card-body text-center py-5">
<!-- Logo solo se esiste -->
<?php if ($school_logo_path): ?>
<img src="<?php echo htmlspecialchars($school_logo_path); ?>"
alt="Logo <?php echo htmlspecialchars($school_name); ?>"
class="mb-4 rounded-3 shadow"
style="height: 90px; object-fit: contain;">
<?php endif; ?>
<!-- Saluto -->
<h2 class="mb-2 text-white">
Ciao<?php echo $user['first_name'] ? ', ' . htmlspecialchars($user['first_name']) : ''; ?>!
</h2>
<p class="mb-0 fs-4 text-white opacity-90">
Sei nella scuola: <strong><?php echo htmlspecialchars($school_name); ?></strong>
</p>
<!-- PULSANTI IN RIGA (uno accanto all'altro) -->
<div class="position-absolute top-0 end-0 mt-3 me-3 d-flex gap-2">
<a href="my_lessons.php" class="btn btn-light btn-lg shadow-sm px-4">
<i class="bx bx-calendar-heart me-2"></i>Le mie lezioni
</a>
<button type="button" class="btn btn-outline-light btn-lg shadow-sm px-4"
data-bs-toggle="modal" data-bs-target="#changeSchoolModal">
<i class="bx bx-transfer me-2"></i>Cambia scuola
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="d-flex flex-column align-items-center text-center">
<!-- Saluto e Nome -->
<h5 class="mb-3">Ciao, <?php echo htmlspecialchars($user['first_name']); ?>!</h5>
</div>
<!-- Sezione dei box -->
<div class="row">
<!-- Lezioni programmate -->
<div class="col-12 col-md-4 mb-3">
<div class="card card-pastel radius-10 text-center" style="background-color: #c8e6c9;">
<div class="card-body">
<h6 class="mb-2">Lezioni Programmate</h6>
<h3 class="mb-0 text-primary">5</h3>
</div>
</div>
</div>
<!-- Ticket da programmare -->
<div class="col-12 col-md-4 mb-3">
<div class="card card-pastel radius-10 text-center" style="background-color: #f8bbd0;">
<div class="card-body">
<h6 class="mb-2">Ticket da Programmare</h6>
<h3 class="mb-0 text-primary">3</h3>
</div>
</div>
</div>
<!-- Lezioni da confermare -->
<div class="col-12 col-md-4 mb-3">
<div class="card card-pastel radius-10 text-center" style="background-color: #bbdefb;">
<div class="card-body">
<h6 class="mb-2">Lezioni da Confermare</h6>
<h3 class="mb-0 text-primary">2</h3>
</div>
<!-- PROFILO + STATISTICHE -->
<div class="row g-4 mb-5">
<div class="col-lg-4">
<div class="card stat-card text-center h-100">
<div class="card-body">
<img src="<?php echo $avatar; ?>" alt="Avatar" class="rounded-circle avatar-circle mb-3">
<h5><?php echo htmlspecialchars($user['first_name'] . ' ' . $user['last_name']); ?></h5>
<p class="text-muted"><?php echo htmlspecialchars($user['email']); ?></p>
</div>
</div>
</div>
</div>
</div>
<!-- Sezione delle lezioni future -->
<div class="card card-pastel radius-10 mt-4">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0">Le tue Lezioni Future</h6>
</div>
</div>
</div>
<div class="card-body">
<!-- Header con calendario e filtri -->
<div class="calendar-header">
<!-- Calendario per cambiare mese -->
<div>
<input type="month" id="monthPicker" value="2025-04" class="form-control" style="width: 150px;">
</div>
<!-- Filtri -->
<div>
<button class="filter-btn active">Programmate</button>
<button class="filter-btn">Effettuate</button>
<button class="filter-btn">Perse</button>
</div>
</div>
<!-- Lista delle lezioni -->
<div class="row">
<!-- Lezione 1 -->
<div class="col-12 col-md-6 mb-3">
<div class="card lesson-card radius-10">
<div class="card-body d-flex justify-content-between align-items-center">
<div class="lesson-details">
<h6 class="mb-1">Yoga Flow</h6>
<p class="text-muted">15 Apr 2025, 18:00</p>
<p class="text-muted">Scuola: Yoga Harmony</p>
<p class="text-muted">Via Roma 12, Milano</p>
</div>
<button class="reschedule-btn">Riprogramma</button>
</div>
</div>
</div>
<!-- Lezione 2 -->
<div class="col-12 col-md-6 mb-3">
<div class="card lesson-card radius-10">
<div class="card-body d-flex justify-content-between align-items-center">
<div class="lesson-details">
<h6 class="mb-1">Hatha Yoga</h6>
<p class="text-muted">20 Apr 2025, 09:00</p>
<p class="text-muted">Scuola: Zen Studio</p>
<p class="text-muted">Corso Italia 45, Torino</p>
</div>
<button class="reschedule-btn">Riprogramma</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Nuova Sezione: Riepilogo Ordini -->
<div class="card card-pastel radius-10 mt-4">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0">I tuoi Ordini</h6>
</div>
</div>
</div>
<div class="card-body">
<?php if (empty($orders)): ?>
<p class="text-center text-muted">Non hai ancora effettuato ordini per questa scuola.</p>
<?php else: ?>
<div class="row">
<?php foreach ($orders as $order): ?>
<div class="col-12 col-md-6 mb-3">
<div class="card order-card radius-10">
<div class="card-body">
<div class="order-details">
<h6 class="mb-1">Ordine #<?php echo htmlspecialchars($order['order_number']); ?></h6>
<p class="text-muted">Data: <?php echo date('d/m/Y H:i', strtotime($order['created_at'])); ?></p>
<p><strong>Prodotto:</strong> <?php echo htmlspecialchars($order['product_name']); ?></p>
<p><strong>Variazione:</strong> <?php echo htmlspecialchars($order['variation_name']); ?></p>
<?php if (!empty($order['class_name'])): ?>
<p><strong>Classe:</strong> <?php echo htmlspecialchars($order['class_name'] . ' - ' . $order['level'] . ' (' . $order['day_of_week'] . ')'); ?></p>
<?php endif; ?>
<p><strong>Entrate Totali:</strong> <?php echo $order['total_entries']; ?></p>
<p><strong>Recuperi Disponibili:</strong> <?php echo $order['available_recoveries']; ?></p>
<?php if (!empty($order['expiration_date'])): ?>
<p><strong>Valido fino al:</strong> <?php echo date('d/m/Y', strtotime($order['expiration_date'])); ?></p>
<?php endif; ?>
<p class="price"><strong>Prezzo:</strong> <?php echo number_format($order['price'], 2); ?></p>
</div>
</div>
<div class="col-lg-8">
<div class="row g-4">
<div class="col-md-4">
<div class="card stat-card text-center h-100">
<div class="card-body">
<h3 class="text-primary fw-bold"><?php echo count($orders); ?></h3>
<p class="mb-0">Ordini totali</p>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="col-md-4">
<div class="card stat-card text-center h-100">
<div class="card-body">
<h3 class="text-success fw-bold"><?php echo number_format($total_spent, 2); ?></h3>
<p class="mb-0">Speso in totale</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card stat-card text-center h-100">
<div class="card-body">
<h3 class="text-info fw-bold"><?php echo $available_entries; ?></h3>
<p class="mb-0">Ingressi disponibili</p>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<!-- I TUOI ORDINI -->
<div class="card radius-20 shadow-lg">
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
<h4 class="mb-0">I tuoi ordini</h4>
<span class="badge bg-light text-dark"><?php echo count($orders); ?> totali</span>
</div>
<div class="card-body p-0">
<?php if (empty($orders)): ?>
<div class="text-center py-5">
<i class="bx bx-package bx-lg text-muted"></i>
<h5 class="text-muted mt-3">Non hai ancora effettuato ordini</h5>
<a href="products.php" class="btn btn-primary mt-3">Vai ai corsi</a>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-pastel">
<tr>
<th>Data</th>
<th>Ordine</th>
<th>Prodotto</th>
<th>Ingressi</th>
<th>Scadenza</th>
<th>Prezzo</th>
<th>Stato</th>
</tr>
</thead>
<tbody>
<?php foreach ($orders as $o): ?>
<tr class="table-light">
<td><?php echo date('d/m/Y', strtotime($o['created_at'])); ?></td>
<td><strong>#<?php echo $o['order_number']; ?></strong></td>
<td>
<strong><?php echo htmlspecialchars($o['product_name']); ?></strong>
<?php if ($o['variation_name']): ?>
<br><small class="text-success"><?php echo htmlspecialchars($o['variation_name']); ?></small>
<?php endif; ?>
<?php if ($o['class_name']): ?>
<br><small class="text-info"><?php echo htmlspecialchars($o['class_name']); ?></small>
<?php endif; ?>
</td>
<td>
<?php if ($o['available_entries'] != $o['total_entries']): ?>
<span class="text-success"><?php echo $o['available_entries']; ?></span>/<?php echo $o['total_entries']; ?>
<?php else: ?>
<?php echo $o['total_entries']; ?>
<?php endif; ?>
</td>
<td>
<?php if ($o['expiration_date']): ?>
<span class="<?php echo strtotime($o['expiration_date']) < time() ? 'text-danger' : 'text-warning'; ?>">
<?php echo date('d/m/Y', strtotime($o['expiration_date'])); ?>
</span>
<?php else: ?>
<em>Nessuna</em>
<?php endif; ?>
</td>
<td class="text-success fw-bold"><?php echo number_format($o['price'], 2); ?></td>
<td>
<span class="badge-soft <?php echo $o['status'] == 'completed' ? 'bg-success' : ($o['status'] == 'pending' ? 'bg-warning' : 'bg-secondary'); ?>">
<?php echo ucfirst($o['status']); ?>
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<!--end page wrapper -->
<!--start overlay-->
<div class="overlay toggle-icon"></div>
<!--end overlay-->
<!--Start Back To Top Button-->
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<!--End Back To Top Button-->
<?php include('include/footer.php'); ?>
</div>
<!--end wrapper-->
<!-- search modal -->
<?php //include('include/searchmodal.php');
?>
<!-- end search modal -->
<!--start switcher-->
<?php //include('include/themeswitcher.php');
?>
<!--end switcher-->
<?php include('jsinclude.php'); ?>
<!-- Modal Cambia Scuola -->
<div class="modal fade" id="changeSchoolModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title">Scegli la scuola</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body text-center py-5">
<i class="bx bx-building-house bx-lg text-muted"></i>
<h4 class="mt-3 text-muted">Le tue scuole</h4>
<p class="text-muted">Qui compariranno tutte le scuole in cui sei iscritto</p>
<div class="spinner-border text-primary mt-4" role="status">
<span class="visually-hidden">Caricamento...</span>
</div>
</div>
</div>
</div>
</div>
</body>
</html>