feat(dashboard): playtime chart, recently played and a playing hint

The dashboard shows the playtime of the last 30 days and Steam's recently
played games. The detail page offers to set a backlog game to Playing when
Steam reports recent playtime; unsaved edits in the backlog card stay.
This commit is contained in:
lobo committed 2026-09-24 13:41:37 +02:00
1 parent d4c0f8d8f3
commit 89c5ba5253
11 files changed
+334 -15

No files matched your search

+9 -7
View File
@@ -1,4 +1,4 @@
import {useState} from 'react';
import {useEffect, useState} from 'react';
import {useNavigate} from 'react-router-dom';
import {useTranslation} from 'react-i18next';
import {toast} from 'sonner';
@@ -11,7 +11,7 @@ import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/c
import {Textarea} from '@/components/ui/textarea';
import {cn} from '@/lib/utils';
import {STATUS_META} from './GameStatusBadge.jsx';
import {GAME_PRIORITIES, GAME_STATUSES, NO_PRIORITY, toBacklogRequest} from '../utils/backlog.js';
import {GAME_PRIORITIES, GAME_STATUSES, NO_PRIORITY, saveBacklogEntry, toBacklogRequest} from '../utils/backlog.js';
import useSessionExpired from '../hooks/useSessionExpired.js';
const NOTES_MAX = 2000;
@@ -29,6 +29,12 @@ export default function BacklogCard({game, onSaved}) {
const expireSession = useSessionExpired();
const [saved, setSaved] = useState(() => toForm(game));
const [form, setForm] = useState(saved);
// The PlayingHint can change the status from outside; keep the other unsaved edits.
useEffect(() => {
setSaved((current) => (current.status === game.status ? current : {...current, status: game.status}));
setForm((current) => (current.status === game.status ? current : {...current, status: game.status}));
}, [game.status]);
const [busy, setBusy] = useState(false);
const dirty = JSON.stringify(form) !== JSON.stringify(saved);
@@ -42,11 +48,7 @@ export default function BacklogCard({game, onSaved}) {
}
setBusy(true);
try {
const response = await fetch(`${import.meta.env.VITE_CORE_API_URL}/api/library/games/${game.appid}/backlog`, {
method: 'PUT',
headers: {'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json'},
body: JSON.stringify(toBacklogRequest(form)),
});
const response = await saveBacklogEntry(game.appid, toBacklogRequest(form));
if (response.status === 401) {
expireSession();
return;