From fc7d7431535c573981b434e0001454fae675a627 Mon Sep 17 00:00:00 2001 From: rene Date: Fri, 24 Apr 2026 08:39:41 +0200 Subject: [PATCH] Badge-System: personal/general Split, Punkte ohne Zahl, SW by-v328 --- backend/routes/notifications.py | 29 +++++++++++++++++++++++++++++ backend/static/js/api.js | 1 + backend/static/js/app.js | 16 ++++------------ backend/static/sw.js | 2 +- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/backend/routes/notifications.py b/backend/routes/notifications.py index 0990748..0805896 100644 --- a/backend/routes/notifications.py +++ b/backend/routes/notifications.py @@ -40,6 +40,35 @@ async def unread_count(user=Depends(get_current_user)): return {"count": row[0]} +# ------------------------------------------------------------------ +# GET /api/notifications/badge — Dot-Indikatoren für Header +# personal: Chat, Freunde, Trainer, Sitting, Gesundheit, Meilensteine +# general: Gassi-Treffen, Giftköder, Verlorene Hunde, Wetter +# ------------------------------------------------------------------ +_PERSONAL = { + 'chat_message', 'friend_request', 'weekly_praise', + 'health_reminder', 'milestone', + 'sitting_request', 'sitting_confirmed', 'sitting_cancelled', +} +_GENERAL = { + 'walk_invite', 'lost_dog_alert', 'poison_alert', + 'weather_heat', 'weather_thunder', +} + +@router.get("/badge") +async def badge_status(user=Depends(get_current_user)): + with db() as conn: + rows = conn.execute( + "SELECT DISTINCT type FROM notifications WHERE user_id=? AND read_at IS NULL", + (user["id"],), + ).fetchall() + types = {r["type"] for r in rows} + return { + "personal": bool(types & _PERSONAL), + "general": bool(types & _GENERAL), + } + + # ------------------------------------------------------------------ # PATCH /api/notifications/read-all — alle als gelesen markieren # ------------------------------------------------------------------ diff --git a/backend/static/js/api.js b/backend/static/js/api.js index 7341740..2d8844d 100644 --- a/backend/static/js/api.js +++ b/backend/static/js/api.js @@ -515,6 +515,7 @@ const API = (() => { const notifications = { list() { return get('/notifications'); }, unreadCount() { return get('/notifications/unread-count'); }, + badge() { return get('/notifications/badge'); }, readAll() { return patch('/notifications/read-all', {}); }, read(id) { return patch(`/notifications/${id}/read`, {}); }, delete(id) { return del(`/notifications/${id}`); }, diff --git a/backend/static/js/app.js b/backend/static/js/app.js index f626c5e..d3235ec 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '315'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '316'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const App = (() => { @@ -470,13 +470,9 @@ const App = (() => { async function _updateNotifBadge() { if (!state.user) return; try { - const { count } = await API.notifications.unreadCount(); - // Sidebar-Badge (Zahl) — entfernt aus Sidebar, aber ID bleibt für Kompatibilität - const badge = document.getElementById('notif-badge'); - if (badge) { badge.textContent = count; badge.style.display = count > 0 ? '' : 'none'; } - // Burger-Punkt - const navBadge = document.getElementById('notif-nav-badge'); - if (navBadge) navBadge.classList.toggle('hidden', count === 0); + const b = await API.notifications.badge(); + document.getElementById('notif-nav-badge')?.classList.toggle('hidden', !b.general); + document.getElementById('chat-nav-badge')?.classList.toggle('hidden', !b.personal); } catch { /* ignorieren */ } } @@ -485,12 +481,8 @@ const App = (() => { try { const convs = await API.chat.conversations(); const total = convs.reduce((s, c) => s + (c.unread_count || 0), 0); - // Sidebar-Badge (Zahl) const badge = document.getElementById('chat-badge'); if (badge) { badge.textContent = total; badge.style.display = total > 0 ? '' : 'none'; } - // Avatar-Punkt - const navBadge = document.getElementById('chat-nav-badge'); - if (navBadge) navBadge.classList.toggle('hidden', total === 0); } catch { /* ignorieren */ } } diff --git a/backend/static/sw.js b/backend/static/sw.js index 906279e..635461c 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -3,7 +3,7 @@ Offline-Cache + Push Notifications + Tile-Cache ============================================================ */ -const CACHE_VERSION = 'by-v327'; +const CACHE_VERSION = 'by-v328'; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten