feat: User-Benachrichtigung wenn Admin Favoriten quittiert
This commit is contained in:
@@ -560,6 +560,8 @@ if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='mov
|
|||||||
db.exec("ALTER TABLE movie_favorites ADD COLUMN acknowledged INTEGER NOT NULL DEFAULT 0");
|
db.exec("ALTER TABLE movie_favorites ADD COLUMN acknowledged INTEGER NOT NULL DEFAULT 0");
|
||||||
if (!cols.includes('acknowledged_at'))
|
if (!cols.includes('acknowledged_at'))
|
||||||
db.exec("ALTER TABLE movie_favorites ADD COLUMN acknowledged_at DATETIME DEFAULT NULL");
|
db.exec("ALTER TABLE movie_favorites ADD COLUMN acknowledged_at DATETIME DEFAULT NULL");
|
||||||
|
if (!cols.includes('user_notified'))
|
||||||
|
db.exec("ALTER TABLE movie_favorites ADD COLUMN user_notified INTEGER NOT NULL DEFAULT 0");
|
||||||
if (!cols.includes('media_type'))
|
if (!cols.includes('media_type'))
|
||||||
db.exec("ALTER TABLE movie_favorites ADD COLUMN media_type TEXT NOT NULL DEFAULT 'movie'");
|
db.exec("ALTER TABLE movie_favorites ADD COLUMN media_type TEXT NOT NULL DEFAULT 'movie'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -503,18 +503,28 @@ router.get('/favorites/all', authenticate, requireAdmin, (req, res) => {
|
|||||||
res.json(favs);
|
res.json(favs);
|
||||||
});
|
});
|
||||||
|
|
||||||
// GET /favorites/unacked – unquittierte Zählung
|
// GET /favorites/unacked – unquittierte Zählung (Admin: neue Favoriten; User: quittierte aber unbestätigte)
|
||||||
router.get('/favorites/unacked', authenticate, (req, res) => {
|
router.get('/favorites/unacked', authenticate, (req, res) => {
|
||||||
const isAdmin = req.user.role === 'admin';
|
const isAdmin = req.user.role === 'admin';
|
||||||
const count = isAdmin
|
if (isAdmin) {
|
||||||
? db.prepare('SELECT COUNT(*) as n FROM movie_favorites WHERE acknowledged=0').get()
|
const count = db.prepare('SELECT COUNT(*) as n FROM movie_favorites WHERE acknowledged=0').get();
|
||||||
: db.prepare('SELECT COUNT(*) as n FROM movie_favorites WHERE user_id=? AND acknowledged=0').get(req.user.id);
|
res.json({ count: count.n, isAdmin: true });
|
||||||
res.json({ count: count.n });
|
} else {
|
||||||
|
// User: Favoriten die vom Admin quittiert wurden aber User noch nicht gesehen hat
|
||||||
|
const count = db.prepare('SELECT COUNT(*) as n FROM movie_favorites WHERE user_id=? AND acknowledged=1 AND user_notified=0').get(req.user.id);
|
||||||
|
res.json({ count: count.n, isAdmin: false });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// POST /favorites/user-notify – User bestätigt Kenntnis der quittierten Favoriten
|
||||||
|
router.post('/favorites/user-notify', authenticate, (req, res) => {
|
||||||
|
db.prepare('UPDATE movie_favorites SET user_notified=1 WHERE user_id=? AND acknowledged=1 AND user_notified=0').run(req.user.id);
|
||||||
|
res.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
// POST /favorites/acknowledge-all – Admin: alle quittieren
|
// POST /favorites/acknowledge-all – Admin: alle quittieren
|
||||||
router.post('/favorites/acknowledge-all', authenticate, requireAdmin, (req, res) => {
|
router.post('/favorites/acknowledge-all', authenticate, requireAdmin, (req, res) => {
|
||||||
db.prepare('UPDATE movie_favorites SET acknowledged=1, acknowledged_at=CURRENT_TIMESTAMP WHERE acknowledged=0').run();
|
db.prepare('UPDATE movie_favorites SET acknowledged=1, acknowledged_at=CURRENT_TIMESTAMP, user_notified=0 WHERE acknowledged=0').run();
|
||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -563,7 +573,7 @@ router.delete('/favorites/:tmdb_id', authenticate, (req, res) => {
|
|||||||
|
|
||||||
// POST /favorites/:id/acknowledge – Admin: einzelnen quittieren
|
// POST /favorites/:id/acknowledge – Admin: einzelnen quittieren
|
||||||
router.post('/favorites/:id/acknowledge', authenticate, requireAdmin, (req, res) => {
|
router.post('/favorites/:id/acknowledge', authenticate, requireAdmin, (req, res) => {
|
||||||
db.prepare('UPDATE movie_favorites SET acknowledged=1, acknowledged_at=CURRENT_TIMESTAMP WHERE id=?').run(req.params.id);
|
db.prepare('UPDATE movie_favorites SET acknowledged=1, acknowledged_at=CURRENT_TIMESTAMP, user_notified=0 WHERE id=?').run(req.params.id);
|
||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1983,12 +1983,22 @@ function Dashboard({ toast, mobile, setActive, setDevToolsNav, unreadMsgs=0, unr
|
|||||||
</button>
|
</button>
|
||||||
{/* Unquittierte Favoriten für alle User */}
|
{/* Unquittierte Favoriten für alle User */}
|
||||||
{unackedFavs > 0 && (
|
{unackedFavs > 0 && (
|
||||||
<button onClick={()=>{ setActive('media'); setTimeout(()=>window.dispatchEvent(new CustomEvent('media-navigate',{detail:'favoriten'})),80); }} style={{
|
<button onClick={()=>{
|
||||||
|
if (unackedFavs?.isAdmin) {
|
||||||
|
setActive('media');
|
||||||
|
setTimeout(()=>window.dispatchEvent(new CustomEvent('media-navigate',{detail:'favoriten'})),80);
|
||||||
|
} else {
|
||||||
|
api('/tools/media/favorites/user-notify',{method:'POST',body:{}}).then(()=>setUnackedFavs({count:0,isAdmin:false})).catch(()=>{});
|
||||||
|
}
|
||||||
|
}} style={{
|
||||||
background:'rgba(245,158,11,0.12)', border:'1px solid rgba(245,158,11,0.35)',
|
background:'rgba(245,158,11,0.12)', border:'1px solid rgba(245,158,11,0.35)',
|
||||||
borderRadius:7, color:'#f59e0b', cursor:'pointer',
|
borderRadius:7, color:'#f59e0b', cursor:'pointer',
|
||||||
padding:'4px 10px', fontSize:9, fontFamily:'monospace', letterSpacing:1,
|
padding:'4px 10px', fontSize:9, fontFamily:'monospace', letterSpacing:1,
|
||||||
}}>
|
}}>
|
||||||
⭐ {unackedFavs} neue Favorit{unackedFavs!==1?'en':''}
|
{unackedFavs?.isAdmin
|
||||||
|
? `⭐ ${unackedFavs.count} neue Favorit${unackedFavs.count!==1?'en':''}`
|
||||||
|
: `✅ ${unackedFavs.count} Favorit${unackedFavs.count!==1?'en':' wurde'} bestätigt`
|
||||||
|
}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -3618,7 +3628,7 @@ export default function App() {
|
|||||||
const [unreadBoard, setUnreadBoard] = useState(0);
|
const [unreadBoard, setUnreadBoard] = useState(0);
|
||||||
const [unreadPromoted, setUnreadPromoted] = useState(0);
|
const [unreadPromoted, setUnreadPromoted] = useState(0);
|
||||||
const [unreadChangelog,setUnreadChangelog]= useState(0);
|
const [unreadChangelog,setUnreadChangelog]= useState(0);
|
||||||
const [unackedFavs, setUnackedFavs] = useState(0);
|
const [unackedFavs, setUnackedFavs] = useState({count:0,isAdmin:false});
|
||||||
const [mediaInitTab, setMediaInitTab] = useState(null);
|
const [mediaInitTab, setMediaInitTab] = useState(null);
|
||||||
|
|
||||||
const [authChecked, setAuthChecked] = useState(false);
|
const [authChecked, setAuthChecked] = useState(false);
|
||||||
@@ -3658,7 +3668,7 @@ export default function App() {
|
|||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(!user)return;
|
if(!user)return;
|
||||||
const poll=()=>api('/tools/media/favorites/unacked').then(d=>setUnackedFavs(d.count||0)).catch(()=>{});
|
const poll=()=>api('/tools/media/favorites/unacked').then(d=>setUnackedFavs({count:d.count||0,isAdmin:d.isAdmin})).catch(()=>{});
|
||||||
poll(); const ti=setInterval(poll,60000); return()=>clearInterval(ti);
|
poll(); const ti=setInterval(poll,60000); return()=>clearInterval(ti);
|
||||||
},[user]);
|
},[user]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user