116 lines
4.5 KiB
JavaScript
116 lines
4.5 KiB
JavaScript
/* ============================================================
|
||
public/js/shop.js
|
||
Shop-Popup – Gems kaufen
|
||
============================================================ */
|
||
|
||
const shopOverlay = document.getElementById("shop-overlay");
|
||
const shopPopup = document.getElementById("shop-popup");
|
||
const shopClose = document.getElementById("shop-close");
|
||
const shopGrid = document.getElementById("shop-grid");
|
||
|
||
/* ════════════════════════════════════════════
|
||
Shop öffnen
|
||
════════════════════════════════════════════ */
|
||
export async function openShop() {
|
||
shopOverlay.classList.add("active");
|
||
shopPopup.classList.add("active");
|
||
await loadPackages();
|
||
}
|
||
|
||
/* ════════════════════════════════════════════
|
||
Shop schließen
|
||
════════════════════════════════════════════ */
|
||
function closeShop() {
|
||
shopOverlay.classList.remove("active");
|
||
shopPopup.classList.remove("active");
|
||
}
|
||
|
||
shopClose?.addEventListener("click", closeShop);
|
||
shopOverlay?.addEventListener("click", closeShop);
|
||
document.addEventListener("keydown", (e) => {
|
||
if (e.key === "Escape") closeShop();
|
||
});
|
||
|
||
/* ════════════════════════════════════════════
|
||
Pakete laden
|
||
════════════════════════════════════════════ */
|
||
async function loadPackages() {
|
||
shopGrid.innerHTML = `<div class="shop-loading">Lade Angebote...</div>`;
|
||
|
||
try {
|
||
const res = await fetch("/api/shop/packages");
|
||
const pkgs = await res.json();
|
||
renderPackages(pkgs);
|
||
} catch {
|
||
shopGrid.innerHTML = `<div class="shop-loading">Fehler beim Laden.</div>`;
|
||
}
|
||
}
|
||
|
||
/* ════════════════════════════════════════════
|
||
Pakete rendern
|
||
════════════════════════════════════════════ */
|
||
function renderPackages(pkgs) {
|
||
shopGrid.innerHTML = pkgs.map(pkg => {
|
||
const total = pkg.gems + pkg.bonus;
|
||
const priceEur = (pkg.price / 100).toFixed(2).replace(".", ",");
|
||
const hasBonus = pkg.bonus > 0;
|
||
const perGem = (pkg.price / total).toFixed(1);
|
||
|
||
return `
|
||
<div class="shop-card" data-id="${pkg.id}">
|
||
${hasBonus ? `<div class="shop-badge">+${pkg.bonus} Bonus!</div>` : ""}
|
||
<div class="shop-gem-icon">💠</div>
|
||
<div class="shop-package-name">${pkg.name}</div>
|
||
<div class="shop-gems-amount">${total.toLocaleString("de-DE")}</div>
|
||
<div class="shop-gems-label">Gems</div>
|
||
${hasBonus ? `<div class="shop-breakdown">${pkg.gems} + <span style="color:#f0d060">${pkg.bonus} Bonus</span></div>` : ""}
|
||
<div class="shop-price-per">~ ${perGem}¢ pro Gem</div>
|
||
<button class="shop-buy-btn" data-id="${pkg.id}">
|
||
${priceEur} €
|
||
</button>
|
||
</div>`;
|
||
}).join("");
|
||
|
||
shopGrid.querySelectorAll(".shop-buy-btn").forEach(btn => {
|
||
btn.addEventListener("click", () => checkout(btn.dataset.id, btn));
|
||
});
|
||
}
|
||
|
||
/* ════════════════════════════════════════════
|
||
Checkout starten
|
||
════════════════════════════════════════════ */
|
||
async function checkout(packageId, btn) {
|
||
btn.disabled = true;
|
||
btn.textContent = "Weiterleiten...";
|
||
|
||
try {
|
||
const res = await fetch("/api/shop/checkout", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ packageId }),
|
||
});
|
||
const data = await res.json();
|
||
|
||
if (!res.ok || !data.url) {
|
||
alert(data.error || "Fehler beim Starten der Zahlung.");
|
||
btn.disabled = false;
|
||
btn.textContent = getPrice(packageId);
|
||
return;
|
||
}
|
||
|
||
window.location.href = data.url;
|
||
} catch {
|
||
alert("Verbindungsfehler.");
|
||
btn.disabled = false;
|
||
btn.textContent = "Fehler";
|
||
}
|
||
}
|
||
|
||
function getPrice(id) {
|
||
const prices = {
|
||
starter: "1,99 €", abenteurer: "7,99 €",
|
||
ritter: "14,99 €", fuerst: "34,99 €", koenig: "59,99 €"
|
||
};
|
||
return prices[id] || "Kaufen";
|
||
}
|