1031 lines
35 KiB
PHP
1031 lines
35 KiB
PHP
<?php
|
||
require_once('include/headscript.php');
|
||
|
||
/**
|
||
* Anteprima "scheda evento" pubblica (prototipo del widget WordPress).
|
||
* Versione COMPATTA + espandibile:
|
||
* - stato compatto: data, titolo, capacità/luogo/orario, prezzo, prenotazione
|
||
* - "Dettagli": espande la scheda completa (cover, descrizione, gallery, mappa,
|
||
* per chi è adatto / cosa portare / istruzioni)
|
||
* Prenotazione a passo unico: qty + "Prenota" rivela Nome/Cognome/Email + consensi
|
||
* nella stessa card. In anteprima "Conferma" non invia: mostra un riepilogo.
|
||
*/
|
||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||
|
||
function e($value): string
|
||
{
|
||
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||
}
|
||
|
||
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
||
if ($id <= 0) {
|
||
http_response_code(404);
|
||
echo 'Evento non trovato';
|
||
exit();
|
||
}
|
||
|
||
$st = $pdo->prepare("SELECT e.*, u.first_name AS cf, u.last_name AS cl
|
||
FROM events e LEFT JOIN auth_users u ON u.id = e.user_id
|
||
WHERE e.id = ?");
|
||
$st->execute([$id]);
|
||
$ev = $st->fetch(PDO::FETCH_ASSOC);
|
||
if (!$ev) {
|
||
http_response_code(404);
|
||
echo 'Evento non trovato';
|
||
exit();
|
||
}
|
||
|
||
$bs = $pdo->prepare("SELECT COALESCE(SUM(seats),0) FROM event_bookings WHERE event_id = ? AND status IN ('confirmed','pending','offered')");
|
||
$bs->execute([$id]);
|
||
$booked = (int) $bs->fetchColumn();
|
||
$maxSeats = (int) $ev['max_seats'];
|
||
$remaining = max(0, $maxSeats - $booked);
|
||
$soldOut = $remaining <= 0;
|
||
$maxPer = max(1, (int) $ev['max_per_booking']);
|
||
$waitlistOn = ($ev['waitlist_enabled'] ?? 'N') === 'Y';
|
||
$waitMode = $soldOut && $waitlistOn; // pieno ma con lista d'attesa
|
||
$hardFull = $soldOut && !$waitlistOn; // pieno senza lista d'attesa
|
||
$maxQty = $soldOut ? ($waitMode ? $maxPer : 0) : max(1, min($maxPer, $remaining));
|
||
|
||
$cost = (float) $ev['cost'];
|
||
$curr = $ev['currency'] ?: 'EUR';
|
||
$symbols = ['EUR' => '€', 'USD' => '$', 'GBP' => '£', 'CHF' => 'CHF'];
|
||
$sym = $symbols[$curr] ?? $curr;
|
||
$priceLabel = $cost > 0 ? $sym . number_format($cost, 2, ',', '.') : 'Gratuito';
|
||
|
||
$color = (isset($ev['color']) && preg_match('/^#[0-9a-fA-F]{6}$/', $ev['color'])) ? $ev['color'] : '#4CAF50';
|
||
|
||
$gallery = [];
|
||
if (!empty($ev['gallery'])) {
|
||
$g = json_decode($ev['gallery'], true);
|
||
if (is_array($g)) {
|
||
$gallery = $g;
|
||
}
|
||
}
|
||
|
||
$mesiAbbr = [1 => 'GEN', 2 => 'FEB', 3 => 'MAR', 4 => 'APR', 5 => 'MAG', 6 => 'GIU', 7 => 'LUG', 8 => 'AGO', 9 => 'SET', 10 => 'OTT', 11 => 'NOV', 12 => 'DIC'];
|
||
$mesi = [1 => 'gennaio', 2 => 'febbraio', 3 => 'marzo', 4 => 'aprile', 5 => 'maggio', 6 => 'giugno', 7 => 'luglio', 8 => 'agosto', 9 => 'settembre', 10 => 'ottobre', 11 => 'novembre', 12 => 'dicembre'];
|
||
|
||
$startTs = strtotime($ev['starts_at']);
|
||
$dayNum = (int) date('j', $startTs);
|
||
$monAbbr = $mesiAbbr[(int) date('n', $startTs)];
|
||
$dateLong = $dayNum . ' ' . $mesi[(int) date('n', $startTs)] . ' ' . date('Y', $startTs);
|
||
$timeLabel = date('H:i', $startTs);
|
||
if (!empty($ev['ends_at'])) {
|
||
$timeLabel .= '–' . date('H:i', strtotime($ev['ends_at']));
|
||
}
|
||
|
||
$organizer = trim((string) $ev['organizer_name']) !== ''
|
||
? $ev['organizer_name']
|
||
: trim(($ev['cf'] ?? '') . ' ' . ($ev['cl'] ?? ''));
|
||
|
||
$mapQuery = trim((string) $ev['address']) !== ''
|
||
? $ev['address']
|
||
: (($ev['lat'] !== null && $ev['lng'] !== null) ? ($ev['lat'] . ',' . $ev['lng']) : '');
|
||
|
||
$hasDetails = trim((string) $ev['description']) !== ''
|
||
|| trim((string) $ev['suitable_for']) !== ''
|
||
|| trim((string) $ev['what_to_bring']) !== ''
|
||
|| trim((string) $ev['instructions']) !== ''
|
||
|| !empty($ev['cover_image'])
|
||
|| !empty($gallery)
|
||
|| $mapQuery !== '';
|
||
|
||
function textBlock(?string $t): string
|
||
{
|
||
return nl2br(e((string) $t));
|
||
}
|
||
?>
|
||
<!doctype html>
|
||
<html lang="it">
|
||
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<title><?php echo e($ev['title']); ?> — Anteprima</title>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
||
|
||
<style>
|
||
:root {
|
||
--accent: <?php echo $color; ?>;
|
||
--ink: #2b2622;
|
||
--muted: #8c837c;
|
||
--line: #ece7e2;
|
||
--paper: #faf8f6;
|
||
--card: #ffffff;
|
||
--accent-soft: color-mix(in srgb, var(--accent) 10%, white);
|
||
--accent-tint: color-mix(in srgb, var(--accent) 16%, white);
|
||
--accent-ink: color-mix(in srgb, var(--accent) 62%, black);
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
background: var(--paper);
|
||
color: var(--ink);
|
||
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||
line-height: 1.55;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
.preview-bar {
|
||
background: var(--ink);
|
||
color: #f4efe9;
|
||
font-size: 13px;
|
||
text-align: center;
|
||
padding: 8px 16px;
|
||
}
|
||
|
||
.wrap {
|
||
max-width: 720px;
|
||
margin: 0 auto;
|
||
padding: 26px 18px 60px;
|
||
}
|
||
|
||
.card {
|
||
background: var(--card);
|
||
border-radius: 18px;
|
||
overflow: hidden;
|
||
box-shadow: 0 14px 40px rgba(43, 38, 34, 0.10);
|
||
}
|
||
|
||
/* ---------- HEADER COMPATTO ---------- */
|
||
.chead {
|
||
display: flex;
|
||
gap: 16px;
|
||
padding: 18px 22px;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.date-chip {
|
||
flex-shrink: 0;
|
||
border: 1px solid var(--line);
|
||
border-radius: 12px;
|
||
padding: 7px 11px 5px;
|
||
text-align: center;
|
||
min-width: 54px;
|
||
}
|
||
|
||
.date-chip .m {
|
||
font-size: 10.5px;
|
||
font-weight: 600;
|
||
letter-spacing: .12em;
|
||
color: var(--accent-ink);
|
||
}
|
||
|
||
.date-chip .d {
|
||
font-family: 'Fraunces', serif;
|
||
font-size: 23px;
|
||
font-weight: 600;
|
||
color: var(--ink);
|
||
line-height: 1;
|
||
}
|
||
|
||
.chead-thumb {
|
||
width: 76px;
|
||
height: 76px;
|
||
border-radius: 12px;
|
||
object-fit: cover;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.chead .main {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.title-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.title-row h1 {
|
||
font-family: 'Fraunces', serif;
|
||
font-weight: 500;
|
||
font-size: 21px;
|
||
margin: 0;
|
||
color: var(--ink);
|
||
}
|
||
|
||
.toggle {
|
||
background: none;
|
||
border: none;
|
||
color: var(--accent-ink);
|
||
font-weight: 600;
|
||
font-size: 13px;
|
||
cursor: pointer;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 2px 2px;
|
||
}
|
||
|
||
.toggle svg {
|
||
width: 15px;
|
||
height: 15px;
|
||
transition: transform .2s;
|
||
}
|
||
|
||
.toggle.open svg {
|
||
transform: rotate(180deg);
|
||
}
|
||
|
||
.cmeta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px 20px;
|
||
margin-top: 9px;
|
||
}
|
||
|
||
.cmeta .item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
color: var(--muted);
|
||
font-size: 13.5px;
|
||
}
|
||
|
||
.cmeta .item svg {
|
||
width: 16px;
|
||
height: 16px;
|
||
color: var(--accent-ink);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.cmeta .item strong {
|
||
color: var(--ink);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.price-badge {
|
||
flex-shrink: 0;
|
||
align-self: flex-start;
|
||
background: var(--accent);
|
||
color: #fff;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
padding: 7px 13px;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
/* ---------- DETTAGLI ESPANDIBILI ---------- */
|
||
.details {
|
||
display: none;
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
|
||
.details.open {
|
||
display: block;
|
||
}
|
||
|
||
.hero {
|
||
position: relative;
|
||
height: 260px;
|
||
background: linear-gradient(135deg, var(--accent-ink), var(--accent));
|
||
}
|
||
|
||
.hero img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
display: block;
|
||
}
|
||
|
||
.hero .emblem {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: rgba(255, 255, 255, .35);
|
||
}
|
||
|
||
.hero .emblem svg {
|
||
width: 72px;
|
||
height: 72px;
|
||
}
|
||
|
||
.body {
|
||
padding: 22px;
|
||
}
|
||
|
||
.section+.section {
|
||
margin-top: 24px;
|
||
}
|
||
|
||
.section h3 {
|
||
font-family: 'Fraunces', serif;
|
||
font-weight: 600;
|
||
font-size: 18px;
|
||
color: var(--ink);
|
||
margin: 0 0 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 9px;
|
||
}
|
||
|
||
.section h3 svg {
|
||
width: 19px;
|
||
height: 19px;
|
||
color: var(--accent-ink);
|
||
}
|
||
|
||
.desc {
|
||
font-size: 15px;
|
||
color: #4a433d;
|
||
}
|
||
|
||
.desc :where(p) {
|
||
margin: 0 0 10px;
|
||
}
|
||
|
||
.desc :where(img) {
|
||
max-width: 100%;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.detail-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
||
gap: 12px;
|
||
}
|
||
|
||
.detail {
|
||
background: var(--accent-soft);
|
||
border: 1px solid color-mix(in srgb, var(--accent) 18%, white);
|
||
border-radius: 13px;
|
||
padding: 14px 15px;
|
||
}
|
||
|
||
.detail .h {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-weight: 600;
|
||
color: var(--accent-ink);
|
||
margin-bottom: 6px;
|
||
font-size: 13.5px;
|
||
}
|
||
|
||
.detail .h svg {
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
|
||
.detail .t {
|
||
font-size: 13.5px;
|
||
color: #4a433d;
|
||
}
|
||
|
||
.gallery {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.gallery img {
|
||
width: 100px;
|
||
height: 100px;
|
||
object-fit: cover;
|
||
border-radius: 11px;
|
||
cursor: pointer;
|
||
transition: transform .15s, box-shadow .15s;
|
||
}
|
||
|
||
.gallery img:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 8px 18px rgba(0, 0, 0, .15);
|
||
}
|
||
|
||
.map {
|
||
border: 0;
|
||
width: 100%;
|
||
height: 210px;
|
||
border-radius: 13px;
|
||
display: block;
|
||
}
|
||
|
||
/* ---------- BOOKING ---------- */
|
||
.booking {
|
||
padding: 18px 22px;
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
|
||
.booking-compact {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
gap: 18px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.bc-block .lbl {
|
||
font-size: 12px;
|
||
color: var(--muted);
|
||
text-transform: uppercase;
|
||
letter-spacing: .05em;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.bc-title {
|
||
font-family: 'Fraunces', serif;
|
||
font-weight: 600;
|
||
font-size: 18px;
|
||
color: var(--ink);
|
||
margin-right: auto;
|
||
align-self: center;
|
||
}
|
||
|
||
.stepper {
|
||
display: flex;
|
||
align-items: center;
|
||
border: 1px solid var(--line);
|
||
border-radius: 11px;
|
||
overflow: hidden;
|
||
background: #fff;
|
||
}
|
||
|
||
.stepper button {
|
||
border: none;
|
||
background: #fff;
|
||
width: 42px;
|
||
height: 44px;
|
||
font-size: 21px;
|
||
color: var(--accent-ink);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.stepper button:disabled {
|
||
color: #cfc8c2;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.stepper .n {
|
||
width: 50px;
|
||
text-align: center;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.total-box .val {
|
||
font-family: 'Fraunces', serif;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: var(--accent-ink);
|
||
}
|
||
|
||
.cta {
|
||
border: none;
|
||
border-radius: 11px;
|
||
background: var(--accent);
|
||
color: #fff;
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
font-family: inherit;
|
||
cursor: pointer;
|
||
transition: filter .15s;
|
||
}
|
||
|
||
.cta:hover {
|
||
filter: brightness(.94);
|
||
}
|
||
|
||
.cta:disabled {
|
||
background: #cfc8c2;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.cta.compact {
|
||
padding: 13px 24px;
|
||
}
|
||
|
||
.cta.full {
|
||
width: 100%;
|
||
padding: 14px;
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.booking-form {
|
||
display: none;
|
||
margin-top: 18px;
|
||
padding-top: 18px;
|
||
border-top: 1px dashed var(--line);
|
||
}
|
||
|
||
.booking-form.open {
|
||
display: block;
|
||
}
|
||
|
||
.field-row {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 12px;
|
||
}
|
||
|
||
.field {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.field label {
|
||
display: block;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: var(--ink);
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.field label .req {
|
||
color: #c0392b;
|
||
}
|
||
|
||
.field input {
|
||
width: 100%;
|
||
border: 1px solid var(--line);
|
||
border-radius: 10px;
|
||
padding: 11px 13px;
|
||
font-size: 15px;
|
||
font-family: inherit;
|
||
background: #fff;
|
||
color: var(--ink);
|
||
}
|
||
|
||
.field input:focus {
|
||
outline: none;
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, white);
|
||
}
|
||
|
||
.consent {
|
||
font-size: 13px;
|
||
color: #4a433d;
|
||
display: flex;
|
||
gap: 9px;
|
||
align-items: flex-start;
|
||
margin-bottom: 9px;
|
||
}
|
||
|
||
.consent input {
|
||
margin-top: 3px;
|
||
}
|
||
|
||
.consent a {
|
||
color: var(--accent-ink);
|
||
}
|
||
|
||
.soldout-note {
|
||
text-align: center;
|
||
font-weight: 600;
|
||
color: #c0392b;
|
||
}
|
||
|
||
.waitlist-banner {
|
||
background: color-mix(in srgb, var(--accent) 12%, white);
|
||
color: var(--accent-ink);
|
||
border-radius: 12px;
|
||
padding: 12px 14px;
|
||
font-size: 13.5px;
|
||
margin-bottom: 14px;
|
||
}
|
||
|
||
.form-error {
|
||
color: #c0392b;
|
||
font-size: 13px;
|
||
margin-top: 8px;
|
||
min-height: 18px;
|
||
}
|
||
|
||
.booking-done {
|
||
text-align: center;
|
||
padding: 6px 4px;
|
||
}
|
||
|
||
.booking-done .ok {
|
||
width: 52px;
|
||
height: 52px;
|
||
border-radius: 50%;
|
||
background: var(--accent);
|
||
color: #fff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin: 0 auto 10px;
|
||
}
|
||
|
||
.booking-done h3 {
|
||
margin: 0 0 6px;
|
||
font-family: 'Fraunces', serif;
|
||
}
|
||
|
||
.booking-done p {
|
||
color: #4a433d;
|
||
font-size: 14px;
|
||
margin: 2px 0;
|
||
}
|
||
|
||
.booking-done .hintline {
|
||
color: var(--muted);
|
||
font-size: 12.5px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.lightbox {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(24, 19, 16, .9);
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 50;
|
||
padding: 24px;
|
||
}
|
||
|
||
.lightbox.open {
|
||
display: flex;
|
||
}
|
||
|
||
.lightbox img {
|
||
max-width: 92vw;
|
||
max-height: 86vh;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.lightbox .close {
|
||
position: absolute;
|
||
top: 18px;
|
||
right: 22px;
|
||
color: #fff;
|
||
font-size: 34px;
|
||
cursor: pointer;
|
||
background: none;
|
||
border: none;
|
||
line-height: 1;
|
||
}
|
||
|
||
@media (max-width: 560px) {
|
||
.hero {
|
||
height: 200px;
|
||
}
|
||
|
||
.title-row h1 {
|
||
font-size: 19px;
|
||
}
|
||
|
||
.field-row {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.booking-compact {
|
||
gap: 14px;
|
||
}
|
||
|
||
.bc-title {
|
||
width: 100%;
|
||
margin-bottom: 4px;
|
||
}
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
* {
|
||
transition: none !important;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<div class="preview-bar">Anteprima — la card parte compatta; “Dettagli” apre la scheda completa. Il pulsante non invia nulla.</div>
|
||
|
||
<div class="wrap">
|
||
<div class="card">
|
||
|
||
<!-- HEADER COMPATTO -->
|
||
<div class="chead">
|
||
<div class="date-chip">
|
||
<div class="m"><?php echo e($monAbbr); ?></div>
|
||
<div class="d"><?php echo $dayNum; ?></div>
|
||
</div>
|
||
<?php if (!empty($ev['cover_image'])) : ?>
|
||
<img class="chead-thumb" src="<?php echo e($ev['cover_image']); ?>" alt="<?php echo e($ev['title']); ?>">
|
||
<?php endif; ?>
|
||
<div class="main">
|
||
<div class="title-row">
|
||
<h1><?php echo e($ev['title']); ?></h1>
|
||
<?php if ($hasDetails) : ?>
|
||
<button type="button" class="toggle" id="details-toggle" aria-expanded="false">
|
||
<span id="toggle-label">Dettagli</span>
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="m6 9 6 6 6-6" />
|
||
</svg>
|
||
</button>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="cmeta">
|
||
<div class="item">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">
|
||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
||
<circle cx="12" cy="7" r="4" />
|
||
</svg>
|
||
<span>Capacità <strong><?php echo $booked; ?>/<?php echo $maxSeats; ?></strong></span>
|
||
</div>
|
||
<?php if (trim((string) $ev['address']) !== '') : ?>
|
||
<div class="item">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">
|
||
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
|
||
<circle cx="12" cy="10" r="3" />
|
||
</svg>
|
||
<span><?php echo e($ev['address']); ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
<div class="item">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">
|
||
<circle cx="12" cy="12" r="9" />
|
||
<path d="M12 7v5l3 2" />
|
||
</svg>
|
||
<span><?php echo e($dateLong); ?> · <?php echo e($timeLabel); ?></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="price-badge"><?php echo e($priceLabel); ?></div>
|
||
</div>
|
||
|
||
<!-- DETTAGLI ESPANDIBILI -->
|
||
<?php if ($hasDetails) : ?>
|
||
<div class="details" id="details">
|
||
<div class="hero">
|
||
<?php if (!empty($ev['cover_image'])) : ?>
|
||
<img src="<?php echo e($ev['cover_image']); ?>" alt="<?php echo e($ev['title']); ?>">
|
||
<?php else : ?>
|
||
<div class="emblem"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4">
|
||
<rect x="3" y="3" width="18" height="18" rx="2" />
|
||
<circle cx="9" cy="9" r="2" />
|
||
<path d="m21 15-5-5L5 21" />
|
||
</svg></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<div class="body">
|
||
<?php if (trim((string) $ev['description']) !== '') : ?>
|
||
<div class="section">
|
||
<div class="desc"><?php echo $ev['description']; ?></div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (trim((string) $ev['suitable_for']) !== '' || trim((string) $ev['what_to_bring']) !== '' || trim((string) $ev['instructions']) !== '') : ?>
|
||
<div class="section">
|
||
<div class="detail-grid">
|
||
<?php if (trim((string) $ev['suitable_for']) !== '') : ?>
|
||
<div class="detail">
|
||
<div class="h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">
|
||
<path d="M20.8 5.6a5 5 0 0 0-7-.1L12 7l-1.8-1.5a5 5 0 1 0-6.6 7.5L12 21l8.4-8a5 5 0 0 0 .4-7.4z" />
|
||
</svg> Per chi è adatto</div>
|
||
<div class="t"><?php echo textBlock($ev['suitable_for']); ?></div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php if (trim((string) $ev['what_to_bring']) !== '') : ?>
|
||
<div class="detail">
|
||
<div class="h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">
|
||
<path d="M6 7h12l1 13H5L6 7z" />
|
||
<path d="M9 7a3 3 0 0 1 6 0" />
|
||
</svg> Cosa portare</div>
|
||
<div class="t"><?php echo textBlock($ev['what_to_bring']); ?></div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php if (trim((string) $ev['instructions']) !== '') : ?>
|
||
<div class="detail">
|
||
<div class="h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">
|
||
<circle cx="12" cy="12" r="9" />
|
||
<path d="M12 11v5" />
|
||
<path d="M12 8h.01" />
|
||
</svg> Istruzioni</div>
|
||
<div class="t"><?php echo textBlock($ev['instructions']); ?></div>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($gallery)) : ?>
|
||
<div class="section">
|
||
<h3><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">
|
||
<rect x="3" y="3" width="18" height="18" rx="2" />
|
||
<circle cx="9" cy="9" r="2" />
|
||
<path d="m21 15-5-5L5 21" />
|
||
</svg> Galleria</h3>
|
||
<div class="gallery">
|
||
<?php foreach ($gallery as $g) : ?>
|
||
<img src="<?php echo e($g); ?>" alt="" data-full="<?php echo e($g); ?>">
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($mapQuery !== '') : ?>
|
||
<div class="section">
|
||
<h3><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">
|
||
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
|
||
<circle cx="12" cy="10" r="3" />
|
||
</svg> Dove</h3>
|
||
<iframe class="map" loading="lazy" src="https://www.google.com/maps?q=<?php echo urlencode($mapQuery); ?>&output=embed"></iframe>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<!-- BOOKING (compatto, passo unico) -->
|
||
<div class="booking" id="booking">
|
||
<?php if ($hardFull) : ?>
|
||
<div class="soldout-note">Evento esaurito — non ci sono più posti disponibili.</div>
|
||
<?php else : ?>
|
||
<?php if ($waitMode) : ?>
|
||
<div class="waitlist-banner">Posti esauriti — puoi iscriverti alla <strong>lista d'attesa</strong>: ti avviseremo se si libera un posto.</div>
|
||
<?php endif; ?>
|
||
<div class="booking-compact">
|
||
<div class="bc-title"><?php echo $waitMode ? "Lista d'attesa" : 'Prenota questo evento'; ?></div>
|
||
<div class="bc-block">
|
||
<div class="lbl">Persone</div>
|
||
<div class="stepper">
|
||
<button type="button" id="q-minus">−</button>
|
||
<span class="n" id="q-num">1</span>
|
||
<button type="button" id="q-plus">+</button>
|
||
</div>
|
||
</div>
|
||
<div class="bc-block total-box">
|
||
<div class="lbl">Totale</div>
|
||
<div class="val" id="q-total"><?php echo e($priceLabel); ?></div>
|
||
</div>
|
||
<button type="button" class="cta compact" id="b-open"><?php echo $waitMode ? "Lista d'attesa" : 'Prenota'; ?></button>
|
||
</div>
|
||
|
||
<div class="booking-form" id="booking-form">
|
||
<div class="field-row">
|
||
<div class="field">
|
||
<label>Nome <span class="req">*</span></label>
|
||
<input type="text" id="b-name" placeholder="Il tuo nome">
|
||
</div>
|
||
<div class="field">
|
||
<label>Cognome <span class="req">*</span></label>
|
||
<input type="text" id="b-surname" placeholder="Il tuo cognome">
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<label>Email <span class="req">*</span></label>
|
||
<input type="email" id="b-email" placeholder="latua@email.it">
|
||
</div>
|
||
<label class="consent">
|
||
<input type="checkbox" id="b-consent">
|
||
<span>Ho letto e accetto l'<a href="#" target="_blank">informativa privacy</a>. <span class="req">*</span></span>
|
||
</label>
|
||
<label class="consent">
|
||
<input type="checkbox" id="b-marketing">
|
||
<span>Desidero ricevere aggiornamenti e novità via email.</span>
|
||
</label>
|
||
<button type="button" class="cta full" id="b-submit"><?php echo $waitMode ? "Iscriviti alla lista d'attesa" : 'Conferma prenotazione'; ?></button>
|
||
<div class="form-error" id="b-error"></div>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
var WAIT_MODE = <?php echo $waitMode ? 'true' : 'false'; ?>;
|
||
</script>
|
||
</div>
|
||
|
||
<div class="lightbox" id="lightbox">
|
||
<button class="close" id="lb-close">×</button>
|
||
<img src="" alt="" id="lb-img">
|
||
</div>
|
||
|
||
<script>
|
||
var COST = <?php echo json_encode($cost); ?>;
|
||
var SYM = <?php echo json_encode($sym); ?>;
|
||
var MAXQTY = <?php echo (int) $maxQty; ?>;
|
||
|
||
function fmtMoney(v) {
|
||
if (v <= 0) return 'Gratuito';
|
||
return SYM + v.toLocaleString('it-IT', {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2
|
||
});
|
||
}
|
||
|
||
// Toggle dettagli
|
||
var dt = document.getElementById('details-toggle');
|
||
if (dt) {
|
||
dt.addEventListener('click', function() {
|
||
var box = document.getElementById('details');
|
||
var open = box.classList.toggle('open');
|
||
dt.classList.toggle('open', open);
|
||
dt.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||
document.getElementById('toggle-label').textContent = open ? 'Chiudi' : 'Dettagli';
|
||
});
|
||
}
|
||
|
||
(function() {
|
||
var qty = 1;
|
||
var numEl = document.getElementById('q-num');
|
||
if (!numEl) return;
|
||
var totEl = document.getElementById('q-total');
|
||
var minus = document.getElementById('q-minus');
|
||
var plus = document.getElementById('q-plus');
|
||
var submitBtn = document.getElementById('b-submit');
|
||
|
||
function refresh() {
|
||
numEl.textContent = qty;
|
||
totEl.textContent = fmtMoney(qty * COST);
|
||
minus.disabled = qty <= 1;
|
||
plus.disabled = qty >= MAXQTY;
|
||
if (submitBtn) {
|
||
if (typeof WAIT_MODE !== 'undefined' && WAIT_MODE) {
|
||
submitBtn.textContent = "Iscriviti alla lista d'attesa";
|
||
} else {
|
||
submitBtn.textContent = 'Conferma prenotazione' + (COST > 0 ? ' · ' + fmtMoney(qty * COST) : '');
|
||
}
|
||
}
|
||
}
|
||
minus.addEventListener('click', function() {
|
||
if (qty > 1) {
|
||
qty--;
|
||
refresh();
|
||
}
|
||
});
|
||
plus.addEventListener('click', function() {
|
||
if (qty < MAXQTY) {
|
||
qty++;
|
||
refresh();
|
||
}
|
||
});
|
||
refresh();
|
||
|
||
// "Prenota" rivela i campi (stessa card, passo unico)
|
||
document.getElementById('b-open').addEventListener('click', function() {
|
||
document.getElementById('booking-form').classList.add('open');
|
||
this.style.display = 'none';
|
||
document.getElementById('b-name').focus();
|
||
});
|
||
|
||
submitBtn.addEventListener('click', function() {
|
||
var name = document.getElementById('b-name').value.trim();
|
||
var surname = document.getElementById('b-surname').value.trim();
|
||
var email = document.getElementById('b-email').value.trim();
|
||
var consent = document.getElementById('b-consent').checked;
|
||
var err = document.getElementById('b-error');
|
||
if (!name || !surname) {
|
||
err.textContent = 'Inserisci nome e cognome.';
|
||
return;
|
||
}
|
||
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) {
|
||
err.textContent = 'Inserisci un\'email valida.';
|
||
return;
|
||
}
|
||
if (!consent) {
|
||
err.textContent = 'Devi accettare l\'informativa privacy.';
|
||
return;
|
||
}
|
||
err.textContent = '';
|
||
|
||
var marketing = document.getElementById('b-marketing').checked;
|
||
var wm = (typeof WAIT_MODE !== 'undefined' && WAIT_MODE);
|
||
document.getElementById('booking').innerHTML =
|
||
'<div class="booking-done">' +
|
||
' <div class="ok"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" width="24" height="24"><path d="M20 6 9 17l-5-5"/></svg></div>' +
|
||
' <h3>' + (wm ? "Anteprima lista d'attesa" : 'Anteprima prenotazione') + '</h3>' +
|
||
' <p><strong>' + name + ' ' + surname + '</strong> · ' + email + '</p>' +
|
||
' <p>' + qty + ' ' + (qty === 1 ? 'persona' : 'persone') + (wm ? " · in lista d'attesa" : ' · Totale <strong>' + fmtMoney(qty * COST) + '</strong>') + '</p>' +
|
||
' <p>Marketing: ' + (marketing ? 'sì' : 'no') + '</p>' +
|
||
' <p class="hintline">' + (wm ? "Nel widget pubblico, qui parte l'iscrizione alla lista d'attesa." : 'Nel widget pubblico, qui parte la prenotazione reale (POST all\'endpoint).') + '</p>' +
|
||
'</div>';
|
||
});
|
||
})();
|
||
|
||
// Lightbox galleria
|
||
var lb = document.getElementById('lightbox');
|
||
var lbImg = document.getElementById('lb-img');
|
||
document.querySelectorAll('.gallery img').forEach(function(img) {
|
||
img.addEventListener('click', function() {
|
||
lbImg.src = img.getAttribute('data-full');
|
||
lb.classList.add('open');
|
||
});
|
||
});
|
||
|
||
function closeLb() {
|
||
lb.classList.remove('open');
|
||
lbImg.src = '';
|
||
}
|
||
document.getElementById('lb-close').addEventListener('click', closeLb);
|
||
lb.addEventListener('click', function(e) {
|
||
if (e.target === lb) closeLb();
|
||
});
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') closeLb();
|
||
});
|
||
</script>
|
||
</body>
|
||
|
||
</html>
|