feat: Hex Wars - Badge auch bei beendeten/abgebrochenen Spielen
This commit is contained in:
@@ -32,6 +32,7 @@ const router = express.Router();
|
|||||||
['opp_head', 'TEXT'],
|
['opp_head', 'TEXT'],
|
||||||
['owner_scouts', 'TEXT'],
|
['owner_scouts', 'TEXT'],
|
||||||
['opp_scouts', 'TEXT'],
|
['opp_scouts', 'TEXT'],
|
||||||
|
['seen_by', 'TEXT'],
|
||||||
]) {
|
]) {
|
||||||
if (!cols.includes(col)) db.exec(`ALTER TABLE geo_games ADD COLUMN ${col} ${def}`);
|
if (!cols.includes(col)) db.exec(`ALTER TABLE geo_games ADD COLUMN ${col} ${def}`);
|
||||||
}
|
}
|
||||||
@@ -281,14 +282,25 @@ router.get('/', authenticate, (req, res) => {
|
|||||||
res.json(games);
|
res.json(games);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Meine Züge: Anzahl Spiele wo ich dran bin ────────────────────────────────
|
// ── Meine Züge + ungesehene Spielenden ──────────────────────────────────────
|
||||||
router.get('/my-turns', authenticate, (req, res) => {
|
router.get('/my-turns', authenticate, (req, res) => {
|
||||||
const me = uid(req);
|
const me = uid(req);
|
||||||
const { count } = db.prepare(`
|
// Aktive Spiele wo ich dran bin
|
||||||
|
const { count: turns } = db.prepare(`
|
||||||
SELECT COUNT(*) as count FROM geo_games
|
SELECT COUNT(*) as count FROM geo_games
|
||||||
WHERE status='active' AND current_turn=?
|
WHERE status='active' AND current_turn=?
|
||||||
`).get(me);
|
`).get(me);
|
||||||
res.json({ count });
|
// Beendete Spiele wo ich beteiligt bin aber noch nicht gesehen habe
|
||||||
|
const games = db.prepare(`
|
||||||
|
SELECT id, seen_by FROM geo_games
|
||||||
|
WHERE status='finished' AND move_count >= 2
|
||||||
|
AND (owner_id=? OR opponent_id=?)
|
||||||
|
`).all(me, me);
|
||||||
|
const unseen = games.filter(g => {
|
||||||
|
const seen = g.seen_by ? JSON.parse(g.seen_by) : [];
|
||||||
|
return !seen.includes(me);
|
||||||
|
}).length;
|
||||||
|
res.json({ count: turns + unseen });
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Topliste ──────────────────────────────────────────────────────────────────
|
// ── Topliste ──────────────────────────────────────────────────────────────────
|
||||||
@@ -502,6 +514,20 @@ router.post('/:id/move', authenticate, (req, res) => {
|
|||||||
res.json(getGameForUser(game.id, me));
|
res.json(getGameForUser(game.id, me));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── Spiel als gesehen markieren ──────────────────────────────────────────────
|
||||||
|
router.post('/:id/seen', authenticate, (req, res) => {
|
||||||
|
const me = uid(req);
|
||||||
|
const game = db.prepare('SELECT * FROM geo_games WHERE id=?').get(req.params.id);
|
||||||
|
if (!game) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||||
|
if (game.owner_id !== me && game.opponent_id !== me) return res.status(403).json({ error: 'Kein Zugriff' });
|
||||||
|
const seen = game.seen_by ? JSON.parse(game.seen_by) : [];
|
||||||
|
if (!seen.includes(me)) {
|
||||||
|
seen.push(me);
|
||||||
|
db.prepare('UPDATE geo_games SET seen_by=? WHERE id=?').run(JSON.stringify(seen), game.id);
|
||||||
|
}
|
||||||
|
res.json({ ok: true });
|
||||||
|
});
|
||||||
|
|
||||||
// ── Scout: 3x3 Bereich aufdecken (kostet Zug) ───────────────────────────────
|
// ── Scout: 3x3 Bereich aufdecken (kostet Zug) ───────────────────────────────
|
||||||
router.post('/:id/scout', authenticate, (req, res) => {
|
router.post('/:id/scout', authenticate, (req, res) => {
|
||||||
const me = uid(req);
|
const me = uid(req);
|
||||||
|
|||||||
@@ -541,7 +541,13 @@ export default function HexWars({ toast }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeId) { setGame(null); return; }
|
if (!activeId) { setGame(null); return; }
|
||||||
api(`/tools/gebietseroberung/${activeId}`).then(setGame).catch(() => {});
|
api(`/tools/gebietseroberung/${activeId}`).then(g => {
|
||||||
|
setGame(g);
|
||||||
|
// Beendetes Spiel als gesehen markieren → Badge verschwindet
|
||||||
|
if (g.status === 'finished') {
|
||||||
|
api(`/tools/gebietseroberung/${activeId}/seen`, { body: {} }).catch(() => {});
|
||||||
|
}
|
||||||
|
}).catch(() => {});
|
||||||
}, [activeId]);
|
}, [activeId]);
|
||||||
|
|
||||||
// Polling wenn Gegner dran
|
// Polling wenn Gegner dran
|
||||||
@@ -567,6 +573,9 @@ export default function HexWars({ toast }) {
|
|||||||
const handleMove = async (row, col) => {
|
const handleMove = async (row, col) => {
|
||||||
const updated = await api(`/tools/gebietseroberung/${activeId}/move`, { body: { row, col } });
|
const updated = await api(`/tools/gebietseroberung/${activeId}/move`, { body: { row, col } });
|
||||||
setGame(updated);
|
setGame(updated);
|
||||||
|
if (updated.status === 'finished') {
|
||||||
|
api(`/tools/gebietseroberung/${activeId}/seen`, { body: {} }).catch(() => {});
|
||||||
|
}
|
||||||
// Direkt den games-State patchen damit die Liste sofort stimmt (kein Warten auf loadGames)
|
// Direkt den games-State patchen damit die Liste sofort stimmt (kein Warten auf loadGames)
|
||||||
setGames(prev => prev.map(g => g.id === updated.id
|
setGames(prev => prev.map(g => g.id === updated.id
|
||||||
? { ...g, current_turn: updated.current_turn, move_count: updated.move_count, status: updated.status, winner_id: updated.winner_id }
|
? { ...g, current_turn: updated.current_turn, move_count: updated.move_count, status: updated.status, winner_id: updated.winner_id }
|
||||||
|
|||||||
Reference in New Issue
Block a user