Navigation, Karten-FABs, Nearby-Alerts

- Bottom-Nav neu: Karte | Routen | + | Tagebuch | Forum
- + reduziert auf: Giftköder, Gassi-Treffen, Verlorener Hund
- Notification-Badge auf User-Avatar (Header)
- Nearby-Alerts: Nav-Leiste pulsiert rot/orange bei Giftköder/vermisstm Hund in 20km
- SW postMessage bei poison/lost_alert → sofortiger Alert-Check
- Karten-FABs: nur Marker setzen + Standort (Route aufzeichnen + Offline entfernt)
- SW by-v272, APP_VER 262
This commit is contained in:
rene 2026-04-20 19:46:34 +02:00
parent 5141ba9969
commit 65d1cf6c7f
7 changed files with 105 additions and 27 deletions

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '261'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '262'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const App = (() => {
@ -361,17 +361,14 @@ const App = (() => {
</button>`;
UI.modal.open({
title: 'Was möchtest du hinzufügen?',
title: 'Schnellmeldung',
body: `
<div class="flex flex-col gap-3">
${authBtn('diary', 'btn-secondary', 'book-open', 'Tagebuch-Eintrag')}
${authBtn('health', 'btn-secondary', 'syringe', 'Gesundheits-Eintrag')}
${authBtn('chat', 'btn-secondary', 'chat-circle-dots','Neue Nachricht')}
${authBtn('forum', 'btn-secondary', 'push-pin', 'Forenbeitrag erstellen')}
<button class="btn btn-danger w-full" data-quick="poison">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning-octagon"></use></svg> Giftköder melden
</button>
${authBtn('walk', 'btn-nature', 'paw-print', 'Gassi-Treffen erstellen')}
${authBtn('walk', 'btn-secondary', 'paw-print', 'Gassi-Treffen erstellen')}
${authBtn('lost', 'btn-secondary', 'magnifying-glass','Verlorener Hund melden')}
</div>
${!loggedIn ? `<p style="font-size:var(--text-xs);color:var(--c-text-muted);text-align:center;margin-top:var(--space-3)">
<svg class="ph-icon" style="width:12px;height:12px" aria-hidden="true"><use href="/icons/phosphor.svg#info"></use></svg>
@ -391,12 +388,9 @@ const App = (() => {
// Ohne Delay trifft es das neu geöffnete Modal und schließt es sofort.
setTimeout(() => {
if (action.startsWith('auth-')) { navigate('settings'); return; }
if (action === 'diary') { navigate('diary'); pages['diary'].module?.openNew?.(); }
if (action === 'health') { navigate('health'); pages['health'].module?.openNew?.(); }
if (action === 'poison') { navigate('poison'); pages['poison'].module?.openNew?.(); }
if (action === 'walk') { navigate('walks'); pages['walks'].module?.openNew?.(); }
if (action === 'chat') { navigate('chat'); setTimeout(() => pages['chat'].module?._showNewMessagePicker?.(), 400); }
if (action === 'forum') { navigate('forum'); setTimeout(() => pages['forum'].module?.openNew?.(), 400); }
if (action === 'lost') { navigate('lost'); setTimeout(() => pages['lost'].module?.openNew?.(), 400); }
}, 350);
}, { once: true });
}
@ -434,11 +428,14 @@ const App = (() => {
_updateNotifBadge();
_updateChatBadge();
_checkNearbyAlerts();
setInterval(() => { _updateNotifBadge(); _updateChatBadge(); }, 30_000);
setInterval(_checkNearbyAlerts, 5 * 60_000);
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
_updateNotifBadge();
_updateChatBadge();
_checkNearbyAlerts();
if (state.page === 'chat') {
pages['chat']?.module?.refresh?.();
}
@ -452,6 +449,22 @@ const App = (() => {
}
}
async function _checkNearbyAlerts() {
const nav = document.getElementById('bottom-nav');
if (!nav) return;
try {
const pos = await new Promise((resolve, reject) =>
navigator.geolocation.getCurrentPosition(resolve, reject, { timeout: 5000, maximumAge: 120_000 })
);
const { latitude: lat, longitude: lon } = pos.coords;
const data = await API.get(`/alerts?lat=${lat}&lon=${lon}`);
nav.classList.toggle('alert-poison', !!data.poison);
nav.classList.toggle('alert-lost', !data.poison && !!data.lost);
} catch {
// Kein Standort verfügbar — kein Alert anzeigen
}
}
async function _updateNotifBadge() {
if (!state.user) return;
try {
@ -820,7 +833,8 @@ const App = (() => {
renderDogSwitcher: _renderDogSwitcher,
getInstallPrompt: () => _installPrompt, requireAuth,
showOnboarding: _showOnboardingModal,
updateNotifBadge: _updateNotifBadge };
updateNotifBadge: _updateNotifBadge,
_checkNearbyAlerts };
})();