Aufgabenverwaltung angepasst, Eventseite weiter bearbeitet
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
This commit is contained in:
164
bin/main/static/community/location-events.html
Normal file
164
bin/main/static/community/location-events.html
Normal file
@@ -0,0 +1,164 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/img/icon.png" type="image/png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Alle Events – xXx Sphere</title>
|
||||
<link rel="stylesheet" href="/css/variables.css">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="stylesheet" href="/css/community.css">
|
||||
<style>
|
||||
.back-link { display:inline-flex; align-items:center; gap:0.35rem; color:var(--color-muted); font-size:0.88rem; text-decoration:none; margin-bottom:1rem; }
|
||||
.back-link:hover { color:var(--color-primary); }
|
||||
|
||||
.page-title { font-size:1.15rem; font-weight:700; margin:0 0 1.25rem; }
|
||||
|
||||
.event-list { display:flex; flex-direction:column; gap:0.75rem; }
|
||||
.event-card { background:var(--color-card); border:1px solid var(--color-secondary); border-radius:10px; display:flex; gap:0.75rem; padding:0.75rem; text-decoration:none; color:inherit; transition:border-color 0.15s; cursor:pointer; }
|
||||
.event-card:hover { border-color:var(--color-primary); }
|
||||
.event-card-img { width:64px; height:64px; border-radius:8px; object-fit:cover; background:var(--color-secondary); flex-shrink:0; overflow:hidden; display:flex; align-items:center; justify-content:center; font-size:1.4rem; }
|
||||
.event-card-img img { width:100%; height:100%; object-fit:cover; }
|
||||
.event-card-body { flex:1; min-width:0; }
|
||||
.event-card-title { font-weight:600; font-size:0.92rem; margin:0 0 0.2rem; }
|
||||
.event-card-date { font-size:0.78rem; color:var(--color-muted); }
|
||||
.event-card-attendees { font-size:0.78rem; color:var(--color-muted); }
|
||||
|
||||
.paging-bar { display:flex; align-items:center; justify-content:center; gap:0.75rem; margin-top:1.25rem; flex-wrap:wrap; }
|
||||
.paging-bar button { background:var(--color-secondary); border:none; color:var(--color-text); padding:0.45rem 1rem; border-radius:6px; font-size:0.88rem; cursor:pointer; transition:background 0.15s; }
|
||||
.paging-bar button:hover:not(:disabled) { background:var(--color-primary); color:#fff; }
|
||||
.paging-bar button:disabled { opacity:0.4; cursor:default; }
|
||||
.paging-info { font-size:0.85rem; color:var(--color-muted); }
|
||||
|
||||
.empty-hint { color:var(--color-muted); font-size:0.9rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="app">
|
||||
|
||||
<div class="main">
|
||||
<div class="content">
|
||||
|
||||
<a class="back-link" id="backLink" href="#">‹ Zurück zur Location</a>
|
||||
|
||||
<div id="locName" class="page-title">Alle Events</div>
|
||||
|
||||
<div id="eventList" class="event-list">
|
||||
<p class="empty-hint">Wird geladen…</p>
|
||||
</div>
|
||||
|
||||
<div class="paging-bar" id="pagingBar" style="display:none;">
|
||||
<button id="prevBtn" onclick="changePage(-1)" disabled>‹ Zurück</button>
|
||||
<span class="paging-info" id="pagingInfo"></span>
|
||||
<button id="nextBtn" onclick="changePage(1)">Weiter ›</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/nav.js"></script>
|
||||
<script>
|
||||
const PAGE_SIZE = 10;
|
||||
const params = new URLSearchParams(location.search);
|
||||
const locationId = params.get('id');
|
||||
|
||||
let allEvents = [];
|
||||
let currentPage = 0;
|
||||
|
||||
document.getElementById('backLink').href = `/community/location-detail.html?id=${locationId}`;
|
||||
|
||||
function escHtml(s) {
|
||||
if (!s) return '';
|
||||
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
|
||||
function formatDate(iso) {
|
||||
if (!iso) return '';
|
||||
const d = new Date(iso);
|
||||
return d.toLocaleDateString('de-DE', { weekday:'short', day:'2-digit', month:'2-digit', year:'numeric' })
|
||||
+ ' ' + d.toLocaleTimeString('de-DE', { hour:'2-digit', minute:'2-digit' }) + ' Uhr';
|
||||
}
|
||||
|
||||
function buildEventCard(e) {
|
||||
const imgHtml = e.imageData
|
||||
? `<img src="data:image/jpeg;base64,${e.imageData}" alt="${escHtml(e.title)}">`
|
||||
: '🗓';
|
||||
return `
|
||||
<a class="event-card" href="/community/event-detail.html?id=${e.eventId}">
|
||||
<div class="event-card-img">${imgHtml}</div>
|
||||
<div class="event-card-body">
|
||||
<div class="event-card-title">${escHtml(e.title)}</div>
|
||||
<div class="event-card-date">${formatDate(e.startAt)}</div>
|
||||
<div class="event-card-attendees">${e.attendeeCount} Teilnehmer*in(nen)${e.attendingMe ? ' · Du nimmst teil' : ''}</div>
|
||||
</div>
|
||||
</a>`;
|
||||
}
|
||||
|
||||
function renderPage() {
|
||||
const list = document.getElementById('eventList');
|
||||
const totalPages = Math.ceil(allEvents.length / PAGE_SIZE);
|
||||
const start = currentPage * PAGE_SIZE;
|
||||
const slice = allEvents.slice(start, start + PAGE_SIZE);
|
||||
|
||||
list.innerHTML = slice.length
|
||||
? slice.map(buildEventCard).join('')
|
||||
: '<p class="empty-hint">Keine weiteren Veranstaltungen.</p>';
|
||||
|
||||
const pagingBar = document.getElementById('pagingBar');
|
||||
if (allEvents.length > PAGE_SIZE) {
|
||||
pagingBar.style.display = '';
|
||||
document.getElementById('prevBtn').disabled = currentPage === 0;
|
||||
document.getElementById('nextBtn').disabled = currentPage >= totalPages - 1;
|
||||
document.getElementById('pagingInfo').textContent =
|
||||
`Seite ${currentPage + 1} von ${totalPages} (${allEvents.length} Events)`;
|
||||
} else {
|
||||
pagingBar.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function changePage(dir) {
|
||||
const totalPages = Math.ceil(allEvents.length / PAGE_SIZE);
|
||||
const next = currentPage + dir;
|
||||
if (next < 0 || next >= totalPages) return;
|
||||
currentPage = next;
|
||||
renderPage();
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
async function init() {
|
||||
if (!locationId) {
|
||||
document.getElementById('eventList').innerHTML = '<p class="empty-hint">Keine Location-ID angegeben.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Locationname laden
|
||||
const locRes = await fetch(`/locations/${locationId}`);
|
||||
if (locRes.ok) {
|
||||
const loc = await locRes.json();
|
||||
document.getElementById('locName').textContent = `Alle Events – ${loc.name}`;
|
||||
document.title = `Events – ${loc.name} – xXx Sphere`;
|
||||
}
|
||||
|
||||
// Events laden
|
||||
const res = await fetch(`/locations/${locationId}/events`);
|
||||
if (!res.ok) {
|
||||
document.getElementById('eventList').innerHTML = '<p class="empty-hint">Events konnten nicht geladen werden.</p>';
|
||||
return;
|
||||
}
|
||||
const events = await res.json();
|
||||
const now = new Date();
|
||||
allEvents = events
|
||||
.filter(e => new Date(e.startAt) >= now)
|
||||
.sort((a, b) => new Date(a.startAt) - new Date(b.startAt));
|
||||
|
||||
if (allEvents.length === 0) {
|
||||
document.getElementById('eventList').innerHTML = '<p class="empty-hint">Keine bevorstehenden Veranstaltungen.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
renderPage();
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user