fix: abort old loads, stale sync state, warn before unsaved edits are lost

This commit is contained in:
lobo committed 2026-09-30 07:51:09 +02:00
1 parent cbafa3d540
commit 9ddc50f819
28 files changed
+753 -121

No files matched your search

+13 -33
View File
@@ -26,7 +26,8 @@ import useSaveAppearance from '../hooks/useSaveAppearance.js';
import {usePreferences} from '../context/PreferencesContext.jsx';
import PageContainer from '../components/PageContainer.jsx';
import ProfileArtMenu from '../components/ProfileArtMenu.jsx';
import {apiFetch} from '../utils/api.js';
import {request} from '../utils/api.js';
import useAbortPrevious from '../hooks/useAbortPrevious.js';
import {ACHIEVEMENT_ICONS, reportBrokenImage} from '../utils/brokenImages.js';
import {canCorrect} from '../utils/corrections.js';
import {celebrationFor, celebrationLevel} from '../utils/confetti.js';
@@ -94,43 +95,22 @@ export default function GameDetail() {
setData(null);
}
const nextSignal = useAbortPrevious();
useEffect(() => {
let cancelled = false;
const signal = nextSignal();
setIsLoading(true);
setError(null);
(async () => {
try {
const url = `${import.meta.env.VITE_CORE_API_URL}/api/library/games/${appid}`;
const response = await apiFetch(url, {
headers: {
'Content-Type': 'application/json',
},
});
if (cancelled) return;
if (response.status === 401) return;
if (response.status === 404) {
setError('GAME_DETAIL.NOT_FOUND');
return;
}
if (!response.ok) {
setError('GAME_DETAIL.ERROR_LOAD');
return;
}
const json = await response.json();
setData(json);
} catch (err) {
if (!cancelled) {
console.error('GameDetail load error:', err);
setError('INFO.ERROR.NETWORK_FAILURE');
}
} finally {
if (!cancelled) setIsLoading(false);
}
const {ok, status, data: json} = await request(
`${import.meta.env.VITE_CORE_API_URL}/api/library/games/${appid}`, {signal});
if (signal.aborted) return;
setIsLoading(false);
if (status === 401) return;
if (status === 404) setError('GAME_DETAIL.NOT_FOUND');
else if (!ok || !json) setError(status === 0 ? 'INFO.ERROR.NETWORK_FAILURE' : 'GAME_DETAIL.ERROR_LOAD');
else setData(json);
})();
return () => {
cancelled = true;
};
}, [appid, reloads]);
}, [nextSignal, appid, reloads]);
const sortedAchievements = useMemo(() => {
if (!data?.achievements) return [];