247 lines
8.8 KiB
JavaScript
247 lines
8.8 KiB
JavaScript
/* YogaSoul Eventi — interazioni widget */
|
|
(function () {
|
|
"use strict";
|
|
|
|
function fmtMoney(v, sym) {
|
|
if (v <= 0) return "Gratuito";
|
|
return (
|
|
sym +
|
|
v.toLocaleString("it-IT", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2,
|
|
})
|
|
);
|
|
}
|
|
|
|
function apiBase(el) {
|
|
var w = el.closest(".yse-widget");
|
|
return (w && w.getAttribute("data-api")) || "";
|
|
}
|
|
|
|
function initCard(card) {
|
|
var api = apiBase(card);
|
|
var eid = parseInt(card.getAttribute("data-eid"), 10);
|
|
var cost = parseFloat(card.getAttribute("data-cost")) || 0;
|
|
var sym = card.getAttribute("data-sym") || "€";
|
|
var maxQty = parseInt(card.getAttribute("data-maxqty"), 10) || 0;
|
|
var waitMode = card.getAttribute("data-waitmode") === "1";
|
|
|
|
// Toggle dettagli
|
|
var toggle = card.querySelector(".yse-toggle");
|
|
if (toggle) {
|
|
toggle.addEventListener("click", function () {
|
|
var det = card.querySelector(".yse-details");
|
|
if (!det) return;
|
|
var open = det.classList.toggle("yse-open");
|
|
toggle.classList.toggle("yse-on", open);
|
|
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
|
var lbl = toggle.querySelector(".yse-tlabel");
|
|
if (lbl) lbl.textContent = open ? "Chiudi" : "Dettagli";
|
|
});
|
|
}
|
|
|
|
var booking = card.querySelector(".yse-booking");
|
|
var numEl = card.querySelector(".yse-num");
|
|
if (!numEl) return; // esaurito senza lista d'attesa: nessuna prenotazione
|
|
|
|
var totEl = card.querySelector(".yse-total .yse-val");
|
|
var minus = card.querySelector(".yse-minus");
|
|
var plus = card.querySelector(".yse-plus");
|
|
var openBtn = card.querySelector(".yse-open");
|
|
var form = card.querySelector(".yse-bform");
|
|
var submit = card.querySelector(".yse-submit");
|
|
var qty = 1;
|
|
|
|
function refresh() {
|
|
numEl.textContent = qty;
|
|
if (totEl) totEl.textContent = fmtMoney(qty * cost, sym);
|
|
minus.disabled = qty <= 1;
|
|
plus.disabled = qty >= maxQty;
|
|
if (submit) {
|
|
submit.textContent = waitMode
|
|
? "Iscriviti alla lista d'attesa"
|
|
: "Conferma prenotazione" +
|
|
(cost > 0 ? " · " + fmtMoney(qty * cost, sym) : "");
|
|
}
|
|
}
|
|
minus.addEventListener("click", function () {
|
|
if (qty > 1) {
|
|
qty--;
|
|
refresh();
|
|
}
|
|
});
|
|
plus.addEventListener("click", function () {
|
|
if (qty < maxQty) {
|
|
qty++;
|
|
refresh();
|
|
}
|
|
});
|
|
refresh();
|
|
|
|
openBtn.addEventListener("click", function () {
|
|
form.classList.add("yse-open");
|
|
openBtn.style.display = "none";
|
|
var n = card.querySelector(".yse-name");
|
|
if (n) n.focus();
|
|
});
|
|
|
|
submit.addEventListener("click", function () {
|
|
var name = card.querySelector(".yse-name").value.trim();
|
|
var surname = card.querySelector(".yse-surname").value.trim();
|
|
var email = card.querySelector(".yse-email").value.trim();
|
|
var privacy = card.querySelector(".yse-c-privacy").checked;
|
|
var mkt = card.querySelector(".yse-c-mkt").checked;
|
|
var hp = card.querySelector(".yse-hp").value;
|
|
var err = card.querySelector(".yse-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 (!privacy) {
|
|
err.textContent = "Devi accettare l'informativa privacy.";
|
|
return;
|
|
}
|
|
err.textContent = "";
|
|
|
|
submit.disabled = true;
|
|
submit.textContent = "Invio in corso…";
|
|
|
|
var body = new URLSearchParams();
|
|
body.set("event_id", eid);
|
|
body.set("name", name);
|
|
body.set("surname", surname);
|
|
body.set("email", email);
|
|
body.set("seats", qty);
|
|
body.set("consent", "1");
|
|
body.set("marketing", mkt ? "1" : "0");
|
|
body.set("website", hp); // honeypot
|
|
|
|
fetch(api + "/book.php", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type":
|
|
"application/x-www-form-urlencoded;charset=UTF-8",
|
|
},
|
|
body: body.toString(),
|
|
})
|
|
.then(function (r) {
|
|
return r.json().then(function (j) {
|
|
return { status: r.status, j: j };
|
|
});
|
|
})
|
|
.then(function (res) {
|
|
var j = res.j || {};
|
|
if (j.ok) {
|
|
showDone(booking, j, name, surname, email);
|
|
return;
|
|
}
|
|
// Errori gestiti
|
|
submit.disabled = false;
|
|
refresh();
|
|
if (j.code === "partial") {
|
|
err.textContent =
|
|
j.error ||
|
|
"Sono rimasti solo " + j.remaining + " posti.";
|
|
if (
|
|
typeof j.remaining === "number" &&
|
|
j.remaining > 0
|
|
) {
|
|
maxQty = j.remaining;
|
|
if (qty > maxQty) {
|
|
qty = maxQty;
|
|
refresh();
|
|
}
|
|
}
|
|
} else {
|
|
err.textContent =
|
|
j.error || "Prenotazione non riuscita. Riprova.";
|
|
}
|
|
})
|
|
.catch(function () {
|
|
submit.disabled = false;
|
|
refresh();
|
|
err.textContent = "Errore di rete. Riprova.";
|
|
});
|
|
});
|
|
|
|
function showDone(container, j, name, surname, email) {
|
|
var waiting = j.status === "waiting";
|
|
var title = waiting
|
|
? "Sei in lista d'attesa"
|
|
: "Prenotazione confermata!";
|
|
var msg =
|
|
j.message ||
|
|
(waiting
|
|
? "Ti avviseremo appena si libera un posto."
|
|
: "Ti abbiamo inviato una email di riepilogo.");
|
|
container.innerHTML =
|
|
'<div class="yse-done">' +
|
|
' <div class="yse-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>" +
|
|
title +
|
|
"</h3>" +
|
|
" <p><strong>" +
|
|
escapeHtml(name + " " + surname) +
|
|
"</strong> · " +
|
|
escapeHtml(email) +
|
|
"</p>" +
|
|
" <p>" +
|
|
escapeHtml(msg) +
|
|
"</p>" +
|
|
"</div>";
|
|
}
|
|
}
|
|
|
|
function escapeHtml(s) {
|
|
var d = document.createElement("div");
|
|
d.textContent = s;
|
|
return d.innerHTML;
|
|
}
|
|
|
|
// Lightbox condiviso
|
|
function ensureLightbox() {
|
|
var lb = document.querySelector(".yse-lightbox");
|
|
if (lb) return lb;
|
|
lb = document.createElement("div");
|
|
lb.className = "yse-lightbox";
|
|
lb.innerHTML =
|
|
'<button class="yse-lbclose" aria-label="Chiudi">×</button><img src="" alt="">';
|
|
document.body.appendChild(lb);
|
|
function close() {
|
|
lb.classList.remove("yse-open");
|
|
lb.querySelector("img").src = "";
|
|
}
|
|
lb.addEventListener("click", function (e) {
|
|
if (e.target === lb || e.target.classList.contains("yse-lbclose"))
|
|
close();
|
|
});
|
|
document.addEventListener("keydown", function (e) {
|
|
if (e.key === "Escape") close();
|
|
});
|
|
return lb;
|
|
}
|
|
|
|
function init() {
|
|
document.querySelectorAll(".yse-card").forEach(initCard);
|
|
document.querySelectorAll(".yse-gallery img").forEach(function (img) {
|
|
img.addEventListener("click", function () {
|
|
var lb = ensureLightbox();
|
|
lb.querySelector("img").src = img.getAttribute("data-full");
|
|
lb.classList.add("yse-open");
|
|
});
|
|
});
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|