diff --git a/backend/src/db.js b/backend/src/db.js index c5ad4aa..adb8e1f 100644 --- a/backend/src/db.js +++ b/backend/src/db.js @@ -302,6 +302,8 @@ if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='boa const boardCols = db.prepare("PRAGMA table_info(board_items)").all().map(r => r.name); if (boardCols.length && !boardCols.includes('promoted_from_wish')) db.exec("ALTER TABLE board_items ADD COLUMN promoted_from_wish INTEGER NOT NULL DEFAULT 0"); +if (boardCols.length && !boardCols.includes('promoted_at')) + db.exec("ALTER TABLE board_items ADD COLUMN promoted_at DATETIME DEFAULT NULL"); if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='board_reads'").get()) { db.exec(` CREATE TABLE board_reads ( diff --git a/backend/src/routes/dashboard.js b/backend/src/routes/dashboard.js index 1ccb327..37369d0 100644 --- a/backend/src/routes/dashboard.js +++ b/backend/src/routes/dashboard.js @@ -146,7 +146,10 @@ router.get('/board/unread', authenticate, (req, res) => { const unread = lastRead ? db.prepare("SELECT COUNT(*) c FROM board_items WHERE created_at > ? AND user_id != ?").get(lastRead, u).c : db.prepare('SELECT COUNT(*) c FROM board_items WHERE user_id != ?').get(u).c; - res.json({ unread }); + const unreadPromoted = lastRead + ? db.prepare("SELECT COUNT(*) c FROM board_items WHERE promoted_at > ? AND user_id != ?").get(lastRead, u).c + : db.prepare("SELECT COUNT(*) c FROM board_items WHERE promoted_at IS NOT NULL AND user_id != ?").get(u).c; + res.json({ unread, unreadPromoted }); }); router.post('/board/read', authenticate, (req, res) => { @@ -195,7 +198,7 @@ router.post('/board/:id/promote', authenticate, (req, res) => { const item = db.prepare('SELECT * FROM board_items WHERE id=?').get(req.params.id); if (!item) return res.status(404).json({ error: 'Nicht gefunden' }); if (item.type !== 'wish') return res.status(400).json({ error: 'Nur Wünsche können befördert werden' }); - db.prepare('UPDATE board_items SET type=?, promoted_from_wish=1 WHERE id=?').run('roadmap', item.id); + db.prepare("UPDATE board_items SET type='roadmap', promoted_from_wish=1, promoted_at=datetime('now','localtime') WHERE id=?").run(item.id); const updated = db.prepare(` SELECT b.*, u.username as author FROM board_items b JOIN users u ON u.id=b.user_id WHERE b.id=? diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index b95a828..d19442b 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -990,15 +990,17 @@ function BoardModal({ user, toast, onClose, onRead }) { } -function Dashboard({ toast, mobile, setActive, unreadMsgs=0, unreadBoard=0, user }) { +function Dashboard({ toast, mobile, setActive, unreadMsgs=0, unreadBoard=0, unreadPromoted=0, user }) { const [now, setNow] = useState(new Date()); const [showBoard, setShowBoard] = useState(false); - const [boardUnread, setBoardUnread] = useState(unreadBoard); + const [boardUnread, setBoardUnread] = useState(unreadBoard); + const [promotedUnread, setPromotedUnread] = useState(unreadPromoted); useEffect(()=>{ setBoardUnread(unreadBoard); },[unreadBoard]); + useEffect(()=>{ setPromotedUnread(unreadPromoted); },[unreadPromoted]); useEffect(() => { const t = setInterval(() => setNow(new Date()), 30000); return () => clearInterval(t); }, []); return (
- {showBoard && setShowBoard(false)} onRead={()=>setBoardUnread(0)}/>} + {showBoard && setShowBoard(false)} onRead={()=>{ setBoardUnread(0); setPromotedUnread(0); }}/>}

Dashboard

@@ -1034,6 +1036,14 @@ function Dashboard({ toast, mobile, setActive, unreadMsgs=0, unreadBoard=0, user )} + {promotedUnread > 0 && boardUnread === 0 && ( + + )} + {promotedUnread > 0 && boardUnread > 0 && ( + + )}
@@ -1793,7 +1803,8 @@ export default function App() { const [updateInfo,setUpdateInfo]=useState(null); const [showUpd,setShowUpd]=useState(false); const [unreadMsgs, setUnreadMsgs] = useState(0); - const [unreadBoard, setUnreadBoard] = useState(0); + const [unreadBoard, setUnreadBoard] = useState(0); + const [unreadPromoted, setUnreadPromoted] = useState(0); const [authChecked, setAuthChecked] = useState(false); useEffect(()=>{ @@ -1828,7 +1839,7 @@ export default function App() { useEffect(()=>{ if(!user)return; - const poll=()=>api('/dashboard/board/unread').then(d=>setUnreadBoard(d.unread||0)).catch(()=>{}); + const poll=()=>api('/dashboard/board/unread').then(d=>{ setUnreadBoard(d.unread||0); setUnreadPromoted(d.unreadPromoted||0); }).catch(()=>{}); poll(); const t=setInterval(poll,60*1000); return()=>clearInterval(t); @@ -1881,7 +1892,7 @@ export default function App() { unreadMsgs={unreadMsgs}/> )}
- {active==='dashboard' && } + {active==='dashboard' && } {active==='admin' && } {activeTool && }