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_startup_errors', 1);
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
// This should be equal to: PATH_TO_VANGUARD_FOLDER/extra/auth.php
|
||||
include('../../extra/auth.php');
|
||||
//require_once __DIR__ . '/extra/auth.php';
|
||||
|
||||
// Here we just check if user is not
|
||||
// logged in, and in that case we redirect
|
||||
// the user to vanguard login page.
|
||||
include('../../extra/auth.php');
|
||||
|
||||
if (! Auth::check()) {
|
||||
|
||||
redirectTo('../../public/login');
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
$iduserlogin = $user->present()->id;
|
||||
$nameuser = $user->present()->first_name;
|
||||
$surnameuser = $user->present()->last_name;
|
||||
$emailuser = $user->present()->email;
|
||||
$avatar = $user->present()->avatar;
|
||||
$iduserlogin = $user->present()->id;
|
||||
$nameuser = $user->present()->first_name;
|
||||
$surnameuser = $user->present()->last_name;
|
||||
$emailuser = $user->present()->email;
|
||||
$avatar = $user->present()->avatar;
|
||||
$kindofrole = $user->present()->role_id; // <-- Questo è il ruolo (es. 1=admin, 2=teacher, 3=student, ecc.)
|
||||
|
||||
$kindofrole = $user->present()->role_id;
|
||||
|
||||
|
||||
|
||||
//$user = "1";
|
||||
//$iduserlogin="1";
|
||||
//$nameuser="Claudio";
|
||||
//$emailuser="info@claudiosironi.com";
|
||||
?>
|
||||
<?php
|
||||
// --- INIZIO: Reindirizzamento intelligente per studenti senza profilo ---
|
||||
if (session_status() == PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
$_SESSION["iduserlogin"] = $iduserlogin;
|
||||
$iduserlog = $_SESSION["iduserlogin"];
|
||||
$_SESSION["nameuser"] = $nameuser;
|
||||
$_SESSION["surnameuser"] = $surnameuser;
|
||||
$_SESSION["emailuser"] = $emailuser;
|
||||
$_SESSION["photouser"] = $avatar;
|
||||
// Definisci qui l'ID del ruolo STUDENTE (cambialo se è diverso!)
|
||||
define('ROLE_STUDENTE', 2); // Cambia 3 con il ruolo corretto del tuo studente
|
||||
|
||||
// Escludi alcune pagine dove NON vuoi il redirect (es. login, logout, profile)
|
||||
$current_page = basename($_SERVER['PHP_SELF']);
|
||||
$no_redirect_pages = ['login.php', 'logout.php', 'student_profile.php', 'register.php'];
|
||||
|
||||
if (
|
||||
$kindofrole == ROLE_STUDENTE &&
|
||||
!in_array($current_page, $no_redirect_pages) &&
|
||||
!isset($_SESSION['student_profile_completed'])
|
||||
) {
|
||||
// Controlla se esiste il record in tabella students
|
||||
$stmt = $db->prepare("SELECT id FROM students WHERE user_id = ? LIMIT 1");
|
||||
$stmt->execute([$iduserlogin]);
|
||||
$student_exists = $stmt->fetch();
|
||||
|
||||
if (!$student_exists) {
|
||||
// Non ha completato il profilo → reindirizza
|
||||
$_SESSION['student_profile_pending'] = true;
|
||||
header("Location: student_profile.php");
|
||||
exit;
|
||||
} else {
|
||||
// Ha già completato → segna per non controllare più
|
||||
$_SESSION['student_profile_completed'] = true;
|
||||
}
|
||||
}
|
||||
// --- FINE: Reindirizzamento intelligente ---
|
||||
|
||||
$_SESSION["iduserlogin"] = $iduserlogin;
|
||||
$_SESSION["nameuser"] = $nameuser;
|
||||
$_SESSION["surnameuser"] = $surnameuser;
|
||||
$_SESSION["emailuser"] = $emailuser;
|
||||
$_SESSION["photouser"] = $avatar;
|
||||
|
||||
$photouser = $_SESSION["photouser"];
|
||||
?>
|
||||
|
||||
|
||||
<?php //include files
|
||||
|
||||
//require_once(__DIR__ . '/../../languages/en/general.php');
|
||||
|
||||
//include("generalsettings.php");
|
||||
|
||||
?>
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="school-settings.php">
|
||||
<a href="school_settings.php">
|
||||
<div class="parent-icon"><i class="bx bx-cog"></i></div>
|
||||
<div class="menu-title">Impostazioni</div>
|
||||
</a>
|
||||
|
||||
@ -329,7 +329,7 @@ $cart_count = array_sum(array_column($_SESSION['cart'], 'quantity'));
|
||||
</div>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-user fs-5"></i><span>Profile</span></a></li>
|
||||
<li><a class="dropdown-item d-flex align-items-center" href="student_profile.php"><i class="bx bx-user fs-5"></i><span>Profilo Utente</span></a></li>
|
||||
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-cog fs-5"></i><span>Settings</span></a></li>
|
||||
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-home-circle fs-5"></i><span>Dashboard</span></a></li>
|
||||
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-dollar-circle fs-5"></i><span>Earnings</span></a></li>
|
||||
|
||||
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_name = $school['name'];
|
||||
|
||||
// === RECUPERA IMPOSTAZIONI SCUOLA (valori predefiniti) ===
|
||||
$stmt = $pdo->prepare("SELECT * FROM school_settings WHERE school_id = ?");
|
||||
$stmt->execute([$school_id]);
|
||||
$school_settings = $stmt->fetch() ?: [
|
||||
'allow_freeze_global' => 1,
|
||||
'freeze_max_days_global' => 30,
|
||||
'auto_propagate_on_purchase' => 1,
|
||||
'allow_full_access_rebooking' => 1,
|
||||
'allowed_product_types' => 'subscription,carnet,drop_in'
|
||||
];
|
||||
|
||||
// === PREPARA I TIPI DI PRODOTTO CONSENTITI ===
|
||||
$allowed_types = array_filter(explode(',', $school_settings['allowed_product_types'] ?? 'subscription,carnet,drop_in'));
|
||||
$types_map = [
|
||||
'subscription' => 'Abbonamento',
|
||||
'carnet' => 'Carnet',
|
||||
'drop_in' => 'Lezione Singola'
|
||||
];
|
||||
|
||||
// Recupera i prodotti della scuola con variazioni, classi e variazioni associate
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT p.*,
|
||||
@ -446,6 +465,18 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
font-style: italic;
|
||||
/* Rende il nome del prodotto in corsivo per le variazioni */
|
||||
}
|
||||
|
||||
.precompiled-field {
|
||||
background-color: #fff8c4 !important;
|
||||
/* giallo chiaro, elegante */
|
||||
border: 1px solid #ffe08c;
|
||||
}
|
||||
|
||||
.precompiled-field:focus {
|
||||
background-color: #fffce6 !important;
|
||||
/* un po' più chiaro quando scrivi */
|
||||
box-shadow: 0 0 0 0.2rem rgba(255, 200, 0, 0.25);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -690,10 +721,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Tipo <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="type" required>
|
||||
<option value="carnet">Carnet</option>
|
||||
<option value="subscription">Abbonamento</option>
|
||||
<option value="drop_in">Lezione Singola</option>
|
||||
<select class="form-select precompiled-field" name="type" required>
|
||||
<?php foreach ($allowed_types as $type): ?>
|
||||
<?php if (isset($types_map[$type])): ?>
|
||||
<option value="<?php echo $type; ?>">
|
||||
<?php echo $types_map[$type]; ?>
|
||||
</option>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
@ -732,29 +767,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Permetti congelamento</label>
|
||||
<select class="form-select" name="allow_freeze">
|
||||
<option value="0">No</option>
|
||||
<option value="1">Sì</option>
|
||||
<select class="form-select precompiled-field" name="allow_freeze">
|
||||
<option value="0" <?php echo !$school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>No</option>
|
||||
<option value="1" <?php echo $school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>Sì</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Giorni max congelamento</label>
|
||||
<input type="number" class="form-control" name="freeze_max_days">
|
||||
<input type="number" class="form-control precompiled-field" name="freeze_max_days"
|
||||
value="<?php echo $school_settings['freeze_max_days_global']; ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Accesso completo a tutte le classi</label>
|
||||
<select class="form-select" id="add_product_is_full_access" name="is_full_access" onchange="toggleClassTypesSection(this.value, 'add')">
|
||||
<option value="0">No</option>
|
||||
<option value="1">Sì</option>
|
||||
<select class="form-select precompiled-field" id="add_product_is_full_access" name="is_full_access" onchange="toggleClassTypesSection(this.value, 'add')">
|
||||
<option value="0" <?php echo !$school_settings['allow_full_access_rebooking'] ? 'selected' : ''; ?>>No</option>
|
||||
<option value="1" <?php echo $school_settings['allow_full_access_rebooking'] ? 'selected' : ''; ?>>Sì</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Propaga automaticamente all'ordine</label>
|
||||
<select class="form-select" name="auto_propagate_to_order">
|
||||
<option value="0">No</option>
|
||||
<option value="1">Sì</option>
|
||||
<select class="form-select precompiled-field" name="auto_propagate_to_order">
|
||||
<option value="0" <?php echo !$school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>No</option>
|
||||
<option value="1" <?php echo $school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>Sì</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@ -858,21 +894,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="add_variation_allow_freeze" class="form-label">Permetti Congelamento</label>
|
||||
<select class="form-control" id="add_variation_allow_freeze" name="allow_freeze">
|
||||
<option value="0">No</option>
|
||||
<option value="1">Sì</option>
|
||||
<select class="form-select precompiled-field" name="allow_freeze">
|
||||
<option value="0" <?php echo !$school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>No</option>
|
||||
<option value="1" <?php echo $school_settings['allow_freeze_global'] ? 'selected' : ''; ?>>Sì</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="add_variation_freeze_max_days" class="form-label">Giorni Massimi di Congelamento</label>
|
||||
<input type="number" class="form-control" id="add_variation_freeze_max_days" name="freeze_max_days">
|
||||
<input type="number" class="form-control precompiled-field" name="freeze_max_days"
|
||||
value="<?php echo $school_settings['freeze_max_days_global']; ?>">
|
||||
<small class="form-text text-muted">Lascia vuoto se non applicabile.</small>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="add_variation_auto_propagate" class="form-label">Propaga in Automatico all'Ordine</label>
|
||||
<select class="form-control" id="add_variation_auto_propagate" name="auto_propagate_to_order">
|
||||
<option value="0">No</option>
|
||||
<option value="1">Sì</option>
|
||||
<select class="form-select precompiled-field" name="auto_propagate_to_order">
|
||||
<option value="0" <?php echo !$school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>No</option>
|
||||
<option value="1" <?php echo $school_settings['auto_propagate_on_purchase'] ? 'selected' : ''; ?>>Sì</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">Se sì, la variazione verrà aggiunta automaticamente agli ordini futuri.</small>
|
||||
</div>
|
||||
@ -934,11 +971,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<input type="text" class="form-control" id="edit_product_variation_name" name="variation_name">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="edit_product_type" class="form-label">Tipo</label>
|
||||
<select class="form-control" id="edit_product_type" name="type" required>
|
||||
<option value="carnet">Carnet</option>
|
||||
<option value="subscription">Abbonamento</option>
|
||||
<option value="drop_in">Lezione Singola</option>
|
||||
<label class="form-label">Tipo <span class="text-danger">*</span></label>
|
||||
<select class="form-select precompiled-field" name="type" required>
|
||||
<?php foreach ($allowed_types as $type): ?>
|
||||
<?php if (isset($types_map[$type])): ?>
|
||||
<option value="<?php echo $type; ?>">
|
||||
<?php echo $types_map[$type]; ?>
|
||||
</option>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3" id="edit_price_section">
|
||||
|
||||
@ -1,135 +1,204 @@
|
||||
<?php
|
||||
require_once 'include/headscript.php'; // Include il file con la connessione al database
|
||||
require_once 'include/headscript.php';
|
||||
|
||||
// Connessione al database
|
||||
$dbHandler = DBHandlerSelect::getInstance();
|
||||
$pdo = $dbHandler->getConnection();
|
||||
|
||||
// Funzioni di colore per terminale (se lo lanci da CLI)
|
||||
function green($text)
|
||||
{
|
||||
return "\033[32m$text\033[0m";
|
||||
}
|
||||
function yellow($text)
|
||||
{
|
||||
return "\033[33m$text\033[0m";
|
||||
}
|
||||
function red($text)
|
||||
{
|
||||
return "\033[31m$text\033[0m";
|
||||
}
|
||||
function cyan($text)
|
||||
{
|
||||
return "\033[36m$text\033[0m";
|
||||
}
|
||||
function magenta($text)
|
||||
{
|
||||
return "\033[35m$text\033[0m";
|
||||
}
|
||||
|
||||
echo cyan("=== AVVIO PROPAGAZIONE AUTOMATICA - " . date('Y-m-d H:i:s') . " ===\n");
|
||||
|
||||
try {
|
||||
// Inizia una transazione
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Seleziona gli ordini con status 'completed' e lezioni disponibili
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.id, o.user_id, o.class_type_id, o.available_entries, o.school_id
|
||||
FROM orders o
|
||||
WHERE o.status = 'completed' AND o.available_entries > 0
|
||||
");
|
||||
$stmt->execute();
|
||||
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$totalBookings = 0;
|
||||
$totalOrders = 0;
|
||||
|
||||
$bookings_created = 0;
|
||||
$orders_propagated = 0;
|
||||
$orderSql = "
|
||||
SELECT o.id, o.order_number, o.user_id, o.school_id, o.available_entries,
|
||||
o.product_id, o.variation_id, o.activation_date,
|
||||
p.name as product_name,
|
||||
pv.name as variation_name,
|
||||
u.email as user_email
|
||||
FROM orders o
|
||||
INNER JOIN products p ON o.product_id = p.id
|
||||
LEFT JOIN product_variations pv ON o.variation_id = pv.id AND pv.id IS NOT NULL
|
||||
LEFT JOIN auth_users u ON o.user_id = u.id
|
||||
WHERE o.status = 'completed'
|
||||
AND o.available_entries > 0
|
||||
AND (p.auto_propagate_to_order = 1 OR pv.auto_propagate_to_order = 1)
|
||||
AND (o.activation_date IS NULL OR o.activation_date <= CURDATE())
|
||||
ORDER BY o.created_at ASC
|
||||
";
|
||||
|
||||
$orderStmt = $pdo->prepare($orderSql);
|
||||
$orderStmt->execute();
|
||||
$orders = $orderStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo yellow("Trovati " . count($orders) . " ordini da propagare automaticamente.\n\n");
|
||||
|
||||
foreach ($orders as $order) {
|
||||
$order_id = $order['id'];
|
||||
$user_id = $order['user_id'];
|
||||
$class_type_id = $order['class_type_id'];
|
||||
$available_entries = $order['available_entries'];
|
||||
$school_id = $order['school_id'];
|
||||
$totalOrders++;
|
||||
$orderId = $order['id'];
|
||||
$orderNumber = $order['order_number'];
|
||||
$userId = $order['user_id'];
|
||||
$userEmail = $order['user_email'];
|
||||
$schoolId = $order['school_id'];
|
||||
$remaining = (int)$order['available_entries'];
|
||||
$productName = $order['variation_name'] ?? $order['product_name'];
|
||||
$activation = $order['activation_date'] ?: 'immediata';
|
||||
|
||||
// Recupera i giorni di chiusura della scuola
|
||||
$offStmt = $pdo->prepare("
|
||||
SELECT start_date, end_date
|
||||
FROM day_off
|
||||
WHERE school_id = ? AND (
|
||||
(start_date >= CURDATE()) OR
|
||||
(end_date >= CURDATE()) OR
|
||||
(start_date <= CURDATE() AND end_date >= CURDATE())
|
||||
)
|
||||
");
|
||||
$offStmt->execute([$school_id]);
|
||||
$off_periods = $offStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
echo magenta("──────────────────────────────────────────────────────\n");
|
||||
echo green("ELABORAZIONE ORDINE #$orderNumber (ID: $orderId)\n");
|
||||
echo green("Utente: $userEmail (ID: $userId) | Scuola ID: $schoolId\n");
|
||||
echo green("Prodotto: $productName | Ingressi da propagare: $remaining | Attivazione: $activation\n");
|
||||
|
||||
// Crea un array di date di chiusura
|
||||
$off_dates = [];
|
||||
foreach ($off_periods as $period) {
|
||||
$start_date = new DateTime($period['start_date']);
|
||||
$end_date = new DateTime($period['end_date']);
|
||||
$interval = new DateInterval('P1D');
|
||||
$date_range = new DatePeriod($start_date, $interval, $end_date->modify('+1 day'));
|
||||
foreach ($date_range as $date) {
|
||||
$off_dates[] = $date->format('Y-m-d');
|
||||
}
|
||||
// Recupera class_type consentiti
|
||||
$ctSql = "SELECT DISTINCT class_type_id FROM product_class_types WHERE product_id = ? AND (variation_id IS NULL OR variation_id = ? OR variation_id = ?)";
|
||||
$ctStmt = $pdo->prepare($ctSql);
|
||||
$ctStmt->execute([$order['product_id'], $order['variation_id'], $order['variation_id']]);
|
||||
$classTypeIds = $ctStmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
if (empty($classTypeIds)) {
|
||||
echo red("Nessun class_type associato al prodotto → SKIP\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Trova le prossime sessioni disponibili per questo class_type_id
|
||||
$sessionStmt = $pdo->prepare("
|
||||
SELECT id, session_date
|
||||
FROM class_sessions
|
||||
WHERE class_type_id = ? AND session_date >= CURDATE() AND status = 'scheduled'
|
||||
ORDER BY session_date ASC, start_time ASC
|
||||
LIMIT ?
|
||||
");
|
||||
$sessionStmt->execute([$class_type_id, $available_entries]);
|
||||
// Nomi delle classi per debug - VERSIONE MIGLIORE
|
||||
$placeholders = str_repeat('?,', count($classTypeIds) - 1) . '?';
|
||||
$namesSql = "
|
||||
SELECT ct.id, CONCAT(c.name, ' - ', ct.level, ' ',
|
||||
CASE ct.day_of_week
|
||||
WHEN 'monday' THEN 'Lun'
|
||||
WHEN 'tuesday' THEN 'Mar'
|
||||
WHEN 'wednesday' THEN 'Mer'
|
||||
WHEN 'thursday' THEN 'Gio'
|
||||
WHEN 'friday' THEN 'Ven'
|
||||
WHEN 'saturday' THEN 'Sab'
|
||||
WHEN 'sunday' THEN 'Dom'
|
||||
END, ' ', TIME_FORMAT(ct.start_time, '%H:%i')
|
||||
) as name
|
||||
FROM class_types ct
|
||||
JOIN classes c ON ct.class_id = c.id
|
||||
WHERE ct.id IN ($placeholders)
|
||||
ORDER BY name
|
||||
";
|
||||
$namesStmt = $pdo->prepare($namesSql);
|
||||
$namesStmt->execute($classTypeIds);
|
||||
$classNames = $namesStmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
echo cyan("Classi consentite (" . count($classTypeIds) . "): " . implode(', ', array_values($classNames)) . "\n");
|
||||
|
||||
// Giorni di chiusura
|
||||
$offStmt = $pdo->prepare("SELECT start_date, end_date FROM day_off WHERE school_id = ? AND end_date >= CURDATE()");
|
||||
$offStmt->execute([$schoolId]);
|
||||
$offDates = [];
|
||||
foreach ($offStmt->fetchAll() as $off) {
|
||||
$start = new DateTime($off['start_date']);
|
||||
$end = new DateTime($off['end_date']);
|
||||
$end->modify('+1 day');
|
||||
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
|
||||
foreach ($period as $d) $offDates[$d->format('Y-m-d')] = true;
|
||||
}
|
||||
|
||||
// Tutte le sessioni future
|
||||
$sessionSql = "
|
||||
SELECT cs.id, cs.session_date, cs.start_time, cs.max_capacity, cs.class_type_id,
|
||||
(SELECT COUNT(*) FROM session_bookings sb
|
||||
WHERE sb.session_id = cs.id
|
||||
AND sb.status IN ('booked','attended','rescheduled')) as booked
|
||||
FROM class_sessions cs
|
||||
WHERE cs.class_type_id IN ($placeholders)
|
||||
AND cs.school_id = ?
|
||||
AND cs.session_date >= ?
|
||||
AND cs.status = 'scheduled'
|
||||
ORDER BY cs.session_date ASC, cs.start_time ASC
|
||||
LIMIT 2000
|
||||
";
|
||||
|
||||
$fromDate = $order['activation_date'] ?: date('Y-m-d');
|
||||
$params = array_merge($classTypeIds, [$schoolId, $fromDate]);
|
||||
$sessionStmt = $pdo->prepare($sessionSql);
|
||||
$sessionStmt->execute($params);
|
||||
$sessions = $sessionStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$bookings_for_order = 0;
|
||||
echo yellow("Trovate " . count($sessions) . " lezioni future per queste classi.\n");
|
||||
|
||||
foreach ($sessions as $session) {
|
||||
$session_id = $session['id'];
|
||||
$session_date = $session['session_date'];
|
||||
$bookedThisOrder = 0;
|
||||
|
||||
// Salta se la data è un giorno di chiusura
|
||||
if (in_array($session_date, $off_dates)) {
|
||||
foreach ($sessions as $s) {
|
||||
if ($remaining <= 0) break;
|
||||
|
||||
$date = $s['session_date'];
|
||||
$time = substr($s['start_time'], 0, 5);
|
||||
$className = $classNames[$s['class_type_id']] ?? 'Sconosciuta';
|
||||
|
||||
if (isset($offDates[$date])) {
|
||||
echo " ⚠️ $date $time → $className → GIORNO DI CHIUSURA → saltata\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verifica la capacità massima della sessione
|
||||
$capacityStmt = $pdo->prepare("
|
||||
SELECT max_capacity
|
||||
FROM class_sessions
|
||||
WHERE id = ?
|
||||
");
|
||||
$capacityStmt->execute([$session_id]);
|
||||
$max_capacity = $capacityStmt->fetchColumn();
|
||||
$free = $s['max_capacity'] ? ($s['max_capacity'] - $s['booked']) : 999;
|
||||
|
||||
$bookingCountStmt = $pdo->prepare("
|
||||
SELECT COUNT(*)
|
||||
FROM session_bookings
|
||||
WHERE session_id = ? AND status IN ('booked', 'attended', 'rescheduled')
|
||||
");
|
||||
$bookingCountStmt->execute([$session_id]);
|
||||
$current_bookings = $bookingCountStmt->fetchColumn();
|
||||
|
||||
if ($max_capacity !== null && $current_bookings >= $max_capacity) {
|
||||
continue; // Salta se la sessione è piena
|
||||
if ($free <= 0) {
|
||||
echo red(" FULL $date $time → $className (Posti: {$s['booked']}/{$s['max_capacity']}) → saltata\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Inserisci la prenotazione in session_bookings
|
||||
$insertStmt = $pdo->prepare("
|
||||
INSERT INTO session_bookings (
|
||||
session_id, user_id, status, booked_at, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, 'booked', NOW(), NOW(), NOW())
|
||||
");
|
||||
$insertStmt->execute([
|
||||
$session_id,
|
||||
$user_id
|
||||
]);
|
||||
$bookings_created++;
|
||||
$bookings_for_order++;
|
||||
// PRENOTA!
|
||||
$insert = $pdo->prepare("INSERT INTO session_bookings
|
||||
(session_id, user_id, order_id, status, booked_at, created_at, updated_at)
|
||||
VALUES (?, ?, ?, 'booked', NOW(), NOW(), NOW())");
|
||||
$insert->execute([$s['id'], $userId, $orderId]);
|
||||
|
||||
$totalBookings++;
|
||||
$bookedThisOrder++;
|
||||
$remaining--;
|
||||
|
||||
echo green(" PRENOTATA $date $time → $className | Posto libero: $free → rimanenti da propagare: $remaining\n");
|
||||
}
|
||||
|
||||
// Aggiorna available_entries e lo stato dell'ordine
|
||||
if ($bookings_for_order > 0) {
|
||||
$updateStmt = $pdo->prepare("
|
||||
UPDATE orders
|
||||
SET available_entries = available_entries - ?,
|
||||
status = 'propagated'
|
||||
WHERE id = ?
|
||||
");
|
||||
$updateStmt->execute([$bookings_for_order, $order_id]);
|
||||
$orders_propagated++;
|
||||
// Aggiornamento ordine
|
||||
if ($bookedThisOrder > 0) {
|
||||
$newStatus = ($remaining <= 0) ? 'propagated' : 'completed';
|
||||
$pdo->prepare("UPDATE orders SET available_entries = ?, status = ? WHERE id = ?")
|
||||
->execute([$remaining, $newStatus, $orderId]);
|
||||
|
||||
echo green("Ordine aggiornato: available_entries = $remaining | status = $newStatus\n");
|
||||
} else {
|
||||
echo yellow("Nessuna lezione disponibile al momento → ci riproverà alla prossima esecuzione\n");
|
||||
}
|
||||
echo magenta("──────────────────────────────────────────────────────\n\n");
|
||||
}
|
||||
|
||||
// Conferma la transazione
|
||||
$pdo->commit();
|
||||
|
||||
echo "Propagazione completata con successo: $bookings_created prenotazioni create, $orders_propagated ordini aggiornati.";
|
||||
} catch (PDOException $e) {
|
||||
// In caso di errore, annulla la transazione
|
||||
echo cyan("=== PROPAGAZIONE COMPLETATA ===\n");
|
||||
echo green("Ordini processati: $totalOrders\n");
|
||||
echo green("Prenotazioni automatiche create: $totalBookings\n");
|
||||
echo cyan("Fine esecuzione: " . date('Y-m-d H:i:s') . "\n");
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
echo "Errore durante la propagazione: " . $e->getMessage();
|
||||
echo red("ERRORE CRITICO: " . $e->getMessage() . "\n");
|
||||
error_log("Auto-propagate error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
@ -843,12 +843,12 @@ $daily_sessions = $stmt->fetchAll();
|
||||
<span class="fs-6">Situazione Clienti</span>
|
||||
</a>
|
||||
<!-- Pulsante Ordini -->
|
||||
<a href="#" class="btn btn-success d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
|
||||
<a href="orders.php" class="btn btn-success d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
|
||||
<i class="bx bx-cart me-2" style="font-size: 20px;"></i>
|
||||
<span class="fs-6">Ordini</span>
|
||||
</a>
|
||||
<!-- Pulsante Finanze -->
|
||||
<a href="#" class="btn btn-warning d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
|
||||
<a href="finances.php" class="btn btn-warning d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
|
||||
<i class="bx bx-dollar me-2" style="font-size: 20px;"></i>
|
||||
<span class="fs-6">Finanze</span>
|
||||
</a>
|
||||
@ -867,7 +867,7 @@ $daily_sessions = $stmt->fetchAll();
|
||||
<span class="fs-6">Giorni di Chiusura</span>
|
||||
</a>
|
||||
<!-- Pulsante Impostazioni -->
|
||||
<a href="#" class="btn btn-dark d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
|
||||
<a href="school_settings.php" class="btn btn-dark d-flex align-items-center px-3 py-2 shadow-sm rounded" style="min-width: 150px;">
|
||||
<i class="bx bx-cog me-2" style="font-size: 20px;"></i>
|
||||
<span class="fs-6">Impostazioni</span>
|
||||
</a>
|
||||
@ -1076,73 +1076,126 @@ $daily_sessions = $stmt->fetchAll();
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Sezione Sessioni della Giornata -->
|
||||
<!-- Sezione Sessioni (Singolo giorno o Intervallo) -->
|
||||
<div class="card radius-10 mb-4">
|
||||
<div class="card-header">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-0">Sessioni della Giornata</h6>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
<form action="" method="GET" class="d-flex align-items-center">
|
||||
<label for="session_date" class="me-2">Seleziona Data:</label>
|
||||
<input type="date" id="session_date" name="session_date" class="form-control" value="<?php echo htmlspecialchars($selected_date); ?>" onchange="this.form.submit()">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h6 class="mb-0">Sessioni Programmata</h6>
|
||||
<div class="d-flex gap-2">
|
||||
<!-- I tuoi filtri data esistenti -->
|
||||
<form action="" method="GET" class="d-flex flex-wrap align-items-center gap-2">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<label class="me-2 mb-0 text-nowrap">Dal:</label>
|
||||
<input type="date" name="start_date" class="form-control form-control-sm" value="<?php echo $_GET['start_date'] ?? date('Y-m-d'); ?>" required>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<label class="me-2 mb-0 text-nowrap">Al:</label>
|
||||
<input type="date" name="end_date" class="form-control form-control-sm" value="<?php echo $_GET['end_date'] ?? ''; ?>">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Mostra</button>
|
||||
<?php if (isset($_GET['start_date'])): ?>
|
||||
<a href="?" class="btn btn-outline-secondary btn-sm">Oggi</a>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<!-- PULSANTE CALENDARIO -->
|
||||
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#calendarModal">
|
||||
<i class="bx bx-calendar"></i> Vista Calendario
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php
|
||||
// Determina le date da mostrare
|
||||
$start_date = $_GET['start_date'] ?? date('Y-m-d');
|
||||
$end_date = $_GET['end_date'] ?? $start_date;
|
||||
|
||||
if ($end_date < $start_date) {
|
||||
echo '<div class="alert alert-warning">La data di fine non può essere precedente alla data di inizio.</div>';
|
||||
$end_date = $start_date;
|
||||
}
|
||||
|
||||
// Recupera tutte le sessioni nell'intervallo
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT cs.*,
|
||||
ct.level, ct.day_of_week, ct.start_time, ct.room_name, ct.teacher_id,
|
||||
c.name AS class_name, c.photo AS class_photo,
|
||||
ct.photo AS variation_photo,
|
||||
t.first_name AS teacher_first_name, t.last_name AS teacher_last_name
|
||||
FROM class_sessions cs
|
||||
JOIN class_types ct ON cs.class_type_id = ct.id
|
||||
JOIN classes c ON ct.class_id = c.id
|
||||
LEFT JOIN teachers t ON cs.teacher_id = t.id
|
||||
WHERE cs.session_date BETWEEN ? AND ?
|
||||
AND c.school_id = ?
|
||||
ORDER BY cs.session_date, cs.start_time
|
||||
");
|
||||
$stmt->execute([$start_date, $end_date, $school_id]);
|
||||
$range_sessions = $stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<div class="mb-3">
|
||||
<strong>
|
||||
<?php if ($start_date === $end_date): ?>
|
||||
Sessioni del <span class="text-primary"><?php echo date('d/m/Y', strtotime($start_date)); ?></span>
|
||||
<?php else: ?>
|
||||
Sessioni dal <span class="text-primary"><?php echo date('d/m/Y', strtotime($start_date)); ?></span>
|
||||
al <span class="text-primary"><?php echo date('d/m/Y', strtotime($end_date)); ?></span>
|
||||
(<?php echo count($range_sessions); ?> totali)
|
||||
<?php endif; ?>
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="dailySessionsTable" class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Data</th>
|
||||
<th>Classe</th>
|
||||
<th>Variazione</th>
|
||||
<th>Livello</th>
|
||||
<th>Orario</th>
|
||||
<th>Sala</th>
|
||||
<th>Insegnante</th>
|
||||
<th>Foto</th>
|
||||
<th>Stato</th>
|
||||
<th>Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($daily_sessions)): ?>
|
||||
<?php if (empty($range_sessions)): ?>
|
||||
<tr>
|
||||
<td colspan="8" class="text-center text-muted">Nessuna sessione trovata per questa data.</td>
|
||||
<td colspan="8" class="text-center text-muted">
|
||||
Nessuna sessione programmata in questo intervallo.
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($daily_sessions as $session): ?>
|
||||
<?php
|
||||
$current_date = '';
|
||||
foreach ($range_sessions as $session):
|
||||
$session_date = $session['session_date'];
|
||||
if ($session_date !== $current_date):
|
||||
$current_date = $session_date;
|
||||
?>
|
||||
<tr class="table-info">
|
||||
<td colspan="8" class="fw-bold text-dark">
|
||||
<?php echo date('d/m/Y (l)', strtotime($session_date)); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<tr>
|
||||
<td><?php echo date('d/m', strtotime($session_date)); ?></td>
|
||||
<td><?php echo htmlspecialchars($session['class_name']); ?></td>
|
||||
<td><?php echo ucfirst($session['level']); ?></td>
|
||||
<td><?php echo substr($session['start_time'], 0, 5); ?> - <?php echo substr($session['end_time'], 0, 5); ?></td>
|
||||
<td><?php echo htmlspecialchars($session['room_name'] ?? '—'); ?></td>
|
||||
<td>
|
||||
<?php echo htmlspecialchars(ucfirst($session['level'])); ?>
|
||||
(<?php echo htmlspecialchars(ucfirst($session['day_of_week'])); ?>)
|
||||
<?php echo $session['teacher_id'] ? htmlspecialchars($session['teacher_first_name'] . ' ' . $session['teacher_last_name']) : '<em>Non assegnato</em>'; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo htmlspecialchars($session['start_time']); ?> -
|
||||
<?php echo htmlspecialchars($session['end_time']); ?>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($session['room_name'] ?? 'Non specificata'); ?></td>
|
||||
<td>
|
||||
<?php if ($session['teacher_id']): ?>
|
||||
<?php echo htmlspecialchars($session['teacher_first_name'] . ' ' . $session['teacher_last_name']); ?>
|
||||
<?php else: ?>
|
||||
Non assegnato
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$photo = $session['variation_photo'] ?? $session['class_photo'];
|
||||
if ($photo): ?>
|
||||
<img src="<?php echo htmlspecialchars($photo); ?>" alt="Foto" style="max-width: 50px; max-height: 50px;">
|
||||
<?php else: ?>
|
||||
Nessuna foto
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge <?php echo $session['status'] === 'scheduled' ? 'bg-info' : ($session['status'] === 'completed' ? 'bg-success' : 'bg-danger'); ?>">
|
||||
<?php echo htmlspecialchars(ucfirst($session['status'])); ?>
|
||||
<span class="badge <?php
|
||||
echo $session['status'] === 'scheduled' ? 'bg-info' : ($session['status'] === 'completed' ? 'bg-success' : 'bg-danger');
|
||||
?>">
|
||||
<?php echo $session['status'] === 'scheduled' ? 'Programmata' : ($session['status'] === 'completed' ? 'Completata' : 'Annullata'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
@ -1155,14 +1208,13 @@ $daily_sessions = $stmt->fetchAll();
|
||||
"end_time" => $session['end_time'],
|
||||
"teacher_id" => $session['teacher_id'],
|
||||
"status" => $session['status']
|
||||
]); ?>)'
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Modifica">
|
||||
]); ?>)'>
|
||||
<i class="bx bx-edit"></i>
|
||||
</button>
|
||||
<form action="" method="POST" style="display:inline;" onsubmit="return confirm('Sei sicuro di voler eliminare questa sessione?');">
|
||||
<form action="" method="POST" style="display:inline;" onsubmit="return confirm('Eliminare questa sessione?');">
|
||||
<input type="hidden" name="action" value="delete_session">
|
||||
<input type="hidden" name="id" value="<?php echo $session['id']; ?>">
|
||||
<button type="submit" class="btn btn-sm btn-danger" data-bs-toggle="tooltip" data-bs-placement="top" title="Elimina">
|
||||
<button type="submit" class="btn btn-sm btn-danger">
|
||||
<i class="bx bx-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
@ -1682,6 +1734,135 @@ $daily_sessions = $stmt->fetchAll();
|
||||
document.getElementById('edit_session_status').value = data.status;
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- MODALE CALENDARIO (GRANDE MA NON FULLSCREEN + FIXATO) -->
|
||||
<div class="modal fade" id="calendarModal" tabindex="-1" aria-labelledby="calendarModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable" style="max-width: 95vw;">
|
||||
<div class="modal-content" style="height: 95vh;">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="calendarModalLabel">
|
||||
Calendario Lezioni
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-0 d-flex flex-column" style="height: 100%;">
|
||||
<div id="fullcalendar-modal" class="flex-grow-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FullCalendar CDN -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/main.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/main.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/locales/it.min.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
let calendar = null;
|
||||
|
||||
const modalElement = document.getElementById('calendarModal');
|
||||
const calendarEl = document.getElementById('fullcalendar-modal');
|
||||
|
||||
// Funzione per inizializzare o aggiornare il calendario
|
||||
function initCalendar() {
|
||||
if (calendar) {
|
||||
calendar.destroy();
|
||||
}
|
||||
|
||||
calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
locale: 'it',
|
||||
initialView: 'timeGridWeek',
|
||||
headerToolbar: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'dayGridMonth,timeGridWeek'
|
||||
},
|
||||
buttonText: {
|
||||
today: 'Oggi',
|
||||
month: 'Mese',
|
||||
week: 'Settimana'
|
||||
},
|
||||
height: '100%',
|
||||
slotMinTime: '06:00:00',
|
||||
slotMaxTime: '23:00:00',
|
||||
events: [
|
||||
<?php
|
||||
$from = date('Y-m-d');
|
||||
$to = date('Y-m-d', strtotime('+90 days'));
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT cs.session_date, cs.start_time, cs.end_time, cs.status,
|
||||
c.name AS class_name, ct.level, ct.room_name,
|
||||
t.first_name, t.last_name
|
||||
FROM class_sessions cs
|
||||
JOIN class_types ct ON cs.class_type_id = ct.id
|
||||
JOIN classes c ON ct.class_id = c.id
|
||||
LEFT JOIN teachers t ON cs.teacher_id = t.id
|
||||
WHERE cs.session_date BETWEEN ? AND ?
|
||||
AND c.school_id = ?
|
||||
");
|
||||
$stmt->execute([$from, $to, $school_id]);
|
||||
foreach ($stmt->fetchAll() as $e) {
|
||||
$title = $e['class_name'];
|
||||
if ($e['level']) $title .= ' - ' . ucfirst($e['level']);
|
||||
if ($e['first_name']) $title .= ' (' . $e['first_name'] . ')';
|
||||
if ($e['room_name']) $title .= ' | ' . $e['room_name'];
|
||||
|
||||
$color = '#0d6efd';
|
||||
if ($e['status'] === 'completed') $color = '#198754';
|
||||
if ($e['status'] === 'cancelled') $color = '#dc3545';
|
||||
|
||||
echo "{
|
||||
title: '" . addslashes($title) . "',
|
||||
start: '{$e['session_date']}T{$e['start_time']}',
|
||||
end: '{$e['session_date']}T{$e['end_time']}',
|
||||
color: '$color'
|
||||
}, ";
|
||||
}
|
||||
?>
|
||||
],
|
||||
eventClick: function(info) {
|
||||
const date = info.event.start.toISOString().split('T')[0];
|
||||
window.location.href = '?start_date=' + date + '&end_date=' + date;
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
}
|
||||
|
||||
// Apri il modale → inizializza e forza resize
|
||||
modalElement.addEventListener('shown.bs.modal', function() {
|
||||
initCalendar();
|
||||
setTimeout(() => calendar.updateSize(), 100);
|
||||
});
|
||||
|
||||
// Se chiudi e riapri, ricarica
|
||||
modalElement.addEventListener('hidden.bs.modal', function() {
|
||||
if (calendar) {
|
||||
calendar.destroy();
|
||||
calendar = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#fullcalendar-modal .fc-header-toolbar {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#fullcalendar-modal .fc-button {
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
|
||||
#fullcalendar-modal .fc-event {
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 3px 6px;
|
||||
font-size: 0.9em;
|
||||
white-space: normal;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
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
|
||||
// Ottieni l'istanza del DBHandlerSelect
|
||||
$dbHandler = DBHandlerSelect::getInstance();
|
||||
$pdo = $dbHandler->getConnection();
|
||||
include('include/headscript.php');
|
||||
|
||||
// Recupera lo school_id e user_id dalla sessione
|
||||
$school_id = session('school_id');
|
||||
|
||||
|
||||
// Controlla se l'utente è loggato
|
||||
if (empty($iduserlogin)) {
|
||||
header('Location: login.php?error=not_logged_in');
|
||||
if (!isset($iduserlogin)) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$school = null;
|
||||
// Costruisci manualmente l'URL assoluto per il logo di default
|
||||
$base_url = rtrim(env('APP_URL'), '/') . '/public/userarea/';
|
||||
$school_logo_path = $base_url . 'yogibook_logo.png'; // Default logo
|
||||
$dbHandler = DBHandlerSelect::getInstance();
|
||||
$pdo = $dbHandler->getConnection();
|
||||
|
||||
// === DATI UTENTE ===
|
||||
$stmt = $pdo->prepare("SELECT first_name, last_name, email, avatar FROM auth_users WHERE id = ?");
|
||||
$stmt->execute([$iduserlogin]);
|
||||
$user = $stmt->fetch();
|
||||
$avatar = $user['avatar'] ? '../upload/users/' . $user['avatar'] : '../assets/images/default-avatar.png';
|
||||
|
||||
// === SCUOLA CORRENTE ===
|
||||
$school_id = session('school_id');
|
||||
$school_name = 'Nessuna scuola selezionata';
|
||||
$school_logo_path = null; // niente default
|
||||
|
||||
if ($school_id) {
|
||||
// Usa il modello School per recuperare i dati della scuola
|
||||
$school = \Vanguard\Models\School::find($school_id);
|
||||
$stmt = $pdo->prepare("SELECT name, logo FROM schools WHERE id = ?");
|
||||
$stmt->execute([$school_id]);
|
||||
$school = $stmt->fetch();
|
||||
|
||||
if ($school) {
|
||||
// Se la scuola esiste, aggiorna il percorso del logo
|
||||
$school_logo_path = $school->logo ? $base_url . $school->logo : $school_logo_path;
|
||||
$school_name = $school['name'];
|
||||
if (!empty($school['logo']) && file_exists("photoschool/" . $school['logo'])) {
|
||||
$school_logo_path = "photoschool/" . $school['logo'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Query per i dati dell'utente
|
||||
$stmt = $pdo->prepare("SELECT first_name, last_name, avatar FROM auth_users WHERE id = ?");
|
||||
$stmt->execute([$iduserlogin]);
|
||||
$user = $stmt->fetch();
|
||||
// Dopo aver recuperato i dati dell'utente
|
||||
$avatar = !empty($user['avatar']) ? '../upload/users/' . $user['avatar'] : '../assets/images/default-avatar.png';
|
||||
|
||||
// Query per recuperare gli ordini dell'utente per la scuola corrente
|
||||
// === ORDINI UTENTE ===
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_number, o.created_at, o.price, o.total_entries, o.available_entries, o.available_recoveries, o.expiration_date, o.activation_date,
|
||||
p.name AS product_name, pv.name AS variation_name, c.name AS class_name, ct.level, ct.day_of_week
|
||||
SELECT o.*, p.name AS product_name, pv.name AS variation_name,
|
||||
c.name AS class_name, ct.level, ct.day_of_week
|
||||
FROM orders o
|
||||
JOIN products p ON o.product_id = p.id
|
||||
JOIN product_variations pv ON o.variation_id = pv.id
|
||||
LEFT JOIN product_variations pv ON o.variation_id = pv.id
|
||||
LEFT JOIN classes c ON o.class_id = c.id
|
||||
LEFT JOIN class_types ct ON o.class_type_id = ct.id
|
||||
LEFT JOIN classes c ON ct.class_id = c.id
|
||||
WHERE o.user_id = ? AND o.school_id = ?
|
||||
ORDER BY o.created_at DESC
|
||||
");
|
||||
$stmt->execute([$iduserlogin, $school_id]);
|
||||
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$orders = $stmt->fetchAll();
|
||||
|
||||
// === STATISTICHE RAPIDE ===
|
||||
$total_spent = array_sum(array_column($orders, 'price'));
|
||||
$total_entries = array_sum(array_column($orders, 'total_entries'));
|
||||
$available_entries = array_sum(array_column($orders, 'available_entries'));
|
||||
$active_orders = count(array_filter($orders, fn($o) => $o['status'] === 'completed' && (!$o['expiration_date'] || strtotime($o['expiration_date']) >= time())));
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="it">
|
||||
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!--favicon-->
|
||||
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
||||
<title>La mia Dashboard - Yogiboook</title>
|
||||
<?php include('cssinclude.php'); ?>
|
||||
<?php include('siteinfo.php'); ?>
|
||||
<style>
|
||||
.page-content {
|
||||
background-color: #f0f4f5;
|
||||
/* Sfondo pastello chiaro (grigio-azzurro) */
|
||||
:root {
|
||||
--pastel-blue: #94bacc;
|
||||
--pastel-green: #a3d9b1;
|
||||
--pastel-pink: #f8bbd0;
|
||||
--pastel-yellow: #fff8c4;
|
||||
}
|
||||
|
||||
.card-pastel {
|
||||
background-color: rgb(149, 217, 248);
|
||||
/* Verde menta pastello */
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||||
/* Ombra leggera */
|
||||
border: none;
|
||||
/* Rimuoviamo il bordo predefinito */
|
||||
}
|
||||
|
||||
.avatar-border {
|
||||
border: 3px solid #a3d9b1;
|
||||
/* Bordo verde pastello intorno all'avatar */
|
||||
}
|
||||
|
||||
.btn-pastel {
|
||||
background-color: rgb(148, 186, 204);
|
||||
/* Colore pulsante coordinato */
|
||||
border: none;
|
||||
transition: background-color 0.3s ease;
|
||||
/* Effetto hover */
|
||||
}
|
||||
|
||||
.btn-pastel:hover {
|
||||
background-color: rgb(155, 189, 221);
|
||||
/* Colore più scuro al passaggio del mouse */
|
||||
}
|
||||
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'Poppins', sans-serif;
|
||||
/* Font moderno e morbido, se disponibile */
|
||||
color: #333;
|
||||
/* Colore testo scuro per contrasto */
|
||||
}
|
||||
|
||||
.calendar-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/* Permette ai filtri di andare a capo su schermi piccoli */
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: 10px;
|
||||
/* Spazio tra gli elementi */
|
||||
}
|
||||
|
||||
.lesson-card,
|
||||
.order-card {
|
||||
background-color: #ffffff;
|
||||
border-left: 4px solid #c8e6c9;
|
||||
/* Verde per le lezioni programmate e ordini */
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.lesson-card:hover,
|
||||
.order-card:hover {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
background-color: #f8bbd0;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, #94bacc, #a3d9b1);
|
||||
color: white;
|
||||
padding: 5px 15px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.9rem;
|
||||
margin: 0 5px;
|
||||
/* Spazio tra i pulsanti */
|
||||
}
|
||||
|
||||
.filter-btn.active {
|
||||
background-color: #bbdefb;
|
||||
.card-soft {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.reschedule-btn {
|
||||
background-color: #c8e6c9;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 0.85rem;
|
||||
padding: 5px 10px;
|
||||
.stat-card {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.lesson-details p,
|
||||
.order-details p {
|
||||
margin-bottom: 0.2rem;
|
||||
/* Spazio ridotto tra le righe */
|
||||
.stat-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.avatar-circle {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: cover;
|
||||
border: 4px solid white;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.table-pastel thead {
|
||||
background-color: var(--pastel-blue);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.badge-soft {
|
||||
padding: 0.4em 0.8em;
|
||||
border-radius: 50px;
|
||||
font-size: 0.85rem;
|
||||
/* Testo più piccolo per adattarsi meglio */
|
||||
}
|
||||
|
||||
.order-details .price {
|
||||
font-weight: bold;
|
||||
color: #28a745;
|
||||
/* Verde per il prezzo */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!--wrapper-->
|
||||
<div class="wrapper">
|
||||
<!--sidebar wrapper -->
|
||||
<?php include('include/navbar.php'); ?>
|
||||
<!--end sidebar wrapper -->
|
||||
<!--start header -->
|
||||
<?php include('include/topbar.php'); ?>
|
||||
<!--end header -->
|
||||
<!--start page wrapper -->
|
||||
|
||||
<div class="page-wrapper">
|
||||
<div class="page-content">
|
||||
<div class="page-content" style="background: linear-gradient(to bottom, #f0f8ff, #f8f9fa); min-height: 100vh;">
|
||||
|
||||
<!-- Sezione Scuola -->
|
||||
<div class="card card-pastel radius-10 mb-4">
|
||||
<div class="card-body text-center">
|
||||
<?php if ($school): ?>
|
||||
<h5 class="mb-3">Sei loggato nella scuola: <?php echo htmlspecialchars($school->name); ?></h5>
|
||||
<img src="<?php echo $school_logo_path; ?>" alt="School Logo" style="max-height: 100px;">
|
||||
<?php else: ?>
|
||||
<h5 class="mb-3">Nessuna scuola selezionata</h5>
|
||||
<img src="<?php echo $school_logo_path; ?>" alt="Default Logo" style="max-height: 100px;">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Sezione Profilo -->
|
||||
<div class="card card-pastel radius-10">
|
||||
<div class="card-header">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-0">Stato Utente</h6>
|
||||
<!-- SCUOLA + BENVENUTO -->
|
||||
<div class="container-fluid px-4 pt-4">
|
||||
<div class="card card-pastel radius-20 shadow-lg mb-4 position-relative">
|
||||
<div class="card-body text-center py-5">
|
||||
|
||||
<!-- Logo solo se esiste -->
|
||||
<?php if ($school_logo_path): ?>
|
||||
<img src="<?php echo htmlspecialchars($school_logo_path); ?>"
|
||||
alt="Logo <?php echo htmlspecialchars($school_name); ?>"
|
||||
class="mb-4 rounded-3 shadow"
|
||||
style="height: 90px; object-fit: contain;">
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Saluto -->
|
||||
<h2 class="mb-2 text-white">
|
||||
Ciao<?php echo $user['first_name'] ? ', ' . htmlspecialchars($user['first_name']) : ''; ?>!
|
||||
</h2>
|
||||
<p class="mb-0 fs-4 text-white opacity-90">
|
||||
Sei nella scuola: <strong><?php echo htmlspecialchars($school_name); ?></strong>
|
||||
</p>
|
||||
|
||||
<!-- PULSANTI IN RIGA (uno accanto all'altro) -->
|
||||
<div class="position-absolute top-0 end-0 mt-3 me-3 d-flex gap-2">
|
||||
<a href="my_lessons.php" class="btn btn-light btn-lg shadow-sm px-4">
|
||||
<i class="bx bx-calendar-heart me-2"></i>Le mie lezioni
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-light btn-lg shadow-sm px-4"
|
||||
data-bs-toggle="modal" data-bs-target="#changeSchoolModal">
|
||||
<i class="bx bx-transfer me-2"></i>Cambia scuola
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-column align-items-center text-center">
|
||||
<!-- Saluto e Nome -->
|
||||
<h5 class="mb-3">Ciao, <?php echo htmlspecialchars($user['first_name']); ?>!</h5>
|
||||
</div>
|
||||
|
||||
<!-- Sezione dei box -->
|
||||
<div class="row">
|
||||
<!-- Lezioni programmate -->
|
||||
<div class="col-12 col-md-4 mb-3">
|
||||
<div class="card card-pastel radius-10 text-center" style="background-color: #c8e6c9;">
|
||||
<div class="card-body">
|
||||
<h6 class="mb-2">Lezioni Programmate</h6>
|
||||
<h3 class="mb-0 text-primary">5</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Ticket da programmare -->
|
||||
<div class="col-12 col-md-4 mb-3">
|
||||
<div class="card card-pastel radius-10 text-center" style="background-color: #f8bbd0;">
|
||||
<div class="card-body">
|
||||
<h6 class="mb-2">Ticket da Programmare</h6>
|
||||
<h3 class="mb-0 text-primary">3</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Lezioni da confermare -->
|
||||
<div class="col-12 col-md-4 mb-3">
|
||||
<div class="card card-pastel radius-10 text-center" style="background-color: #bbdefb;">
|
||||
<div class="card-body">
|
||||
<h6 class="mb-2">Lezioni da Confermare</h6>
|
||||
<h3 class="mb-0 text-primary">2</h3>
|
||||
</div>
|
||||
<!-- PROFILO + STATISTICHE -->
|
||||
<div class="row g-4 mb-5">
|
||||
<div class="col-lg-4">
|
||||
<div class="card stat-card text-center h-100">
|
||||
<div class="card-body">
|
||||
<img src="<?php echo $avatar; ?>" alt="Avatar" class="rounded-circle avatar-circle mb-3">
|
||||
<h5><?php echo htmlspecialchars($user['first_name'] . ' ' . $user['last_name']); ?></h5>
|
||||
<p class="text-muted"><?php echo htmlspecialchars($user['email']); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sezione delle lezioni future -->
|
||||
<div class="card card-pastel radius-10 mt-4">
|
||||
<div class="card-header">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-0">Le tue Lezioni Future</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Header con calendario e filtri -->
|
||||
<div class="calendar-header">
|
||||
<!-- Calendario per cambiare mese -->
|
||||
<div>
|
||||
<input type="month" id="monthPicker" value="2025-04" class="form-control" style="width: 150px;">
|
||||
</div>
|
||||
<!-- Filtri -->
|
||||
<div>
|
||||
<button class="filter-btn active">Programmate</button>
|
||||
<button class="filter-btn">Effettuate</button>
|
||||
<button class="filter-btn">Perse</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lista delle lezioni -->
|
||||
<div class="row">
|
||||
<!-- Lezione 1 -->
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<div class="card lesson-card radius-10">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div class="lesson-details">
|
||||
<h6 class="mb-1">Yoga Flow</h6>
|
||||
<p class="text-muted">15 Apr 2025, 18:00</p>
|
||||
<p class="text-muted">Scuola: Yoga Harmony</p>
|
||||
<p class="text-muted">Via Roma 12, Milano</p>
|
||||
</div>
|
||||
<button class="reschedule-btn">Riprogramma</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Lezione 2 -->
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<div class="card lesson-card radius-10">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<div class="lesson-details">
|
||||
<h6 class="mb-1">Hatha Yoga</h6>
|
||||
<p class="text-muted">20 Apr 2025, 09:00</p>
|
||||
<p class="text-muted">Scuola: Zen Studio</p>
|
||||
<p class="text-muted">Corso Italia 45, Torino</p>
|
||||
</div>
|
||||
<button class="reschedule-btn">Riprogramma</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nuova Sezione: Riepilogo Ordini -->
|
||||
<div class="card card-pastel radius-10 mt-4">
|
||||
<div class="card-header">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-0">I tuoi Ordini</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (empty($orders)): ?>
|
||||
<p class="text-center text-muted">Non hai ancora effettuato ordini per questa scuola.</p>
|
||||
<?php else: ?>
|
||||
<div class="row">
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<div class="card order-card radius-10">
|
||||
<div class="card-body">
|
||||
<div class="order-details">
|
||||
<h6 class="mb-1">Ordine #<?php echo htmlspecialchars($order['order_number']); ?></h6>
|
||||
<p class="text-muted">Data: <?php echo date('d/m/Y H:i', strtotime($order['created_at'])); ?></p>
|
||||
<p><strong>Prodotto:</strong> <?php echo htmlspecialchars($order['product_name']); ?></p>
|
||||
<p><strong>Variazione:</strong> <?php echo htmlspecialchars($order['variation_name']); ?></p>
|
||||
<?php if (!empty($order['class_name'])): ?>
|
||||
<p><strong>Classe:</strong> <?php echo htmlspecialchars($order['class_name'] . ' - ' . $order['level'] . ' (' . $order['day_of_week'] . ')'); ?></p>
|
||||
<?php endif; ?>
|
||||
<p><strong>Entrate Totali:</strong> <?php echo $order['total_entries']; ?></p>
|
||||
<p><strong>Recuperi Disponibili:</strong> <?php echo $order['available_recoveries']; ?></p>
|
||||
<?php if (!empty($order['expiration_date'])): ?>
|
||||
<p><strong>Valido fino al:</strong> <?php echo date('d/m/Y', strtotime($order['expiration_date'])); ?></p>
|
||||
<?php endif; ?>
|
||||
<p class="price"><strong>Prezzo:</strong> €<?php echo number_format($order['price'], 2); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-8">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card text-center h-100">
|
||||
<div class="card-body">
|
||||
<h3 class="text-primary fw-bold"><?php echo count($orders); ?></h3>
|
||||
<p class="mb-0">Ordini totali</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card text-center h-100">
|
||||
<div class="card-body">
|
||||
<h3 class="text-success fw-bold">€<?php echo number_format($total_spent, 2); ?></h3>
|
||||
<p class="mb-0">Speso in totale</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card text-center h-100">
|
||||
<div class="card-body">
|
||||
<h3 class="text-info fw-bold"><?php echo $available_entries; ?></h3>
|
||||
<p class="mb-0">Ingressi disponibili</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- I TUOI ORDINI -->
|
||||
<div class="card radius-20 shadow-lg">
|
||||
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
|
||||
<h4 class="mb-0">I tuoi ordini</h4>
|
||||
<span class="badge bg-light text-dark"><?php echo count($orders); ?> totali</span>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<?php if (empty($orders)): ?>
|
||||
<div class="text-center py-5">
|
||||
<i class="bx bx-package bx-lg text-muted"></i>
|
||||
<h5 class="text-muted mt-3">Non hai ancora effettuato ordini</h5>
|
||||
<a href="products.php" class="btn btn-primary mt-3">Vai ai corsi</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="table-pastel">
|
||||
<tr>
|
||||
<th>Data</th>
|
||||
<th>Ordine</th>
|
||||
<th>Prodotto</th>
|
||||
<th>Ingressi</th>
|
||||
<th>Scadenza</th>
|
||||
<th>Prezzo</th>
|
||||
<th>Stato</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($orders as $o): ?>
|
||||
<tr class="table-light">
|
||||
<td><?php echo date('d/m/Y', strtotime($o['created_at'])); ?></td>
|
||||
<td><strong>#<?php echo $o['order_number']; ?></strong></td>
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($o['product_name']); ?></strong>
|
||||
<?php if ($o['variation_name']): ?>
|
||||
<br><small class="text-success"><?php echo htmlspecialchars($o['variation_name']); ?></small>
|
||||
<?php endif; ?>
|
||||
<?php if ($o['class_name']): ?>
|
||||
<br><small class="text-info"><?php echo htmlspecialchars($o['class_name']); ?></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($o['available_entries'] != $o['total_entries']): ?>
|
||||
<span class="text-success"><?php echo $o['available_entries']; ?></span>/<?php echo $o['total_entries']; ?>
|
||||
<?php else: ?>
|
||||
<?php echo $o['total_entries']; ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($o['expiration_date']): ?>
|
||||
<span class="<?php echo strtotime($o['expiration_date']) < time() ? 'text-danger' : 'text-warning'; ?>">
|
||||
<?php echo date('d/m/Y', strtotime($o['expiration_date'])); ?>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<em>Nessuna</em>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="text-success fw-bold">€<?php echo number_format($o['price'], 2); ?></td>
|
||||
<td>
|
||||
<span class="badge-soft <?php echo $o['status'] == 'completed' ? 'bg-success' : ($o['status'] == 'pending' ? 'bg-warning' : 'bg-secondary'); ?>">
|
||||
<?php echo ucfirst($o['status']); ?>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end page wrapper -->
|
||||
<!--start overlay-->
|
||||
<div class="overlay toggle-icon"></div>
|
||||
<!--end overlay-->
|
||||
<!--Start Back To Top Button-->
|
||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||
<!--End Back To Top Button-->
|
||||
|
||||
<?php include('include/footer.php'); ?>
|
||||
</div>
|
||||
<!--end wrapper-->
|
||||
|
||||
<!-- search modal -->
|
||||
<?php //include('include/searchmodal.php');
|
||||
?>
|
||||
<!-- end search modal -->
|
||||
|
||||
<!--start switcher-->
|
||||
<?php //include('include/themeswitcher.php');
|
||||
?>
|
||||
<!--end switcher-->
|
||||
<?php include('jsinclude.php'); ?>
|
||||
<!-- Modal Cambia Scuola -->
|
||||
<div class="modal fade" id="changeSchoolModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title">Scegli la scuola</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center py-5">
|
||||
<i class="bx bx-building-house bx-lg text-muted"></i>
|
||||
<h4 class="mt-3 text-muted">Le tue scuole</h4>
|
||||
<p class="text-muted">Qui compariranno tutte le scuole in cui sei iscritto</p>
|
||||
<div class="spinner-border text-primary mt-4" role="status">
|
||||
<span class="visually-hidden">Caricamento...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user