fixed finances my lesson etc
This commit is contained in:
parent
8c5b9a0d85
commit
70d01f160e
332
public/userarea/finances.php
Normal file
332
public/userarea/finances.php
Normal 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>
|
||||||
@ -6,55 +6,60 @@ $db = DBHandlerSelect::getInstance()->getConnection();
|
|||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
error_reporting(E_ALL | E_STRICT);
|
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
|
include('../../extra/auth.php');
|
||||||
// logged in, and in that case we redirect
|
|
||||||
// the user to vanguard login page.
|
|
||||||
|
|
||||||
if (! Auth::check()) {
|
if (! Auth::check()) {
|
||||||
|
|
||||||
redirectTo('../../public/login');
|
redirectTo('../../public/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
||||||
$iduserlogin = $user->present()->id;
|
$iduserlogin = $user->present()->id;
|
||||||
$nameuser = $user->present()->first_name;
|
$nameuser = $user->present()->first_name;
|
||||||
$surnameuser = $user->present()->last_name;
|
$surnameuser = $user->present()->last_name;
|
||||||
$emailuser = $user->present()->email;
|
$emailuser = $user->present()->email;
|
||||||
$avatar = $user->present()->avatar;
|
$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;
|
// --- INIZIO: Reindirizzamento intelligente per studenti senza profilo ---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//$user = "1";
|
|
||||||
//$iduserlogin="1";
|
|
||||||
//$nameuser="Claudio";
|
|
||||||
//$emailuser="info@claudiosironi.com";
|
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
if (session_status() == PHP_SESSION_NONE) {
|
if (session_status() == PHP_SESSION_NONE) {
|
||||||
session_start();
|
session_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
$_SESSION["iduserlogin"] = $iduserlogin;
|
// Definisci qui l'ID del ruolo STUDENTE (cambialo se è diverso!)
|
||||||
$iduserlog = $_SESSION["iduserlogin"];
|
define('ROLE_STUDENTE', 2); // Cambia 3 con il ruolo corretto del tuo studente
|
||||||
$_SESSION["nameuser"] = $nameuser;
|
|
||||||
$_SESSION["surnameuser"] = $surnameuser;
|
// Escludi alcune pagine dove NON vuoi il redirect (es. login, logout, profile)
|
||||||
$_SESSION["emailuser"] = $emailuser;
|
$current_page = basename($_SERVER['PHP_SELF']);
|
||||||
$_SESSION["photouser"] = $avatar;
|
$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"];
|
$photouser = $_SESSION["photouser"];
|
||||||
?>
|
|
||||||
|
|
||||||
|
|
||||||
<?php //include files
|
|
||||||
|
|
||||||
//require_once(__DIR__ . '/../../languages/en/general.php');
|
|
||||||
|
|
||||||
//include("generalsettings.php");
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<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="parent-icon"><i class="bx bx-cog"></i></div>
|
||||||
<div class="menu-title">Impostazioni</div>
|
<div class="menu-title">Impostazioni</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -329,7 +329,7 @@ $cart_count = array_sum(array_column($_SESSION['cart'], 'quantity'));
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<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-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-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>
|
<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>
|
||||||
|
|||||||
257
public/userarea/my_lessons.php
Normal file
257
public/userarea/my_lessons.php
Normal 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
227
public/userarea/orders.php
Normal 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 |
@ -29,6 +29,25 @@ if (!$school) {
|
|||||||
$school_id = $school['id'];
|
$school_id = $school['id'];
|
||||||
$school_name = $school['name'];
|
$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
|
// Recupera i prodotti della scuola con variazioni, classi e variazioni associate
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT p.*,
|
SELECT p.*,
|
||||||
@ -446,6 +465,18 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
/* Rende il nome del prodotto in corsivo per le variazioni */
|
/* 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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -690,10 +721,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">Tipo <span class="text-danger">*</span></label>
|
<label class="form-label">Tipo <span class="text-danger">*</span></label>
|
||||||
<select class="form-select" name="type" required>
|
<select class="form-select precompiled-field" name="type" required>
|
||||||
<option value="carnet">Carnet</option>
|
<?php foreach ($allowed_types as $type): ?>
|
||||||
<option value="subscription">Abbonamento</option>
|
<?php if (isset($types_map[$type])): ?>
|
||||||
<option value="drop_in">Lezione Singola</option>
|
<option value="<?php echo $type; ?>">
|
||||||
|
<?php echo $types_map[$type]; ?>
|
||||||
|
</option>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@ -732,29 +767,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">Permetti congelamento</label>
|
<label class="form-label">Permetti congelamento</label>
|
||||||
<select class="form-select" name="allow_freeze">
|
<select class="form-select precompiled-field" name="allow_freeze">
|
||||||
<option value="0">No</option>
|
<option value="0" <?php echo !$school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>No</option>
|
||||||
<option value="1">Sì</option>
|
<option value="1" <?php echo $school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>Sì</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">Giorni max congelamento</label>
|
<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>
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">Accesso completo a tutte le classi</label>
|
<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')">
|
<select class="form-select precompiled-field" id="add_product_is_full_access" name="is_full_access" onchange="toggleClassTypesSection(this.value, 'add')">
|
||||||
<option value="0">No</option>
|
<option value="0" <?php echo !$school_settings['allow_full_access_rebooking'] ? 'selected' : ''; ?>>No</option>
|
||||||
<option value="1">Sì</option>
|
<option value="1" <?php echo $school_settings['allow_full_access_rebooking'] ? 'selected' : ''; ?>>Sì</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">Propaga automaticamente all'ordine</label>
|
<label class="form-label">Propaga automaticamente all'ordine</label>
|
||||||
<select class="form-select" name="auto_propagate_to_order">
|
<select class="form-select precompiled-field" name="auto_propagate_to_order">
|
||||||
<option value="0">No</option>
|
<option value="0" <?php echo !$school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>No</option>
|
||||||
<option value="1">Sì</option>
|
<option value="1" <?php echo $school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>Sì</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -858,21 +894,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="add_variation_allow_freeze" class="form-label">Permetti Congelamento</label>
|
<label for="add_variation_allow_freeze" class="form-label">Permetti Congelamento</label>
|
||||||
<select class="form-control" id="add_variation_allow_freeze" name="allow_freeze">
|
<select class="form-select precompiled-field" name="allow_freeze">
|
||||||
<option value="0">No</option>
|
<option value="0" <?php echo !$school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>No</option>
|
||||||
<option value="1">Sì</option>
|
<option value="1" <?php echo $school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>Sì</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="add_variation_freeze_max_days" class="form-label">Giorni Massimi di Congelamento</label>
|
<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>
|
<small class="form-text text-muted">Lascia vuoto se non applicabile.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="add_variation_auto_propagate" class="form-label">Propaga in Automatico all'Ordine</label>
|
<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">
|
<select class="form-select precompiled-field" name="auto_propagate_to_order">
|
||||||
<option value="0">No</option>
|
<option value="0" <?php echo !$school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>No</option>
|
||||||
<option value="1">Sì</option>
|
<option value="1" <?php echo $school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>Sì</option>
|
||||||
</select>
|
</select>
|
||||||
<small class="form-text text-muted">Se sì, la variazione verrà aggiunta automaticamente agli ordini futuri.</small>
|
<small class="form-text text-muted">Se sì, la variazione verrà aggiunta automaticamente agli ordini futuri.</small>
|
||||||
</div>
|
</div>
|
||||||
@ -934,11 +971,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<input type="text" class="form-control" id="edit_product_variation_name" name="variation_name">
|
<input type="text" class="form-control" id="edit_product_variation_name" name="variation_name">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="edit_product_type" class="form-label">Tipo</label>
|
<label class="form-label">Tipo <span class="text-danger">*</span></label>
|
||||||
<select class="form-control" id="edit_product_type" name="type" required>
|
<select class="form-select precompiled-field" name="type" required>
|
||||||
<option value="carnet">Carnet</option>
|
<?php foreach ($allowed_types as $type): ?>
|
||||||
<option value="subscription">Abbonamento</option>
|
<?php if (isset($types_map[$type])): ?>
|
||||||
<option value="drop_in">Lezione Singola</option>
|
<option value="<?php echo $type; ?>">
|
||||||
|
<?php echo $types_map[$type]; ?>
|
||||||
|
</option>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3" id="edit_price_section">
|
<div class="col-md-6 mb-3" id="edit_price_section">
|
||||||
|
|||||||
@ -1,135 +1,204 @@
|
|||||||
<?php
|
<?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();
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
$pdo = $dbHandler->getConnection();
|
$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 {
|
try {
|
||||||
// Inizia una transazione
|
|
||||||
$pdo->beginTransaction();
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
// Seleziona gli ordini con status 'completed' e lezioni disponibili
|
$totalBookings = 0;
|
||||||
$stmt = $pdo->prepare("
|
$totalOrders = 0;
|
||||||
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);
|
|
||||||
|
|
||||||
$bookings_created = 0;
|
$orderSql = "
|
||||||
$orders_propagated = 0;
|
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) {
|
foreach ($orders as $order) {
|
||||||
$order_id = $order['id'];
|
$totalOrders++;
|
||||||
$user_id = $order['user_id'];
|
$orderId = $order['id'];
|
||||||
$class_type_id = $order['class_type_id'];
|
$orderNumber = $order['order_number'];
|
||||||
$available_entries = $order['available_entries'];
|
$userId = $order['user_id'];
|
||||||
$school_id = $order['school_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
|
echo magenta("──────────────────────────────────────────────────────\n");
|
||||||
$offStmt = $pdo->prepare("
|
echo green("ELABORAZIONE ORDINE #$orderNumber (ID: $orderId)\n");
|
||||||
SELECT start_date, end_date
|
echo green("Utente: $userEmail (ID: $userId) | Scuola ID: $schoolId\n");
|
||||||
FROM day_off
|
echo green("Prodotto: $productName | Ingressi da propagare: $remaining | Attivazione: $activation\n");
|
||||||
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);
|
|
||||||
|
|
||||||
// Crea un array di date di chiusura
|
// Recupera class_type consentiti
|
||||||
$off_dates = [];
|
$ctSql = "SELECT DISTINCT class_type_id FROM product_class_types WHERE product_id = ? AND (variation_id IS NULL OR variation_id = ? OR variation_id = ?)";
|
||||||
foreach ($off_periods as $period) {
|
$ctStmt = $pdo->prepare($ctSql);
|
||||||
$start_date = new DateTime($period['start_date']);
|
$ctStmt->execute([$order['product_id'], $order['variation_id'], $order['variation_id']]);
|
||||||
$end_date = new DateTime($period['end_date']);
|
$classTypeIds = $ctStmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
$interval = new DateInterval('P1D');
|
|
||||||
$date_range = new DatePeriod($start_date, $interval, $end_date->modify('+1 day'));
|
if (empty($classTypeIds)) {
|
||||||
foreach ($date_range as $date) {
|
echo red("Nessun class_type associato al prodotto → SKIP\n");
|
||||||
$off_dates[] = $date->format('Y-m-d');
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trova le prossime sessioni disponibili per questo class_type_id
|
// Nomi delle classi per debug - VERSIONE MIGLIORE
|
||||||
$sessionStmt = $pdo->prepare("
|
$placeholders = str_repeat('?,', count($classTypeIds) - 1) . '?';
|
||||||
SELECT id, session_date
|
$namesSql = "
|
||||||
FROM class_sessions
|
SELECT ct.id, CONCAT(c.name, ' - ', ct.level, ' ',
|
||||||
WHERE class_type_id = ? AND session_date >= CURDATE() AND status = 'scheduled'
|
CASE ct.day_of_week
|
||||||
ORDER BY session_date ASC, start_time ASC
|
WHEN 'monday' THEN 'Lun'
|
||||||
LIMIT ?
|
WHEN 'tuesday' THEN 'Mar'
|
||||||
");
|
WHEN 'wednesday' THEN 'Mer'
|
||||||
$sessionStmt->execute([$class_type_id, $available_entries]);
|
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);
|
$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) {
|
$bookedThisOrder = 0;
|
||||||
$session_id = $session['id'];
|
|
||||||
$session_date = $session['session_date'];
|
|
||||||
|
|
||||||
// Salta se la data è un giorno di chiusura
|
foreach ($sessions as $s) {
|
||||||
if (in_array($session_date, $off_dates)) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifica la capacità massima della sessione
|
$free = $s['max_capacity'] ? ($s['max_capacity'] - $s['booked']) : 999;
|
||||||
$capacityStmt = $pdo->prepare("
|
|
||||||
SELECT max_capacity
|
|
||||||
FROM class_sessions
|
|
||||||
WHERE id = ?
|
|
||||||
");
|
|
||||||
$capacityStmt->execute([$session_id]);
|
|
||||||
$max_capacity = $capacityStmt->fetchColumn();
|
|
||||||
|
|
||||||
$bookingCountStmt = $pdo->prepare("
|
if ($free <= 0) {
|
||||||
SELECT COUNT(*)
|
echo red(" FULL $date $time → $className (Posti: {$s['booked']}/{$s['max_capacity']}) → saltata\n");
|
||||||
FROM session_bookings
|
continue;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserisci la prenotazione in session_bookings
|
// PRENOTA!
|
||||||
$insertStmt = $pdo->prepare("
|
$insert = $pdo->prepare("INSERT INTO session_bookings
|
||||||
INSERT INTO session_bookings (
|
(session_id, user_id, order_id, status, booked_at, created_at, updated_at)
|
||||||
session_id, user_id, status, booked_at, created_at, updated_at
|
VALUES (?, ?, ?, 'booked', NOW(), NOW(), NOW())");
|
||||||
)
|
$insert->execute([$s['id'], $userId, $orderId]);
|
||||||
VALUES (?, ?, 'booked', NOW(), NOW(), NOW())
|
|
||||||
");
|
$totalBookings++;
|
||||||
$insertStmt->execute([
|
$bookedThisOrder++;
|
||||||
$session_id,
|
$remaining--;
|
||||||
$user_id
|
|
||||||
]);
|
echo green(" PRENOTATA $date $time → $className | Posto libero: $free → rimanenti da propagare: $remaining\n");
|
||||||
$bookings_created++;
|
|
||||||
$bookings_for_order++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggiorna available_entries e lo stato dell'ordine
|
// Aggiornamento ordine
|
||||||
if ($bookings_for_order > 0) {
|
if ($bookedThisOrder > 0) {
|
||||||
$updateStmt = $pdo->prepare("
|
$newStatus = ($remaining <= 0) ? 'propagated' : 'completed';
|
||||||
UPDATE orders
|
$pdo->prepare("UPDATE orders SET available_entries = ?, status = ? WHERE id = ?")
|
||||||
SET available_entries = available_entries - ?,
|
->execute([$remaining, $newStatus, $orderId]);
|
||||||
status = 'propagated'
|
|
||||||
WHERE id = ?
|
echo green("Ordine aggiornato: available_entries = $remaining | status = $newStatus\n");
|
||||||
");
|
} else {
|
||||||
$updateStmt->execute([$bookings_for_order, $order_id]);
|
echo yellow("Nessuna lezione disponibile al momento → ci riproverà alla prossima esecuzione\n");
|
||||||
$orders_propagated++;
|
|
||||||
}
|
}
|
||||||
|
echo magenta("──────────────────────────────────────────────────────\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conferma la transazione
|
|
||||||
$pdo->commit();
|
$pdo->commit();
|
||||||
|
|
||||||
echo "Propagazione completata con successo: $bookings_created prenotazioni create, $orders_propagated ordini aggiornati.";
|
echo cyan("=== PROPAGAZIONE COMPLETATA ===\n");
|
||||||
} catch (PDOException $e) {
|
echo green("Ordini processati: $totalOrders\n");
|
||||||
// In caso di errore, annulla la transazione
|
echo green("Prenotazioni automatiche create: $totalBookings\n");
|
||||||
|
echo cyan("Fine esecuzione: " . date('Y-m-d H:i:s') . "\n");
|
||||||
|
} catch (Exception $e) {
|
||||||
$pdo->rollBack();
|
$pdo->rollBack();
|
||||||
echo "Errore durante la propagazione: " . $e->getMessage();
|
echo red("ERRORE CRITICO: " . $e->getMessage() . "\n");
|
||||||
|
error_log("Auto-propagate error: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -843,12 +843,12 @@ $daily_sessions = $stmt->fetchAll();
|
|||||||
<span class="fs-6">Situazione Clienti</span>
|
<span class="fs-6">Situazione Clienti</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- Pulsante Ordini -->
|
<!-- 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>
|
<i class="bx bx-cart me-2" style="font-size: 20px;"></i>
|
||||||
<span class="fs-6">Ordini</span>
|
<span class="fs-6">Ordini</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- Pulsante Finanze -->
|
<!-- 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>
|
<i class="bx bx-dollar me-2" style="font-size: 20px;"></i>
|
||||||
<span class="fs-6">Finanze</span>
|
<span class="fs-6">Finanze</span>
|
||||||
</a>
|
</a>
|
||||||
@ -867,7 +867,7 @@ $daily_sessions = $stmt->fetchAll();
|
|||||||
<span class="fs-6">Giorni di Chiusura</span>
|
<span class="fs-6">Giorni di Chiusura</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- Pulsante Impostazioni -->
|
<!-- 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>
|
<i class="bx bx-cog me-2" style="font-size: 20px;"></i>
|
||||||
<span class="fs-6">Impostazioni</span>
|
<span class="fs-6">Impostazioni</span>
|
||||||
</a>
|
</a>
|
||||||
@ -1076,73 +1076,126 @@ $daily_sessions = $stmt->fetchAll();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Sezione Sessioni della Giornata -->
|
<!-- Sezione Sessioni (Singolo giorno o Intervallo) -->
|
||||||
<div class="card radius-10 mb-4">
|
<div class="card radius-10 mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<div>
|
<h6 class="mb-0">Sessioni Programmata</h6>
|
||||||
<h6 class="mb-0">Sessioni della Giornata</h6>
|
<div class="d-flex gap-2">
|
||||||
</div>
|
<!-- I tuoi filtri data esistenti -->
|
||||||
<div class="ms-auto">
|
<form action="" method="GET" class="d-flex flex-wrap align-items-center gap-2">
|
||||||
<form action="" method="GET" class="d-flex align-items-center">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<label for="session_date" class="me-2">Seleziona Data:</label>
|
<label class="me-2 mb-0 text-nowrap">Dal:</label>
|
||||||
<input type="date" id="session_date" name="session_date" class="form-control" value="<?php echo htmlspecialchars($selected_date); ?>" onchange="this.form.submit()">
|
<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>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<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">
|
<div class="table-responsive">
|
||||||
<table id="dailySessionsTable" class="table table-striped table-bordered">
|
<table id="dailySessionsTable" class="table table-striped table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>Data</th>
|
||||||
<th>Classe</th>
|
<th>Classe</th>
|
||||||
<th>Variazione</th>
|
<th>Livello</th>
|
||||||
<th>Orario</th>
|
<th>Orario</th>
|
||||||
<th>Sala</th>
|
<th>Sala</th>
|
||||||
<th>Insegnante</th>
|
<th>Insegnante</th>
|
||||||
<th>Foto</th>
|
|
||||||
<th>Stato</th>
|
<th>Stato</th>
|
||||||
<th>Azioni</th>
|
<th>Azioni</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php if (empty($daily_sessions)): ?>
|
<?php if (empty($range_sessions)): ?>
|
||||||
<tr>
|
<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>
|
</tr>
|
||||||
<?php else: ?>
|
<?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>
|
<tr>
|
||||||
|
<td><?php echo date('d/m', strtotime($session_date)); ?></td>
|
||||||
<td><?php echo htmlspecialchars($session['class_name']); ?></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>
|
<td>
|
||||||
<?php echo htmlspecialchars(ucfirst($session['level'])); ?>
|
<?php echo $session['teacher_id'] ? htmlspecialchars($session['teacher_first_name'] . ' ' . $session['teacher_last_name']) : '<em>Non assegnato</em>'; ?>
|
||||||
(<?php echo htmlspecialchars(ucfirst($session['day_of_week'])); ?>)
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<?php echo htmlspecialchars($session['start_time']); ?> -
|
<span class="badge <?php
|
||||||
<?php echo htmlspecialchars($session['end_time']); ?>
|
echo $session['status'] === 'scheduled' ? 'bg-info' : ($session['status'] === 'completed' ? 'bg-success' : 'bg-danger');
|
||||||
</td>
|
?>">
|
||||||
<td><?php echo htmlspecialchars($session['room_name'] ?? 'Non specificata'); ?></td>
|
<?php echo $session['status'] === 'scheduled' ? 'Programmata' : ($session['status'] === 'completed' ? 'Completata' : 'Annullata'); ?>
|
||||||
<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>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -1155,14 +1208,13 @@ $daily_sessions = $stmt->fetchAll();
|
|||||||
"end_time" => $session['end_time'],
|
"end_time" => $session['end_time'],
|
||||||
"teacher_id" => $session['teacher_id'],
|
"teacher_id" => $session['teacher_id'],
|
||||||
"status" => $session['status']
|
"status" => $session['status']
|
||||||
]); ?>)'
|
]); ?>)'>
|
||||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Modifica">
|
|
||||||
<i class="bx bx-edit"></i>
|
<i class="bx bx-edit"></i>
|
||||||
</button>
|
</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="action" value="delete_session">
|
||||||
<input type="hidden" name="id" value="<?php echo $session['id']; ?>">
|
<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>
|
<i class="bx bx-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
@ -1682,6 +1734,135 @@ $daily_sessions = $stmt->fetchAll();
|
|||||||
document.getElementById('edit_session_status').value = data.status;
|
document.getElementById('edit_session_status').value = data.status;
|
||||||
}
|
}
|
||||||
</script>
|
</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>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
291
public/userarea/school_settings.php
Normal file
291
public/userarea/school_settings.php
Normal 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>
|
||||||
328
public/userarea/student_profile.php
Normal file
328
public/userarea/student_profile.php
Normal 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>
|
||||||
@ -1,366 +1,302 @@
|
|||||||
<?php include('include/headscript.php'); ?>
|
|
||||||
<?php
|
<?php
|
||||||
// Ottieni l'istanza del DBHandlerSelect
|
include('include/headscript.php');
|
||||||
$dbHandler = DBHandlerSelect::getInstance();
|
|
||||||
$pdo = $dbHandler->getConnection();
|
|
||||||
|
|
||||||
// Recupera lo school_id e user_id dalla sessione
|
if (!isset($iduserlogin)) {
|
||||||
$school_id = session('school_id');
|
header('Location: login.php');
|
||||||
|
|
||||||
|
|
||||||
// Controlla se l'utente è loggato
|
|
||||||
if (empty($iduserlogin)) {
|
|
||||||
header('Location: login.php?error=not_logged_in');
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$school = null;
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
// Costruisci manualmente l'URL assoluto per il logo di default
|
$pdo = $dbHandler->getConnection();
|
||||||
$base_url = rtrim(env('APP_URL'), '/') . '/public/userarea/';
|
|
||||||
$school_logo_path = $base_url . 'yogibook_logo.png'; // Default logo
|
// === 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) {
|
if ($school_id) {
|
||||||
// Usa il modello School per recuperare i dati della scuola
|
$stmt = $pdo->prepare("SELECT name, logo FROM schools WHERE id = ?");
|
||||||
$school = \Vanguard\Models\School::find($school_id);
|
$stmt->execute([$school_id]);
|
||||||
|
$school = $stmt->fetch();
|
||||||
|
|
||||||
if ($school) {
|
if ($school) {
|
||||||
// Se la scuola esiste, aggiorna il percorso del logo
|
$school_name = $school['name'];
|
||||||
$school_logo_path = $school->logo ? $base_url . $school->logo : $school_logo_path;
|
if (!empty($school['logo']) && file_exists("photoschool/" . $school['logo'])) {
|
||||||
|
$school_logo_path = "photoschool/" . $school['logo'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query per i dati dell'utente
|
// === ORDINI 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
|
|
||||||
$stmt = $pdo->prepare("
|
$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,
|
SELECT o.*, p.name AS product_name, pv.name AS variation_name,
|
||||||
p.name AS product_name, pv.name AS variation_name, c.name AS class_name, ct.level, ct.day_of_week
|
c.name AS class_name, ct.level, ct.day_of_week
|
||||||
FROM orders o
|
FROM orders o
|
||||||
JOIN products p ON o.product_id = p.id
|
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 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 = ?
|
WHERE o.user_id = ? AND o.school_id = ?
|
||||||
ORDER BY o.created_at DESC
|
ORDER BY o.created_at DESC
|
||||||
");
|
");
|
||||||
$stmt->execute([$iduserlogin, $school_id]);
|
$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>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="it">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<!-- Required meta tags -->
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!--favicon-->
|
<title>La mia Dashboard - Yogiboook</title>
|
||||||
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
|
||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
<?php include('siteinfo.php'); ?>
|
<?php include('siteinfo.php'); ?>
|
||||||
<style>
|
<style>
|
||||||
.page-content {
|
:root {
|
||||||
background-color: #f0f4f5;
|
--pastel-blue: #94bacc;
|
||||||
/* Sfondo pastello chiaro (grigio-azzurro) */
|
--pastel-green: #a3d9b1;
|
||||||
|
--pastel-pink: #f8bbd0;
|
||||||
|
--pastel-yellow: #fff8c4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-pastel {
|
.card-pastel {
|
||||||
background-color: rgb(149, 217, 248);
|
background: linear-gradient(135deg, #94bacc, #a3d9b1);
|
||||||
/* 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;
|
|
||||||
color: white;
|
color: white;
|
||||||
padding: 5px 15px;
|
|
||||||
border-radius: 20px;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
margin: 0 5px;
|
|
||||||
/* Spazio tra i pulsanti */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-btn.active {
|
.card-soft {
|
||||||
background-color: #bbdefb;
|
background: #ffffff;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reschedule-btn {
|
.stat-card {
|
||||||
background-color: #c8e6c9;
|
background: white;
|
||||||
border: none;
|
|
||||||
color: white;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
|
||||||
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lesson-details p,
|
.stat-card:hover {
|
||||||
.order-details p {
|
transform: translateY(-5px);
|
||||||
margin-bottom: 0.2rem;
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
||||||
/* Spazio ridotto tra le righe */
|
}
|
||||||
|
|
||||||
|
.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;
|
font-size: 0.85rem;
|
||||||
/* Testo più piccolo per adattarsi meglio */
|
|
||||||
}
|
|
||||||
|
|
||||||
.order-details .price {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #28a745;
|
|
||||||
/* Verde per il prezzo */
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!--wrapper-->
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<!--sidebar wrapper -->
|
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<!--end sidebar wrapper -->
|
|
||||||
<!--start header -->
|
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
<!--end header -->
|
|
||||||
<!--start page wrapper -->
|
|
||||||
<div class="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 -->
|
<!-- SCUOLA + BENVENUTO -->
|
||||||
<div class="card card-pastel radius-10 mb-4">
|
<div class="container-fluid px-4 pt-4">
|
||||||
<div class="card-body text-center">
|
<div class="card card-pastel radius-20 shadow-lg mb-4 position-relative">
|
||||||
<?php if ($school): ?>
|
<div class="card-body text-center py-5">
|
||||||
<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;">
|
<!-- Logo solo se esiste -->
|
||||||
<?php else: ?>
|
<?php if ($school_logo_path): ?>
|
||||||
<h5 class="mb-3">Nessuna scuola selezionata</h5>
|
<img src="<?php echo htmlspecialchars($school_logo_path); ?>"
|
||||||
<img src="<?php echo $school_logo_path; ?>" alt="Default Logo" style="max-height: 100px;">
|
alt="Logo <?php echo htmlspecialchars($school_name); ?>"
|
||||||
<?php endif; ?>
|
class="mb-4 rounded-3 shadow"
|
||||||
</div>
|
style="height: 90px; object-fit: contain;">
|
||||||
</div>
|
<?php endif; ?>
|
||||||
<!-- Sezione Profilo -->
|
|
||||||
<div class="card card-pastel radius-10">
|
<!-- Saluto -->
|
||||||
<div class="card-header">
|
<h2 class="mb-2 text-white">
|
||||||
<div class="d-flex align-items-center">
|
Ciao<?php echo $user['first_name'] ? ', ' . htmlspecialchars($user['first_name']) : ''; ?>!
|
||||||
<div>
|
</h2>
|
||||||
<h6 class="mb-0">Stato Utente</h6>
|
<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>
|
||||||
</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 -->
|
<!-- PROFILO + STATISTICHE -->
|
||||||
<div class="row">
|
<div class="row g-4 mb-5">
|
||||||
<!-- Lezioni programmate -->
|
<div class="col-lg-4">
|
||||||
<div class="col-12 col-md-4 mb-3">
|
<div class="card stat-card text-center h-100">
|
||||||
<div class="card card-pastel radius-10 text-center" style="background-color: #c8e6c9;">
|
<div class="card-body">
|
||||||
<div class="card-body">
|
<img src="<?php echo $avatar; ?>" alt="Avatar" class="rounded-circle avatar-circle mb-3">
|
||||||
<h6 class="mb-2">Lezioni Programmate</h6>
|
<h5><?php echo htmlspecialchars($user['first_name'] . ' ' . $user['last_name']); ?></h5>
|
||||||
<h3 class="mb-0 text-primary">5</h3>
|
<p class="text-muted"><?php echo htmlspecialchars($user['email']); ?></p>
|
||||||
</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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-lg-8">
|
||||||
</div>
|
<div class="row g-4">
|
||||||
|
<div class="col-md-4">
|
||||||
<!-- Sezione delle lezioni future -->
|
<div class="card stat-card text-center h-100">
|
||||||
<div class="card card-pastel radius-10 mt-4">
|
<div class="card-body">
|
||||||
<div class="card-header">
|
<h3 class="text-primary fw-bold"><?php echo count($orders); ?></h3>
|
||||||
<div class="d-flex align-items-center">
|
<p class="mb-0">Ordini totali</p>
|
||||||
<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>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
<?php endif; ?>
|
</div>
|
||||||
</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>
|
||||||
</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'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
</div>
|
</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'); ?>
|
<?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>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user