Board: gelber Punkt bei befördertem Wunsch, promoted_at Tracking
This commit is contained in:
@@ -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);
|
const boardCols = db.prepare("PRAGMA table_info(board_items)").all().map(r => r.name);
|
||||||
if (boardCols.length && !boardCols.includes('promoted_from_wish'))
|
if (boardCols.length && !boardCols.includes('promoted_from_wish'))
|
||||||
db.exec("ALTER TABLE board_items ADD COLUMN promoted_from_wish INTEGER NOT NULL DEFAULT 0");
|
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()) {
|
if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='board_reads'").get()) {
|
||||||
db.exec(`
|
db.exec(`
|
||||||
CREATE TABLE board_reads (
|
CREATE TABLE board_reads (
|
||||||
|
|||||||
@@ -146,7 +146,10 @@ router.get('/board/unread', authenticate, (req, res) => {
|
|||||||
const unread = lastRead
|
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 created_at > ? AND user_id != ?").get(lastRead, u).c
|
||||||
: db.prepare('SELECT COUNT(*) c FROM board_items WHERE user_id != ?').get(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) => {
|
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);
|
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) 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' });
|
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(`
|
const updated = db.prepare(`
|
||||||
SELECT b.*, u.username as author FROM board_items b
|
SELECT b.*, u.username as author FROM board_items b
|
||||||
JOIN users u ON u.id=b.user_id WHERE b.id=?
|
JOIN users u ON u.id=b.user_id WHERE b.id=?
|
||||||
|
|||||||
@@ -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 [now, setNow] = useState(new Date());
|
||||||
const [showBoard, setShowBoard] = useState(false);
|
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(()=>{ setBoardUnread(unreadBoard); },[unreadBoard]);
|
||||||
|
useEffect(()=>{ setPromotedUnread(unreadPromoted); },[unreadPromoted]);
|
||||||
useEffect(() => { const t = setInterval(() => setNow(new Date()), 30000); return () => clearInterval(t); }, []);
|
useEffect(() => { const t = setInterval(() => setNow(new Date()), 30000); return () => clearInterval(t); }, []);
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: mobile ? '14px 12px 90px' : '36px 44px', maxWidth:1100 }}>
|
<div style={{ padding: mobile ? '14px 12px 90px' : '36px 44px', maxWidth:1100 }}>
|
||||||
{showBoard && <BoardModal user={user} toast={toast} onClose={()=>setShowBoard(false)} onRead={()=>setBoardUnread(0)}/>}
|
{showBoard && <BoardModal user={user} toast={toast} onClose={()=>setShowBoard(false)} onRead={()=>{ setBoardUnread(0); setPromotedUnread(0); }}/>}
|
||||||
<div style={{ marginBottom:16, display:'flex', alignItems:'flex-start', justifyContent:'space-between' }}>
|
<div style={{ marginBottom:16, display:'flex', alignItems:'flex-start', justifyContent:'space-between' }}>
|
||||||
<div>
|
<div>
|
||||||
<h1 style={{ color:'#fff', fontFamily:"'Space Mono',monospace", fontSize:mobile ? 17 : 22, margin:0 }}>Dashboard</h1>
|
<h1 style={{ color:'#fff', fontFamily:"'Space Mono',monospace", fontSize:mobile ? 17 : 22, margin:0 }}>Dashboard</h1>
|
||||||
@@ -1034,6 +1036,14 @@ function Dashboard({ toast, mobile, setActive, unreadMsgs=0, unreadBoard=0, user
|
|||||||
<span style={{ position:'absolute', top:-3, right:-3, width:7, height:7,
|
<span style={{ position:'absolute', top:-3, right:-3, width:7, height:7,
|
||||||
borderRadius:'50%', background:'#4ecdc4', boxShadow:'0 0 5px #4ecdc4' }}/>
|
borderRadius:'50%', background:'#4ecdc4', boxShadow:'0 0 5px #4ecdc4' }}/>
|
||||||
)}
|
)}
|
||||||
|
{promotedUnread > 0 && boardUnread === 0 && (
|
||||||
|
<span style={{ position:'absolute', top:-3, right:-3, width:7, height:7,
|
||||||
|
borderRadius:'50%', background:'#ffe66d', boxShadow:'0 0 5px #ffe66d' }}/>
|
||||||
|
)}
|
||||||
|
{promotedUnread > 0 && boardUnread > 0 && (
|
||||||
|
<span style={{ position:'absolute', top:-3, left:-3, width:7, height:7,
|
||||||
|
borderRadius:'50%', background:'#ffe66d', boxShadow:'0 0 5px #ffe66d' }}/>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1793,7 +1803,8 @@ export default function App() {
|
|||||||
const [updateInfo,setUpdateInfo]=useState(null);
|
const [updateInfo,setUpdateInfo]=useState(null);
|
||||||
const [showUpd,setShowUpd]=useState(false);
|
const [showUpd,setShowUpd]=useState(false);
|
||||||
const [unreadMsgs, setUnreadMsgs] = useState(0);
|
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);
|
const [authChecked, setAuthChecked] = useState(false);
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
@@ -1828,7 +1839,7 @@ export default function App() {
|
|||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(!user)return;
|
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();
|
poll();
|
||||||
const t=setInterval(poll,60*1000);
|
const t=setInterval(poll,60*1000);
|
||||||
return()=>clearInterval(t);
|
return()=>clearInterval(t);
|
||||||
@@ -1881,7 +1892,7 @@ export default function App() {
|
|||||||
unreadMsgs={unreadMsgs}/>
|
unreadMsgs={unreadMsgs}/>
|
||||||
)}
|
)}
|
||||||
<main style={mainStyle}>
|
<main style={mainStyle}>
|
||||||
{active==='dashboard' && <Dashboard toast={toast} mobile={mobile} setActive={setActive} unreadMsgs={unreadMsgs} unreadBoard={unreadBoard} user={user}/>}
|
{active==='dashboard' && <Dashboard toast={toast} mobile={mobile} setActive={setActive} unreadMsgs={unreadMsgs} unreadBoard={unreadBoard} unreadPromoted={unreadPromoted} user={user}/>}
|
||||||
{active==='admin' && <AdminPanel toast={toast} mobile={mobile} user={user}/>}
|
{active==='admin' && <AdminPanel toast={toast} mobile={mobile} user={user}/>}
|
||||||
{activeTool && <activeTool.component toast={toast} mobile={mobile} setActive={setActive}/>}
|
{activeTool && <activeTool.component toast={toast} mobile={mobile} setActive={setActive}/>}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Reference in New Issue
Block a user