Bugfixes, Dating angefangen
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:
@@ -472,6 +472,55 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dating -->
|
||||
<div class="settings-section" id="sec-dating">
|
||||
<div class="settings-section-header" onclick="toggleSection('sec-dating')">
|
||||
<span class="settings-section-title">♥ Dating</span>
|
||||
<span class="settings-section-arrow">▸</span>
|
||||
</div>
|
||||
<div class="settings-section-body">
|
||||
<div class="settings-row">
|
||||
<div class="settings-row-info">
|
||||
<div class="settings-row-label">Dating aktivieren</div>
|
||||
<div class="settings-row-desc">Zeige dein Profil im Dating-Bereich. Ein Standort ist erforderlich.</div>
|
||||
</div>
|
||||
<label style="display:flex;align-items:center;gap:0.5rem;cursor:pointer;">
|
||||
<input type="checkbox" id="datingAktiv" style="width:1.1rem;height:1.1rem;accent-color:var(--color-primary);cursor:pointer;" onchange="onDatingToggle()">
|
||||
</label>
|
||||
</div>
|
||||
<div id="datingStadtRow" style="display:none;">
|
||||
<div class="settings-row" style="flex-wrap:wrap;gap:0.5rem;">
|
||||
<div class="settings-row-info">
|
||||
<div class="settings-row-label">Standort (Stadt)</div>
|
||||
<div class="settings-row-desc">Wird im Dating-Bereich angezeigt.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:0.5rem;margin-bottom:0.35rem;position:relative;">
|
||||
<div style="position:relative;flex:1;display:flex;">
|
||||
<input type="text" id="datingStadt" placeholder="Stadt suchen und auswählen…" autocomplete="off"
|
||||
style="flex:1;padding:0.55rem 2rem 0.55rem 0.8rem;border:1px solid var(--color-secondary);border-radius:6px;background:var(--color-secondary);color:var(--color-text);font-size:0.95rem;outline:none;"
|
||||
oninput="onStadtInput()">
|
||||
<button id="datingStadtClear" onclick="clearStadt()" title="Auswahl aufheben"
|
||||
style="display:none;position:absolute;right:0.4rem;top:50%;transform:translateY(-50%);
|
||||
background:none;border:none;color:var(--color-muted);font-size:1.1rem;cursor:pointer;padding:0.1rem 0.3rem;margin:0;line-height:1;">×</button>
|
||||
</div>
|
||||
<button onclick="detectLocation()" title="Standort ermitteln"
|
||||
style="white-space:nowrap;padding:0.55rem 0.9rem;margin:0;font-size:0.85rem;">
|
||||
⌖ Ermitteln
|
||||
</button>
|
||||
<ul id="stadtSuggestions" style="display:none;position:absolute;top:100%;left:0;right:3.5rem;
|
||||
background:var(--color-card);border:1px solid var(--color-secondary);border-radius:6px;
|
||||
z-index:100;list-style:none;margin:0.2rem 0 0;padding:0;max-height:200px;overflow-y:auto;"></ul>
|
||||
</div>
|
||||
<div id="datingLocMsg" style="font-size:0.82rem;color:var(--color-muted);margin-bottom:0.5rem;"></div>
|
||||
</div>
|
||||
<div class="settings-row" style="border-top:1px solid var(--color-secondary);padding-top:0.75rem;margin-top:0.25rem;">
|
||||
<button onclick="saveDating()" id="saveDatingBtn" style="margin:0;padding:0.55rem 1.25rem;font-size:0.9rem;">Speichern</button>
|
||||
<span id="datingMsg" style="font-size:0.85rem;"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Datenschutz -->
|
||||
<div class="settings-section" id="sec-datenschutz">
|
||||
<div class="settings-section-header" onclick="toggleSection('sec-datenschutz')">
|
||||
@@ -1134,8 +1183,152 @@
|
||||
loadBdsmDefaults();
|
||||
loadSubscription();
|
||||
loadTtlockUserConfig();
|
||||
loadDating();
|
||||
openSectionFromHash();
|
||||
|
||||
// ── Dating ──────────────────────────────────────────────────────────────
|
||||
|
||||
async function loadDating() {
|
||||
const res = await fetch('/login/me');
|
||||
if (!res.ok) return;
|
||||
const user = await res.json();
|
||||
document.getElementById('datingAktiv').checked = !!user.datingAktiv;
|
||||
if (user.datingStadt) {
|
||||
const input = document.getElementById('datingStadt');
|
||||
input.value = user.datingStadt;
|
||||
input.readOnly = true;
|
||||
document.getElementById('datingStadtClear').style.display = '';
|
||||
}
|
||||
if (user.datingLat != null) _datingLat = user.datingLat;
|
||||
if (user.datingLon != null) _datingLon = user.datingLon;
|
||||
document.getElementById('datingStadtRow').style.display = user.datingAktiv ? '' : 'none';
|
||||
}
|
||||
|
||||
function onDatingToggle() {
|
||||
const aktiv = document.getElementById('datingAktiv').checked;
|
||||
document.getElementById('datingStadtRow').style.display = aktiv ? '' : 'none';
|
||||
}
|
||||
|
||||
let _stadtSuggestTimer = null;
|
||||
let _datingLat = null;
|
||||
let _datingLon = null;
|
||||
|
||||
function onStadtInput() {
|
||||
const q = document.getElementById('datingStadt').value.trim();
|
||||
_datingLat = null;
|
||||
_datingLon = null;
|
||||
document.getElementById('datingStadtClear').style.display = 'none';
|
||||
clearTimeout(_stadtSuggestTimer);
|
||||
if (q.length < 2) { hideSuggestions(); return; }
|
||||
_stadtSuggestTimer = setTimeout(() => fetchStadtSuggestions(q), 300);
|
||||
}
|
||||
|
||||
async function fetchStadtSuggestions(q) {
|
||||
try {
|
||||
const url = `https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(q)}&format=json&addressdetails=1&limit=5&featuretype=city`;
|
||||
const res = await fetch(url, { headers: { 'Accept-Language': 'de' } });
|
||||
if (!res.ok) return;
|
||||
const results = await res.json();
|
||||
const ul = document.getElementById('stadtSuggestions');
|
||||
if (!results.length) { hideSuggestions(); return; }
|
||||
ul.innerHTML = results.map(r => {
|
||||
const city = r.address.city || r.address.town || r.address.village || r.address.county || r.name;
|
||||
const country = r.address.country || '';
|
||||
const label = city + (country ? ', ' + country : '');
|
||||
return `<li style="padding:0.5rem 0.75rem;cursor:pointer;font-size:0.9rem;border-bottom:1px solid var(--color-secondary);"
|
||||
onmousedown="selectStadt(event, '${label.replace(/'/g, "\\'")}', ${parseFloat(r.lat)}, ${parseFloat(r.lon)})">${label}</li>`;
|
||||
}).join('');
|
||||
ul.style.display = '';
|
||||
} catch (_) { hideSuggestions(); }
|
||||
}
|
||||
|
||||
function selectStadt(e, label, lat, lon) {
|
||||
e.preventDefault();
|
||||
const input = document.getElementById('datingStadt');
|
||||
input.value = label;
|
||||
input.readOnly = true;
|
||||
_datingLat = lat;
|
||||
_datingLon = lon;
|
||||
document.getElementById('datingStadtClear').style.display = '';
|
||||
hideSuggestions();
|
||||
}
|
||||
|
||||
function clearStadt() {
|
||||
const input = document.getElementById('datingStadt');
|
||||
input.value = '';
|
||||
input.readOnly = false;
|
||||
_datingLat = null;
|
||||
_datingLon = null;
|
||||
document.getElementById('datingStadtClear').style.display = 'none';
|
||||
input.focus();
|
||||
}
|
||||
|
||||
function hideSuggestions() {
|
||||
document.getElementById('stadtSuggestions').style.display = 'none';
|
||||
}
|
||||
|
||||
document.addEventListener('click', e => {
|
||||
if (!e.target.closest('#datingStadtRow')) hideSuggestions();
|
||||
});
|
||||
|
||||
async function detectLocation() {
|
||||
const msgEl = document.getElementById('datingLocMsg');
|
||||
if (!navigator.geolocation) { msgEl.textContent = 'Geolocation nicht unterstützt.'; return; }
|
||||
msgEl.textContent = 'Standort wird ermittelt…';
|
||||
navigator.geolocation.getCurrentPosition(async pos => {
|
||||
try {
|
||||
const { latitude, longitude } = pos.coords;
|
||||
const res = await fetch(
|
||||
`https://nominatim.openstreetmap.org/reverse?lat=${latitude}&lon=${longitude}&format=json&addressdetails=1`,
|
||||
{ headers: { 'Accept-Language': 'de' } }
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
const city = data.address.city || data.address.town || data.address.village || data.address.county || '';
|
||||
const country = data.address.country || '';
|
||||
const input = document.getElementById('datingStadt');
|
||||
input.value = city + (country ? ', ' + country : '');
|
||||
input.readOnly = true;
|
||||
_datingLat = latitude;
|
||||
_datingLon = longitude;
|
||||
document.getElementById('datingStadtClear').style.display = '';
|
||||
msgEl.textContent = '';
|
||||
} catch (_) { msgEl.textContent = 'Standort konnte nicht ermittelt werden.'; }
|
||||
}, () => { msgEl.textContent = 'Zugriff auf Standort verweigert.'; });
|
||||
}
|
||||
|
||||
async function saveDating() {
|
||||
const aktiv = document.getElementById('datingAktiv').checked;
|
||||
const stadt = document.getElementById('datingStadt').value.trim();
|
||||
const msgEl = document.getElementById('datingMsg');
|
||||
if (aktiv && (!stadt || _datingLat == null || _datingLon == null)) {
|
||||
msgEl.textContent = 'Bitte eine Stadt aus der Liste auswählen oder per GPS ermitteln.';
|
||||
msgEl.style.color = 'var(--color-primary)';
|
||||
return;
|
||||
}
|
||||
const btn = document.getElementById('saveDatingBtn');
|
||||
btn.disabled = true;
|
||||
try {
|
||||
const res = await fetch('/user/me/dating', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ datingAktiv: aktiv, datingStadt: stadt || null, datingLat: _datingLat, datingLon: _datingLon })
|
||||
});
|
||||
if (res.ok) {
|
||||
showToast();
|
||||
msgEl.textContent = '';
|
||||
} else {
|
||||
msgEl.textContent = 'Fehler beim Speichern.';
|
||||
msgEl.style.color = 'var(--color-primary)';
|
||||
}
|
||||
} catch (_) {
|
||||
msgEl.textContent = 'Server nicht erreichbar.';
|
||||
msgEl.style.color = 'var(--color-primary)';
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ── TTLock ──────────────────────────────────────────────────────────────
|
||||
|
||||
let _ttlPasswordSet = false;
|
||||
|
||||
Reference in New Issue
Block a user