Public Access
fix: abort old loads, stale sync state, warn before unsaved edits are lost
This commit is contained in:
1 parent
cbafa3d540
commit
9ddc50f819
28 files changed
+753
-121
No files matched your search
+16
-25
@@ -20,7 +20,8 @@ import GameCover from '../components/GameCover.jsx';
|
||||
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 {apiFetch, request} from '../utils/api.js';
|
||||
import useAbortPrevious from '../hooks/useAbortPrevious.js';
|
||||
import {platformLabel} from '../utils/platforms.js';
|
||||
|
||||
const PAGE_SIZES = [20, 40, 80];
|
||||
@@ -65,33 +66,22 @@ export default function GameLibrary() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
const nextSignal = useAbortPrevious();
|
||||
const load = useCallback(async () => {
|
||||
const signal = nextSignal();
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const url = `${import.meta.env.VITE_CORE_API_URL}/api/library/games?${libraryQuery({page, size, sort, status: listStatus, q, maxMinutes: listShortOnly ? SHORT_GAME_MINUTES : null, hidden: hiddenOnly})}`;
|
||||
const response = await apiFetch(url, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (response.status === 401) return;
|
||||
|
||||
if (!response.ok) {
|
||||
setError('LIBRARY.ERROR_LOAD');
|
||||
return;
|
||||
}
|
||||
|
||||
const json = await response.json();
|
||||
setData(json);
|
||||
} catch (err) {
|
||||
console.error('Library load error:', err);
|
||||
setError('INFO.ERROR.NETWORK_FAILURE');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
const url = `${import.meta.env.VITE_CORE_API_URL}/api/library/games?${libraryQuery({page, size, sort, status: listStatus, q, maxMinutes: listShortOnly ? SHORT_GAME_MINUTES : null, hidden: hiddenOnly})}`;
|
||||
const {ok, status, data: json} = await request(url, {signal});
|
||||
if (signal.aborted) return;
|
||||
setIsLoading(false);
|
||||
if (status === 401) return;
|
||||
if (!ok || !json) {
|
||||
setError(status === 0 ? 'INFO.ERROR.NETWORK_FAILURE' : 'LIBRARY.ERROR_LOAD');
|
||||
return;
|
||||
}
|
||||
}, [page, size, sort, listStatus, q, listShortOnly, hiddenOnly]);
|
||||
setData(json);
|
||||
}, [nextSignal, page, size, sort, listStatus, q, listShortOnly, hiddenOnly]);
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
@@ -156,7 +146,7 @@ export default function GameLibrary() {
|
||||
updateParams({page: target});
|
||||
};
|
||||
|
||||
const {trigger: triggerSync, busy: syncBusy} = useForceSync(load);
|
||||
const {trigger: triggerSync, busy: syncBusy} = useForceSync(sync.watch);
|
||||
|
||||
const syncing = syncBusy || sync.isRunning;
|
||||
const ready = !isLoading && !error;
|
||||
@@ -174,6 +164,7 @@ export default function GameLibrary() {
|
||||
status={sync.status}
|
||||
lastSyncedAt={sync.lastSyncedAt}
|
||||
isRunning={sync.isRunning}
|
||||
stale={sync.stale}
|
||||
/>
|
||||
<Button variant="outline" size="sm" onClick={triggerSync} disabled={syncing}>
|
||||
<RefreshCw className={syncing ? 'animate-spin' : ''}/>
|
||||
|
||||
Reference in new issue
Block a user