Files
xxx-sphere-web/bin/main/static/community/event-detail.html
Mario 0f9f109067
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
An den Verantaltungen und Locations gearbeitet
2026-04-05 23:04:09 +02:00

178 lines
8.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>Veranstaltung xXx Sphere</title>
<link rel="stylesheet" href="/css/variables.css">
<link rel="stylesheet" href="/css/style.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); }
.evt-header { display:flex; gap:1rem; align-items:flex-start; margin-bottom:1.25rem; flex-wrap:wrap; }
.evt-img { width:120px; height:120px; border-radius:12px; background:var(--color-secondary); object-fit:cover; flex-shrink:0; display:flex; align-items:center; justify-content:center; font-size:3rem; overflow:hidden; border:2px solid var(--color-secondary); }
.evt-img img { width:100%; height:100%; object-fit:cover; }
.evt-meta { flex:1; min-width:0; }
.evt-title { font-size:1.4rem; font-weight:700; margin:0 0 0.3rem; }
.evt-location { color:var(--color-muted); font-size:0.88rem; margin-bottom:0.2rem; }
.evt-date { font-size:0.88rem; color:var(--color-muted); margin-bottom:0.5rem; }
.evt-desc { font-size:0.93rem; line-height:1.55; white-space:pre-wrap; word-break:break-word; margin-top:0.5rem; }
.attend-btn { display:inline-flex; align-items:center; gap:0.4rem; margin-top:0.75rem; }
.section-title { font-size:1rem; font-weight:700; margin:1.5rem 0 0.75rem; }
.gender-group { margin-bottom:1.25rem; }
.gender-label { font-size:0.78rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:var(--color-muted); margin-bottom:0.5rem; }
.attendee-list { display:flex; flex-wrap:wrap; gap:0.6rem; }
.attendee-chip { display:flex; align-items:center; gap:0.5rem; background:var(--color-card); border:1px solid var(--color-secondary); border-radius:20px; padding:0.3rem 0.6rem 0.3rem 0.3rem; text-decoration:none; color:inherit; transition:border-color 0.15s; font-size:0.85rem; }
.attendee-chip:hover { border-color:var(--color-primary); }
.attendee-avatar { width:28px; height:28px; border-radius:50%; background:var(--color-secondary); object-fit:cover; flex-shrink:0; overflow:hidden; display:flex; align-items:center; justify-content:center; font-size:0.8rem; }
.attendee-avatar img { width:100%; height:100%; object-fit:cover; }
.count-badge { background:var(--color-secondary); border-radius:12px; padding:0.15rem 0.6rem; font-size:0.78rem; color:var(--color-muted); margin-left:0.25rem; display:inline-block; }
</style>
</head>
<body>
<div class="main">
<a id="backLink" href="/community/events.html" class="back-link">← Veranstaltungen</a>
<div id="content">
<p style="color:var(--color-muted);">Wird geladen…</p>
</div>
</div>
<script src="/js/sidebar.js"></script>
<script src="/js/icons.js"></script>
<script>
const params = new URLSearchParams(location.search);
const eventId = params.get('id');
let myUserId = null;
function escHtml(s) {
return (s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
function formatDate(dt) {
if (!dt) return '';
const d = new Date(dt);
return d.toLocaleDateString('de-DE', { weekday:'long', day:'2-digit', month:'long', year:'numeric' })
+ ', ' + d.toLocaleTimeString('de-DE', { hour:'2-digit', minute:'2-digit' }) + ' Uhr';
}
const GENDER_LABELS = {
WEIBLICH: 'Frauen',
MAENNLICH: 'Männer',
DIVERS: 'Divers',
UNBEKANNT: 'Sonstiges'
};
async function loadPage() {
if (!eventId) { document.getElementById('content').innerHTML = '<p>Keine Event-ID angegeben.</p>'; return; }
const [meRes, evtRes] = await Promise.all([
fetch('/login/me'),
fetch(`/location-events/${eventId}`)
]);
if (!evtRes.ok) { document.getElementById('content').innerHTML = '<p>Veranstaltung nicht gefunden.</p>'; return; }
if (meRes.ok) { const me = await meRes.json(); myUserId = me.userId; }
const evt = await evtRes.json();
// Rücklink zur Location
const backLink = document.getElementById('backLink');
if (evt.locationId) {
backLink.href = `/community/location-detail.html?id=${evt.locationId}`;
backLink.textContent = `${escHtml(evt.locationName) || 'Location'}`;
}
document.title = `${evt.title} xXx Sphere`;
renderPage(evt);
}
function renderPage(evt) {
const imgHtml = evt.imageData
? `<img src="data:image/jpeg;base64,${evt.imageData}" alt="${escHtml(evt.title)}">`
: '🗓';
// Teilnehmende nach Geschlecht gruppieren
const byGender = {};
(evt.attendees || []).forEach(a => {
const g = a.geschlecht || 'UNBEKANNT';
if (!byGender[g]) byGender[g] = [];
byGender[g].push(a);
});
const genderOrder = ['WEIBLICH', 'MAENNLICH', 'DIVERS', 'UNBEKANNT'];
const attendeesHtml = genderOrder
.filter(g => byGender[g] && byGender[g].length > 0)
.map(g => {
const chips = byGender[g].map(a => {
const avatarHtml = a.profilePictureLq
? `<img src="data:image/jpeg;base64,${a.profilePictureLq}" alt="${escHtml(a.name)}">`
: a.name.charAt(0).toUpperCase();
return `<a class="attendee-chip" href="/community/benutzer.html?userId=${a.userId}">
<div class="attendee-avatar">${avatarHtml}</div>
${escHtml(a.name)}
</a>`;
}).join('');
return `<div class="gender-group">
<div class="gender-label">${GENDER_LABELS[g] || g} <span class="count-badge">${byGender[g].length}</span></div>
<div class="attendee-list">${chips}</div>
</div>`;
}).join('');
const totalAttendees = (evt.attendees || []).length;
const attending = evt.attendingMe;
document.getElementById('content').innerHTML = `
<div class="evt-header">
<div class="evt-img">${imgHtml}</div>
<div class="evt-meta">
<div class="evt-title">${escHtml(evt.title)}</div>
${evt.locationName ? `<div class="evt-location">📍 <a href="/community/location-detail.html?id=${evt.locationId}" style="color:inherit;text-decoration:none;">${escHtml(evt.locationName)}</a></div>` : ''}
<div class="evt-date">🗓 ${formatDate(evt.startAt)}</div>
${evt.description ? `<div class="evt-desc">${escHtml(evt.description)}</div>` : ''}
<div class="attend-btn">
<button class="btn" id="attendBtn"
style="${attending ? 'background:var(--color-secondary);color:var(--color-text);' : ''}"
onclick="toggleAttend()">
${attending ? '✓ Ich bin dabei' : '+ Ich bin dabei'}
</button>
<span style="color:var(--color-muted);font-size:0.85rem;" id="attendCount">${totalAttendees} Teilnehmer*in(nen)</span>
</div>
</div>
</div>
${totalAttendees > 0 ? `
<div class="section-title">Teilnehmende</div>
${attendeesHtml}
` : '<p style="color:var(--color-muted);font-size:0.9rem;margin-top:1rem;">Noch keine Teilnehmenden.</p>'}
`;
}
async function toggleAttend() {
const res = await fetch(`/location-events/${eventId}/attend`, { method: 'POST' });
if (!res.ok) { alert('Fehler beim Aktualisieren.'); return; }
const data = await res.json();
const btn = document.getElementById('attendBtn');
const countEl = document.getElementById('attendCount');
if (btn) {
btn.textContent = data.attending ? '✓ Ich bin dabei' : '+ Ich bin dabei';
btn.style.background = data.attending ? 'var(--color-secondary)' : '';
btn.style.color = data.attending ? 'var(--color-text)' : '';
}
if (countEl) countEl.textContent = `${data.attendeeCount} Teilnehmer*in(nen)`;
// Teilnehmendenliste neu laden
const evtRes = await fetch(`/location-events/${eventId}`);
if (evtRes.ok) { renderPage(await evtRes.json()); }
}
loadPage();
</script>
</body>
</html>