update mine 6

This commit is contained in:
Cay 2026-03-16 14:17:37 +00:00
parent 02f2369cd6
commit b942401253
3 changed files with 95 additions and 155 deletions

View File

@ -1,121 +1,90 @@
/* ================================ import { showNotification } from "../notification.js";
Mine Frontend
Lädt den Aktionen-Tab mit
Produktionsanzeige + Abholen-Button
================================ */
/* window.showNotification() kommt aus dem globalen Scope (launcher.ejs) */
export async function loadMine(buildingId) { export async function loadMine(buildingId) {
const actionsTab = document.getElementById("tab-actions"); const actionsTab = document.getElementById("tab-actions");
if (!actionsTab) return; if (!actionsTab) return;
actionsTab.innerHTML = `<div class="mine-loading">Lade Mineninfo...</div>`;
actionsTab.innerHTML = `<div class="mine-loading">⛏️ Lade Mineninfo...</div>`;
await renderMineStatus(buildingId); await renderMineStatus(buildingId);
} }
/*
Status rendern
*/
async function renderMineStatus(buildingId) { async function renderMineStatus(buildingId) {
const actionsTab = document.getElementById("tab-actions"); const actionsTab = document.getElementById("tab-actions");
try { try {
const res = await fetch(`/api/mine/${buildingId}/status`); const res = await fetch("/api/mine/" + buildingId + "/status");
if (!res.ok) throw new Error("API Fehler"); if (!res.ok) throw new Error("API Fehler");
const data = await res.json(); const data = await res.json();
if (data.error) { if (data.error) {
actionsTab.innerHTML = `<p class="mine-error">⚠️ ${data.error}</p>`; actionsTab.innerHTML = "<p class='mine-error'> " + data.error + "</p>";
return; return;
} }
const minutesLeft = Math.floor(data.next_cycle_in_seconds / 60); const minutesLeft = Math.floor(data.next_cycle_in_seconds / 60);
const secondsLeft = data.next_cycle_in_seconds % 60; const secondsLeft = data.next_cycle_in_seconds % 60;
/* Ressourcen-Zeilen */ const resourceRows = data.available.map((r) => {
const resourceRows = data.available
.map((r) => {
const icon = resourceIcon(r.resource); const icon = resourceIcon(r.resource);
const label = resourceLabel(r.resource); const label = resourceLabel(r.resource);
const ready = data.ready; return (
return ` "<div class='mine-resource-row " + (data.ready ? "mine-resource-ready" : "") + "'>" +
<div class="mine-resource-row ${ready ? "mine-resource-ready" : ""}"> "<span class='mine-resource-icon'>" + icon + "</span>" +
<span class="mine-resource-icon">${icon}</span> "<span class='mine-resource-label'>" + label + "</span>" +
<span class="mine-resource-label">${label}</span> "<span class='mine-resource-amount'>" + r.amount + "</span>" +
<span class="mine-resource-amount">${r.amount}</span> "</div>"
</div>`; );
}) }).join("");
.join("");
actionsTab.innerHTML = ` actionsTab.innerHTML =
<div class="mine-panel"> "<div class='mine-panel'>" +
"<div class='mine-header-row'>" +
<div class="mine-header-row"> "<span class='mine-level-badge'>Level " + data.level + "</span>" +
<span class="mine-level-badge"> Level ${data.level}</span> "<span class='mine-cycles'>" + (data.cycles > 0 ? data.cycles + "x Zyklus abgeschlossen" : "Laeuft...") + "</span>" +
<span class="mine-cycles">${data.cycles > 0 ? `${data.cycles}× Zyklus abgeschlossen` : "Läuft..."}</span> "</div>" +
</div> "<div class='mine-divider'></div>" +
"<p class='mine-section-title'>Abgebaut</p>" +
<div class="mine-divider"></div> "<div class='mine-resources'>" + resourceRows + "</div>" +
"<div class='mine-divider'></div>" +
<p class="mine-section-title">Abgebaut</p> "<div class='mine-timer-row'>" +
<div class="mine-resources"> "<span class='mine-timer-label'>Naechster Zyklus in</span>" +
${resourceRows} "<span class='mine-timer' id='mine-countdown' data-seconds='" + data.next_cycle_in_seconds + "'>" +
</div> minutesLeft + "m " + secondsLeft + "s" +
"</span>" +
<div class="mine-divider"></div> "</div>" +
"<div class='mine-actions'>" +
<div class="mine-timer-row"> "<button class='mine-btn-collect " + (data.ready ? "" : "mine-btn-disabled") + "'" +
<span class="mine-timer-label">Nächster Zyklus in</span> " id='mine-collect-btn'" +
<span class="mine-timer" id="mine-countdown" " data-building='" + buildingId + "'" +
data-seconds="${data.next_cycle_in_seconds}"> (data.ready ? "" : " disabled") + ">" +
${minutesLeft}m ${secondsLeft}s (data.ready ? "Abholen" : "Noch nicht bereit") +
</span> "</button>" +
</div> "</div>" +
"</div>";
<div class="mine-actions">
<button
class="mine-btn-collect ${data.ready ? "" : "mine-btn-disabled"}"
id="mine-collect-btn"
data-building="${buildingId}"
${data.ready ? "" : "disabled"}
>
${data.ready ? "⛏️ Abholen" : "⏳ Noch nicht bereit"}
</button>
</div>
</div>`;
startCountdown(buildingId); startCountdown(buildingId);
} catch (err) { } catch (err) {
console.error("Mine Fehler:", err); console.error("Mine Fehler:", err);
actionsTab.innerHTML = `<p class="mine-error">⚠️ Fehler beim Laden der Mineninfo.</p>`; actionsTab.innerHTML = "<p class='mine-error'>Fehler beim Laden der Mineninfo.</p>";
} }
} }
/*
Abholen-Klick
*/
document.addEventListener("click", async (e) => { document.addEventListener("click", async (e) => {
const btn = e.target.closest("#mine-collect-btn"); const btn = e.target.closest("#mine-collect-btn");
if (!btn || btn.disabled) return; if (!btn || btn.disabled) return;
const buildingId = btn.dataset.building; const buildingId = btn.dataset.building;
btn.disabled = true; btn.disabled = true;
btn.textContent = "Wird abgeholt..."; btn.textContent = "Wird abgeholt...";
try { try {
const res = await fetch(`/api/mine/${buildingId}/collect`, { method: "POST" }); const res = await fetch("/api/mine/" + buildingId + "/collect", { method: "POST" });
if (!res.ok) throw new Error("API Fehler"); if (!res.ok) throw new Error("API Fehler");
const data = await res.json(); const data = await res.json();
if (data.error) { if (data.error) {
window.showNotification( showNotification(
data.ready_in_display data.ready_in_display
? `Die Mine ist noch nicht bereit.\nBereit in: ${data.ready_in_display}` ? "Die Mine ist noch nicht bereit.\nBereit in: " + data.ready_in_display
: data.error, : data.error,
"Mine", "Mine",
"⛏️" "⛏️"
@ -124,33 +93,20 @@ document.addEventListener("click", async (e) => {
return; return;
} }
/* Erfolg was wurde abgeholt? */
const lines = data.collected const lines = data.collected
.map((c) => `${resourceIcon(c.resource)} ${resourceLabel(c.resource)}: +${c.amount}`) .map((c) => resourceIcon(c.resource) + " " + resourceLabel(c.resource) + ": +" + c.amount)
.join("\n"); .join("\n");
window.showNotification( showNotification("Erfolgreich abgeholt!\n\n" + lines, "Mine", "⛏️");
`Erfolgreich abgeholt!\n\n${lines}`,
"Mine",
"⛏️"
);
await renderMineStatus(buildingId); await renderMineStatus(buildingId);
} catch (err) { } catch (err) {
console.error("Abholen Fehler:", err); console.error("Abholen Fehler:", err);
window.showNotification( showNotification("Fehler beim Abholen. Bitte erneut versuchen.", "Fehler", "⚠️");
"Fehler beim Abholen. Bitte erneut versuchen.",
"Fehler",
"⚠️"
);
await renderMineStatus(buildingId); await renderMineStatus(buildingId);
} }
}); });
/*
Countdown-Timer (live)
*/
let countdownInterval = null; let countdownInterval = null;
function startCountdown(buildingId) { function startCountdown(buildingId) {
@ -158,20 +114,13 @@ function startCountdown(buildingId) {
countdownInterval = setInterval(() => { countdownInterval = setInterval(() => {
const el = document.getElementById("mine-countdown"); const el = document.getElementById("mine-countdown");
if (!el) { if (!el) { clearInterval(countdownInterval); return; }
clearInterval(countdownInterval);
return;
}
let secs = parseInt(el.dataset.seconds, 10) - 1; let secs = parseInt(el.dataset.seconds, 10) - 1;
if (secs < 0) secs = 0; if (secs < 0) secs = 0;
el.dataset.seconds = secs; el.dataset.seconds = secs;
el.textContent = Math.floor(secs / 60) + "m " + (secs % 60) + "s";
const m = Math.floor(secs / 60);
const s = secs % 60;
el.textContent = `${m}m ${s}s`;
/* Zyklus abgeschlossen → UI neu laden */
if (secs === 0) { if (secs === 0) {
clearInterval(countdownInterval); clearInterval(countdownInterval);
renderMineStatus(buildingId); renderMineStatus(buildingId);
@ -179,29 +128,12 @@ function startCountdown(buildingId) {
}, 1000); }, 1000);
} }
/*
Hilfsfunktionen
*/
function resourceIcon(resource) { function resourceIcon(resource) {
const map = { const map = { gold: "🪙", copper: "🟤", silver: "⚪", iron: "⚙️", stone: "🪨", wood: "🪵" };
gold: "🪙", return map[resource] || "📦";
copper: "🟤",
silver: "⚪",
iron: "⚙️",
stone: "🪨",
wood: "🪵",
};
return map[resource] ?? "📦";
} }
function resourceLabel(resource) { function resourceLabel(resource) {
const map = { const map = { gold: "Gold", copper: "Kupfer", silver: "Silber", iron: "Eisen", stone: "Stein", wood: "Holz" };
gold: "Gold", return map[resource] || resource;
copper: "Kupfer",
silver: "Silber",
iron: "Eisen",
stone: "Stein",
wood: "Holz",
};
return map[resource] ?? resource;
} }

View File

@ -1,34 +1,4 @@
/* ================================ import { showNotification } from "../notification.js";
Eigene Benachrichtigung
================================ */
function showNotification(message, title = "Hinweis", icon = "⚔️") {
const overlay = document.getElementById("game-notification-overlay");
const notification = document.getElementById("game-notification");
const msgEl = document.getElementById("notification-message");
const titleEl = document.getElementById("notification-title");
const iconEl = document.getElementById("notification-icon");
const okBtn = document.getElementById("notification-ok");
msgEl.innerText = message;
titleEl.innerText = title;
iconEl.innerText = icon;
overlay.classList.add("show");
notification.style.display = "block";
requestAnimationFrame(() => {
notification.classList.add("show");
});
okBtn.onclick = () => {
notification.classList.remove("show");
overlay.classList.remove("show");
setTimeout(() => {
notification.style.display = "none";
}, 200);
};
}
export async function loadSchwarzmarkt() { export async function loadSchwarzmarkt() {
const ui = document.querySelector(".building-ui"); const ui = document.querySelector(".building-ui");

38
public/js/notification.js Normal file
View File

@ -0,0 +1,38 @@
/* ================================
Globale Notification Funktion
Wird von allen Modulen genutzt
================================ */
export function showNotification(message, title = "Hinweis", icon = "⚔️") {
const overlay = document.getElementById("game-notification-overlay");
const popup = document.getElementById("game-notification");
const msgEl = document.getElementById("notification-message");
const titleEl = document.getElementById("notification-title");
const iconEl = document.getElementById("notification-icon");
const okBtn = document.getElementById("notification-ok");
if (!overlay || !popup || !msgEl) return;
msgEl.innerText = message;
titleEl.innerText = title;
iconEl.innerText = icon;
overlay.classList.add("show");
popup.style.display = "block";
requestAnimationFrame(() => {
popup.classList.add("show");
});
// Alten Listener entfernen um Mehrfach-Klicks zu vermeiden
const newBtn = okBtn.cloneNode(true);
okBtn.parentNode.replaceChild(newBtn, okBtn);
newBtn.onclick = () => {
popup.classList.remove("show");
overlay.classList.remove("show");
setTimeout(() => {
popup.style.display = "none";
}, 200);
};
}