Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
627 lines
26 KiB
HTML
627 lines
26 KiB
HTML
<!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>Suche – xXx Sphere</title>
|
||
<link rel="stylesheet" href="/css/variables.css">
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
<style>
|
||
.search-hero {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
.search-hero-input-wrap {
|
||
flex: 1;
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.search-hero-icon {
|
||
position: absolute;
|
||
left: 0.85rem;
|
||
color: var(--color-muted);
|
||
display: flex;
|
||
align-items: center;
|
||
pointer-events: none;
|
||
}
|
||
#searchInput {
|
||
width: 100%;
|
||
padding: 0.65rem 1rem 0.65rem 2.6rem;
|
||
border: 1px solid var(--color-secondary);
|
||
border-radius: 8px;
|
||
background: var(--color-card);
|
||
color: var(--color-text);
|
||
font-size: 1rem;
|
||
outline: none;
|
||
transition: border-color 0.2s;
|
||
box-sizing: border-box;
|
||
}
|
||
#searchInput:focus { border-color: var(--color-primary); }
|
||
|
||
.search-tabs {
|
||
display: flex;
|
||
gap: 0;
|
||
border-bottom: 1px solid var(--color-secondary);
|
||
margin-bottom: 1.25rem;
|
||
}
|
||
.search-tab-btn {
|
||
background: none;
|
||
border: none;
|
||
border-bottom: 3px solid transparent;
|
||
border-radius: 0;
|
||
padding: 0.55rem 1.1rem;
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
color: var(--color-muted);
|
||
cursor: pointer;
|
||
margin-bottom: -1px;
|
||
transition: color 0.15s, border-color 0.15s;
|
||
}
|
||
.search-tab-btn:hover { color: var(--color-text); background: none; }
|
||
.search-tab-btn.active { color: var(--color-primary); border-bottom-color: var(--color-primary); }
|
||
.search-tab-count {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: var(--color-secondary);
|
||
color: var(--color-muted);
|
||
border-radius: 10px;
|
||
font-size: 0.7rem;
|
||
font-weight: 700;
|
||
min-width: 1.2em;
|
||
padding: 0 0.35em;
|
||
margin-left: 0.3em;
|
||
vertical-align: middle;
|
||
}
|
||
.search-tab-btn.active .search-tab-count {
|
||
background: var(--color-primary);
|
||
color: #fff;
|
||
}
|
||
|
||
.search-panel { display: none; }
|
||
.search-panel.active { display: block; }
|
||
|
||
.search-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||
gap: 0.85rem;
|
||
}
|
||
|
||
.search-card {
|
||
background: var(--color-card);
|
||
border: 1px solid var(--color-secondary);
|
||
border-radius: 10px;
|
||
padding: 0.85rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
text-decoration: none;
|
||
color: var(--color-text);
|
||
transition: border-color 0.15s;
|
||
min-width: 0;
|
||
}
|
||
.search-card:hover { border-color: var(--color-primary); }
|
||
.search-card-avatar {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
background: var(--color-secondary);
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 1.3rem;
|
||
overflow: hidden;
|
||
}
|
||
.search-card-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
|
||
.search-card-avatar--square { border-radius: 8px; }
|
||
.search-card-avatar--square img { border-radius: 6px; }
|
||
.search-card-body { min-width: 0; }
|
||
.search-card-name {
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
.search-card-sub {
|
||
font-size: 0.75rem;
|
||
color: var(--color-muted);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.search-empty {
|
||
text-align: center;
|
||
padding: 2.5rem 1rem;
|
||
color: var(--color-muted);
|
||
font-size: 0.9rem;
|
||
}
|
||
.search-loading {
|
||
text-align: center;
|
||
padding: 2rem 1rem;
|
||
color: var(--color-muted);
|
||
font-size: 0.9rem;
|
||
}
|
||
.search-load-more {
|
||
display: block;
|
||
width: 100%;
|
||
margin-top: 1rem;
|
||
padding: 0.6rem;
|
||
background: none;
|
||
border: 1px solid var(--color-secondary);
|
||
border-radius: 8px;
|
||
color: var(--color-muted);
|
||
cursor: pointer;
|
||
font-size: 0.88rem;
|
||
transition: border-color 0.15s, color 0.15s;
|
||
}
|
||
.search-load-more:hover { border-color: var(--color-primary); color: var(--color-primary); background: none; }
|
||
|
||
.hashtag-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.3rem;
|
||
padding: 0.4rem 0.85rem;
|
||
background: var(--color-card);
|
||
border: 1px solid var(--color-secondary);
|
||
border-radius: 20px;
|
||
color: var(--color-primary);
|
||
font-weight: 600;
|
||
font-size: 0.9rem;
|
||
text-decoration: none;
|
||
transition: border-color 0.15s, background 0.15s;
|
||
}
|
||
.hashtag-chip:hover { border-color: var(--color-primary); background: var(--color-secondary); }
|
||
|
||
/* Dialog (Gruppen-Beitritt) */
|
||
.dialog-backdrop { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.6); z-index:200; align-items:center; justify-content:center; }
|
||
.dialog-backdrop.visible { display:flex; }
|
||
.dialog { background:var(--color-card); border:1px solid var(--color-secondary); border-radius:12px; padding:1.75rem; width:100%; max-width:420px; box-shadow:0 8px 32px rgba(0,0,0,0.6); max-height:90vh; overflow-y:auto; }
|
||
.dialog h3 { color:var(--color-primary); font-size:1.1rem; margin-bottom:1.25rem; }
|
||
.dialog label { display:block; font-size:0.8rem; color:#aaa; margin-bottom:0.3rem; margin-top:1rem; }
|
||
.dialog textarea { width:100%; padding:0.6rem 0.85rem; border:1px solid var(--color-secondary); border-radius:6px; background:var(--color-secondary); color:var(--color-text); font-size:0.95rem; outline:none; transition:border-color 0.2s; resize:vertical; min-height:80px; box-sizing:border-box; }
|
||
.dialog textarea:focus { border-color:var(--color-primary); }
|
||
.dialog-actions { display:flex; justify-content:flex-end; gap:0.75rem; margin-top:1.5rem; }
|
||
.dialog-actions button { flex:none; margin:0; padding:0.55rem 1.1rem; font-size:0.9rem; width:auto; }
|
||
</style>
|
||
</head>
|
||
<body class="app">
|
||
<div class="main">
|
||
<div class="content">
|
||
<h1 style="margin-bottom:1rem;">Suche</h1>
|
||
|
||
<div class="search-hero">
|
||
<div class="search-hero-input-wrap">
|
||
<span class="search-hero-icon" id="searchIcon"></span>
|
||
<input type="text" id="searchInput" placeholder="Suchen nach Personen, Locations, Veranstaltungen, Gruppen…"
|
||
autocomplete="off" spellcheck="false">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="search-tabs">
|
||
<button class="search-tab-btn active" data-tab="users">
|
||
Personen <span class="search-tab-count" id="countUsers">0</span>
|
||
</button>
|
||
<button class="search-tab-btn" data-tab="locations">
|
||
Locations <span class="search-tab-count" id="countLocations">0</span>
|
||
</button>
|
||
<button class="search-tab-btn" data-tab="events">
|
||
Veranstaltungen <span class="search-tab-count" id="countEvents">0</span>
|
||
</button>
|
||
<button class="search-tab-btn" data-tab="gruppen">
|
||
Gruppen <span class="search-tab-count" id="countGruppen">0</span>
|
||
</button>
|
||
<button class="search-tab-btn" data-tab="hashtags">
|
||
Hashtags <span class="search-tab-count" id="countHashtags">0</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="search-panel active" id="panel-users">
|
||
<div class="search-loading" id="loadingUsers" style="display:none;">Wird geladen…</div>
|
||
<div class="search-grid" id="gridUsers"></div>
|
||
<button class="search-load-more" id="moreUsers" style="display:none;">Mehr laden</button>
|
||
</div>
|
||
|
||
<div class="search-panel" id="panel-locations">
|
||
<div class="search-loading" id="loadingLocations" style="display:none;">Wird geladen…</div>
|
||
<div class="search-grid" id="gridLocations"></div>
|
||
<button class="search-load-more" id="moreLocations" style="display:none;">Mehr laden</button>
|
||
</div>
|
||
|
||
<div class="search-panel" id="panel-events">
|
||
<div class="search-loading" id="loadingEvents" style="display:none;">Wird geladen…</div>
|
||
<div class="search-grid" id="gridEvents"></div>
|
||
<button class="search-load-more" id="moreEvents" style="display:none;">Mehr laden</button>
|
||
</div>
|
||
|
||
<div class="search-panel" id="panel-gruppen">
|
||
<div class="search-loading" id="loadingGruppen" style="display:none;">Wird geladen…</div>
|
||
<div class="search-grid" id="gridGruppen"></div>
|
||
</div>
|
||
|
||
<div class="search-panel" id="panel-hashtags">
|
||
<div class="search-loading" id="loadingHashtags" style="display:none;">Wird geladen…</div>
|
||
<div id="gridHashtags" style="display:flex; flex-wrap:wrap; gap:0.6rem; padding-top:0.25rem;"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Beitrittsanfrage Dialog -->
|
||
<div class="dialog-backdrop" id="searchJoinDialog">
|
||
<div class="dialog">
|
||
<h3>Beitrittsanfrage senden</h3>
|
||
<p id="searchJoinGroupName" style="font-weight:600; margin-bottom:0.5rem;"></p>
|
||
<label>Nachricht (optional)</label>
|
||
<textarea id="searchJoinNachricht" placeholder="Warum möchtest du beitreten?"></textarea>
|
||
<p class="message error" id="searchJoinError" style="display:none; margin-top:0.75rem;"></p>
|
||
<div class="dialog-actions">
|
||
<button class="secondary" id="searchJoinCancelBtn">Abbrechen</button>
|
||
<button id="searchJoinSendBtn">Anfrage senden</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/js/icons.js"></script>
|
||
<script src="/js/nav.js"></script>
|
||
<script>
|
||
(function () {
|
||
const PAGE_SIZE = 24;
|
||
|
||
function esc(s) {
|
||
return String(s ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||
}
|
||
|
||
function IC(key) { return window.IC ? window.IC(key) : (window.ICONS?.[key]?.value || ''); }
|
||
|
||
// ── Suchicon setzen ──
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
const icon = document.getElementById('searchIcon');
|
||
if (icon) icon.innerHTML = IC('SEARCH') || '🔍';
|
||
});
|
||
setTimeout(() => {
|
||
const icon = document.getElementById('searchIcon');
|
||
if (icon && !icon.innerHTML) icon.innerHTML = IC('SEARCH') || '🔍';
|
||
}, 200);
|
||
|
||
// ── State ──
|
||
const state = {
|
||
users: { offset: 0, total: 0, loading: false },
|
||
locations: { offset: 0, total: 0, loading: false },
|
||
events: { offset: 0, total: 0, loading: false }
|
||
};
|
||
|
||
let currentQuery = '';
|
||
let debounceTimer;
|
||
|
||
// ── Tabs ──
|
||
document.querySelectorAll('.search-tab-btn').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
document.querySelectorAll('.search-tab-btn').forEach(b => b.classList.remove('active'));
|
||
document.querySelectorAll('.search-panel').forEach(p => p.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
document.getElementById('panel-' + btn.dataset.tab).classList.add('active');
|
||
});
|
||
});
|
||
|
||
// ── "Mehr laden" Buttons ──
|
||
document.getElementById('moreUsers').addEventListener('click', () => loadMore('users'));
|
||
document.getElementById('moreLocations').addEventListener('click', () => loadMore('locations'));
|
||
document.getElementById('moreEvents').addEventListener('click', () => loadMore('events'));
|
||
|
||
// ── Suche starten ──
|
||
const input = document.getElementById('searchInput');
|
||
input.addEventListener('input', () => {
|
||
clearTimeout(debounceTimer);
|
||
const q = input.value.trim();
|
||
if (q.length < 2) { clearAll(); return; }
|
||
debounceTimer = setTimeout(() => startSearch(q), 300);
|
||
});
|
||
|
||
function startSearch(q) {
|
||
currentQuery = q;
|
||
// URL aktualisieren
|
||
const url = new URL(window.location);
|
||
url.searchParams.set('q', q);
|
||
history.replaceState(null, '', url);
|
||
// State zurücksetzen
|
||
['users', 'locations', 'events'].forEach(t => {
|
||
state[t].offset = 0;
|
||
state[t].total = 0;
|
||
document.getElementById('grid' + cap(t)).innerHTML = '';
|
||
document.getElementById('more' + cap(t)).style.display = 'none';
|
||
});
|
||
// Alle Typen parallel laden
|
||
loadChunk('users');
|
||
loadChunk('locations');
|
||
loadChunk('events');
|
||
loadGruppen(q);
|
||
loadHashtags(q);
|
||
}
|
||
|
||
function clearAll() {
|
||
currentQuery = '';
|
||
['users', 'locations', 'events'].forEach(t => {
|
||
state[t].offset = 0;
|
||
state[t].total = 0;
|
||
document.getElementById('grid' + cap(t)).innerHTML = '';
|
||
document.getElementById('more' + cap(t)).style.display = 'none';
|
||
document.getElementById('count' + cap(t)).textContent = '0';
|
||
document.getElementById('loading' + cap(t)).style.display = 'none';
|
||
});
|
||
document.getElementById('gridGruppen').innerHTML = '';
|
||
document.getElementById('countGruppen').textContent = '0';
|
||
document.getElementById('loadingGruppen').style.display = 'none';
|
||
document.getElementById('gridHashtags').innerHTML = '';
|
||
document.getElementById('countHashtags').textContent = '0';
|
||
document.getElementById('loadingHashtags').style.display = 'none';
|
||
const url = new URL(window.location);
|
||
url.searchParams.delete('q');
|
||
history.replaceState(null, '', url);
|
||
}
|
||
|
||
function loadMore(type) {
|
||
if (state[type].loading) return;
|
||
loadChunk(type);
|
||
}
|
||
|
||
async function loadChunk(type) {
|
||
if (!currentQuery || state[type].loading) return;
|
||
state[type].loading = true;
|
||
|
||
const loadingEl = document.getElementById('loading' + cap(type));
|
||
const moreBtn = document.getElementById('more' + cap(type));
|
||
loadingEl.style.display = '';
|
||
moreBtn.style.display = 'none';
|
||
|
||
try {
|
||
const url = `/search?q=${encodeURIComponent(currentQuery)}&limit=${PAGE_SIZE}&offset=${state[type].offset}&type=${type}`;
|
||
const res = await fetch(url);
|
||
if (!res.ok) throw new Error();
|
||
const data = await res.json();
|
||
|
||
const items = data[type] || [];
|
||
state[type].offset += items.length;
|
||
state[type].total = data.total?.[type] ?? (items.length < PAGE_SIZE ? state[type].offset : state[type].offset + 1);
|
||
|
||
appendItems(type, items);
|
||
|
||
// Zähler aktualisieren
|
||
document.getElementById('count' + cap(type)).textContent = state[type].offset;
|
||
|
||
// "Mehr laden" zeigen wenn noch mehr vorhanden
|
||
moreBtn.style.display = items.length === PAGE_SIZE ? '' : 'none';
|
||
} catch (e) {
|
||
// ignore
|
||
} finally {
|
||
state[type].loading = false;
|
||
loadingEl.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
function appendItems(type, items) {
|
||
const grid = document.getElementById('grid' + cap(type));
|
||
if (!items.length && state[type].offset === 0) {
|
||
if (!grid.innerHTML) {
|
||
grid.innerHTML = `<div class="search-empty" style="grid-column:1/-1;">Keine Ergebnisse.</div>`;
|
||
}
|
||
return;
|
||
}
|
||
items.forEach(item => {
|
||
const card = document.createElement('a');
|
||
if (type === 'users') {
|
||
card.href = `/community/benutzer.html?userId=${esc(item.userId)}`;
|
||
const av = item.profilePicture
|
||
? `<div class="search-card-avatar"><img src="data:image/png;base64,${esc(item.profilePicture)}" alt=""></div>`
|
||
: `<div class="search-card-avatar">${IC('PROFILE') || '👤'}</div>`;
|
||
card.innerHTML = `${av}<div class="search-card-body"><div class="search-card-name">${esc(item.name)}</div></div>`;
|
||
} else if (type === 'locations') {
|
||
card.href = `/community/location-detail.html?id=${esc(item.locationId)}`;
|
||
const av = item.profilePicture
|
||
? `<div class="search-card-avatar search-card-avatar--square"><img src="data:image/png;base64,${esc(item.profilePicture)}" alt=""></div>`
|
||
: `<div class="search-card-avatar search-card-avatar--square">📍</div>`;
|
||
card.innerHTML = `${av}<div class="search-card-body"><div class="search-card-name">${esc(item.name)}</div></div>`;
|
||
} else {
|
||
card.href = `/community/event-detail.html?eventId=${esc(item.eventId)}`;
|
||
const av = item.imageData
|
||
? `<div class="search-card-avatar search-card-avatar--square"><img src="${esc(item.imageData)}" alt=""></div>`
|
||
: `<div class="search-card-avatar search-card-avatar--square">🗓</div>`;
|
||
const sub = item.startAt ? new Date(item.startAt).toLocaleString('de-DE', { dateStyle: 'short', timeStyle: 'short' }) : '';
|
||
card.innerHTML = `${av}<div class="search-card-body"><div class="search-card-name">${esc(item.title)}</div><div class="search-card-sub">${esc(sub)}</div></div>`;
|
||
}
|
||
card.className = 'search-card';
|
||
grid.appendChild(card);
|
||
});
|
||
}
|
||
|
||
// ── Gruppen-Suche ──
|
||
|
||
async function loadGruppen(q) {
|
||
const loadingEl = document.getElementById('loadingGruppen');
|
||
const grid = document.getElementById('gridGruppen');
|
||
loadingEl.style.display = '';
|
||
grid.innerHTML = '';
|
||
try {
|
||
const res = await fetch('/gruppen/search?q=' + encodeURIComponent(q));
|
||
if (!res.ok) throw new Error();
|
||
const data = await res.json();
|
||
document.getElementById('countGruppen').textContent = data.length;
|
||
if (!data.length) {
|
||
grid.innerHTML = '<div class="search-empty" style="grid-column:1/-1;">Keine Ergebnisse.</div>';
|
||
return;
|
||
}
|
||
data.forEach(g => grid.appendChild(buildGruppeCard(g)));
|
||
} catch (e) {
|
||
// ignore
|
||
} finally {
|
||
loadingEl.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
function buildGruppeCard(g) {
|
||
const card = document.createElement('div');
|
||
card.className = 'search-card';
|
||
card.style.cssText = 'justify-content:space-between; cursor:pointer;';
|
||
card.addEventListener('click', () => { location.href = '/community/gruppe.html?gruppeId=' + g.gruppeId; });
|
||
|
||
const av = g.bild
|
||
? `<div class="search-card-avatar search-card-avatar--square"><img src="data:image/jpeg;base64,${esc(g.bild)}" alt=""></div>`
|
||
: `<div class="search-card-avatar search-card-avatar--square">👥</div>`;
|
||
const privBadge = g.isPrivate ? ' 🔒' : '';
|
||
const sub = g.memberCount + ' Mitglied' + (g.memberCount !== 1 ? 'er' : '');
|
||
|
||
const info = document.createElement('div');
|
||
info.style.cssText = 'display:flex; align-items:center; gap:0.75rem; min-width:0; flex:1;';
|
||
info.innerHTML = `${av}<div class="search-card-body"><div class="search-card-name">${esc(g.name)}${privBadge}</div><div class="search-card-sub">${esc(sub)}</div></div>`;
|
||
card.appendChild(info);
|
||
|
||
if (!g.myRole) {
|
||
const btn = document.createElement('button');
|
||
btn.style.cssText = 'font-size:0.78rem; padding:0.3rem 0.65rem; width:auto; margin:0; white-space:nowrap; flex-shrink:0; margin-left:0.5rem;';
|
||
if (g.myRequestStatus === 'AUSSTEHEND') {
|
||
btn.disabled = true;
|
||
btn.style.opacity = '0.6';
|
||
btn.textContent = 'Anfrage ausstehend';
|
||
} else if (g.isPrivate) {
|
||
btn.textContent = 'Anfrage senden';
|
||
btn.addEventListener('click', e => { e.stopPropagation(); openSearchJoinDialog(g.gruppeId, g.name); });
|
||
} else {
|
||
btn.textContent = 'Beitreten';
|
||
btn.addEventListener('click', e => { e.stopPropagation(); joinGruppeSearch(g.gruppeId, btn); });
|
||
}
|
||
card.appendChild(btn);
|
||
}
|
||
|
||
return card;
|
||
}
|
||
|
||
// ── Hashtag-Suche ──
|
||
|
||
async function loadHashtags(q) {
|
||
const loadingEl = document.getElementById('loadingHashtags');
|
||
const grid = document.getElementById('gridHashtags');
|
||
loadingEl.style.display = '';
|
||
grid.innerHTML = '';
|
||
try {
|
||
const raw = q.startsWith('#') ? q.slice(1) : q;
|
||
const res = await fetch('/hashtags/suggest?q=' + encodeURIComponent(raw) + '&limit=20');
|
||
if (!res.ok) throw new Error();
|
||
const tags = await res.json();
|
||
document.getElementById('countHashtags').textContent = tags.length;
|
||
if (!tags.length) {
|
||
grid.innerHTML = '<div class="search-empty">Keine Hashtags gefunden.</div>';
|
||
return;
|
||
}
|
||
tags.forEach(tag => {
|
||
const a = document.createElement('a');
|
||
a.className = 'hashtag-chip';
|
||
a.href = '/community/feed.html?tag=' + encodeURIComponent(tag);
|
||
a.textContent = '#' + tag;
|
||
grid.appendChild(a);
|
||
});
|
||
} catch (e) {
|
||
// ignore
|
||
} finally {
|
||
loadingEl.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
async function joinGruppeSearch(gruppeId, btn) {
|
||
btn.disabled = true;
|
||
btn.textContent = '…';
|
||
try {
|
||
const res = await fetch('/gruppen/' + gruppeId + '/join', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: '{}'
|
||
});
|
||
if (res.ok || res.status === 201) {
|
||
btn.textContent = 'Beigetreten ✓';
|
||
} else {
|
||
btn.disabled = false;
|
||
btn.textContent = 'Beitreten';
|
||
}
|
||
} catch (e) {
|
||
btn.disabled = false;
|
||
btn.textContent = 'Beitreten';
|
||
}
|
||
}
|
||
|
||
// ── Join-Dialog für Gruppen ──
|
||
|
||
let searchJoinGruppeId = null;
|
||
|
||
function openSearchJoinDialog(gruppeId, name) {
|
||
searchJoinGruppeId = gruppeId;
|
||
document.getElementById('searchJoinGroupName').textContent = name;
|
||
document.getElementById('searchJoinNachricht').value = '';
|
||
document.getElementById('searchJoinError').style.display = 'none';
|
||
document.getElementById('searchJoinDialog').classList.add('visible');
|
||
}
|
||
|
||
function closeSearchJoinDialog() {
|
||
document.getElementById('searchJoinDialog').classList.remove('visible');
|
||
searchJoinGruppeId = null;
|
||
}
|
||
|
||
async function sendSearchJoinRequest() {
|
||
if (!searchJoinGruppeId) return;
|
||
document.getElementById('searchJoinError').style.display = 'none';
|
||
const nachricht = document.getElementById('searchJoinNachricht').value.trim() || null;
|
||
try {
|
||
const res = await fetch('/gruppen/' + searchJoinGruppeId + '/join', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ nachricht })
|
||
});
|
||
if (res.ok || res.status === 201) {
|
||
closeSearchJoinDialog();
|
||
if (currentQuery.length >= 2) loadGruppen(currentQuery);
|
||
} else {
|
||
const el = document.getElementById('searchJoinError');
|
||
el.textContent = 'Fehler beim Senden der Anfrage.';
|
||
el.style.display = 'block';
|
||
}
|
||
} catch (e) {
|
||
const el = document.getElementById('searchJoinError');
|
||
el.textContent = 'Fehler: ' + e.message;
|
||
el.style.display = 'block';
|
||
}
|
||
}
|
||
|
||
document.getElementById('searchJoinCancelBtn').addEventListener('click', closeSearchJoinDialog);
|
||
document.getElementById('searchJoinSendBtn').addEventListener('click', sendSearchJoinRequest);
|
||
document.getElementById('searchJoinDialog').addEventListener('click', e => {
|
||
if (e.target === document.getElementById('searchJoinDialog')) closeSearchJoinDialog();
|
||
});
|
||
|
||
function cap(s) { return s.charAt(0).toUpperCase() + s.slice(1); }
|
||
|
||
// ── URL-Parameter beim Start auslesen ──
|
||
const params = new URLSearchParams(window.location.search);
|
||
const initQ = params.get('q') || '';
|
||
const initTab = params.get('tab') || '';
|
||
|
||
if (initTab) {
|
||
const tabBtn = document.querySelector(`.search-tab-btn[data-tab="${initTab}"]`);
|
||
if (tabBtn) tabBtn.click();
|
||
}
|
||
|
||
if (initQ.length >= 2) {
|
||
input.value = initQ;
|
||
setTimeout(() => startSearch(initQ), 100);
|
||
} else if (initTab === 'hashtags') {
|
||
// Populäre Tags zeigen wenn kein Suchbegriff
|
||
setTimeout(() => loadHashtags(''), 100);
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|