refactor(frontend): lint, one session guard, one request helper, one user context

This commit is contained in:
lobo committed 2026-09-29 15:40:55 +02:00
1 parent 111ab1e200
commit d0ea9e900d
78 files changed
+2138 -624

No files matched your search

+7 -20
View File
@@ -1,10 +1,9 @@
import {useCallback, useEffect, useState} from 'react';
import {Link, useNavigate, useSearchParams} from 'react-router-dom';
import {Link, useSearchParams} from 'react-router-dom';
import {useTranslation} from 'react-i18next';
import useLibrarySync from '../hooks/useLibrarySync.js';
import SyncStatusBadge from '../components/SyncStatusBadge.jsx';
import useForceSync from '../hooks/useForceSync.js';
import useSessionExpired from '../hooks/useSessionExpired.js';
import {formatPlaytime} from '../utils/games.js';
import {libraryQuery, parseStatus} from '../utils/backlog.js';
import {GAME_STATUSES, MAX_LIBRARY_SEARCH_LENGTH} from '../utils/limits.js';
@@ -22,7 +21,6 @@ import LibraryTabs from '../components/LibraryTabs.jsx';
import GameStatusBadge from '../components/GameStatusBadge.jsx';
import PageContainer from '../components/PageContainer.jsx';
import {apiFetch} from '../utils/api.js';
import {hasSession} from '../utils/auth.js';
import {platformLabel} from '../utils/platforms.js';
const PAGE_SIZES = [20, 40, 80];
@@ -42,8 +40,6 @@ const SORT_OPTIONS = [
export default function GameLibrary() {
const {t} = useTranslation();
const navigate = useNavigate();
const expireSession = useSessionExpired();
const [searchParams, setSearchParams] = useSearchParams();
const page = Math.max(0, parseInt(searchParams.get('page') ?? '0', 10) || 0);
@@ -70,10 +66,6 @@ export default function GameLibrary() {
const [error, setError] = useState(null);
const load = useCallback(async () => {
if (!hasSession()) {
navigate('/login');
return;
}
setIsLoading(true);
setError(null);
try {
@@ -84,10 +76,7 @@ export default function GameLibrary() {
},
});
if (response.status === 401) {
expireSession();
return;
}
if (response.status === 401) return;
if (!response.ok) {
setError('LIBRARY.ERROR_LOAD');
@@ -102,14 +91,13 @@ export default function GameLibrary() {
} finally {
setIsLoading(false);
}
}, [navigate, expireSession, page, size, sort, listStatus, q, listShortOnly, hiddenOnly]);
}, [page, size, sort, listStatus, q, listShortOnly, hiddenOnly]);
useEffect(() => {
load();
}, [load]);
useEffect(() => {
if (!hasSession()) return undefined;
let cancelled = false;
apiFetch(`${import.meta.env.VITE_CORE_API_URL}/api/library/games-count`)
.then((response) => (response.ok ? response.json() : null))
@@ -127,26 +115,25 @@ export default function GameLibrary() {
enabled: hasSteamId,
expectInitialSync,
onComplete: load,
onUnauthorized: expireSession,
});
const updateParams = (next) => {
const updateParams = useCallback((next) => {
const params = new URLSearchParams(searchParams);
Object.entries(next).forEach(([k, v]) => (v === null || v === '' ? params.delete(k) : params.set(k, String(v))));
setSearchParams(params);
};
}, [searchParams, setSearchParams]);
// Back/forward navigation changes q without typing. Keeps a trailing space the user is still typing.
useEffect(() => {
setSearch((current) => (current.trim() === q ? current : q));
}, [q]);
// searchParams is a dependency, so a status click during the delay restarts the timer with fresh params.
// updateParams changes with searchParams, so a status click during the delay restarts the timer with fresh params.
useEffect(() => {
if (search.trim() === q) return undefined;
const timer = setTimeout(() => updateParams({q: search.trim(), page: 0}), SEARCH_DEBOUNCE_MS);
return () => clearTimeout(timer);
}, [search, q, searchParams]);
}, [search, q, updateParams]);
const onStatusChange = (value) => {
updateParams({status: value, hidden: null, page: 0});