Add missing error handling

This commit is contained in:
schroda
2024-04-27 22:28:55 +02:00
parent a447719309
commit 773d2b1026
20 changed files with 322 additions and 65 deletions

View File

@@ -7,7 +7,6 @@
*/
import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
import Stack from '@mui/material/Stack';
import Tooltip from '@mui/material/Tooltip';
import { styled } from '@mui/material/styles';
@@ -36,6 +35,8 @@ import { Chapters } from '@/lib/data/Chapters.ts';
import { ChaptersWithMeta } from '@/lib/data/ChaptersWithMeta.ts';
import { ChapterActionMenuItems } from '@/components/chapter/ChapterActionMenuItems.tsx';
import { ChaptersDownloadActionMenuItems } from '@/components/chapter/ChaptersDownloadActionMenuItems.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
const ChapterListHeader = styled(Stack)(({ theme }) => ({
margin: 8,
@@ -77,7 +78,12 @@ export const ChapterList: React.FC<IProps> = ({ manga, isRefreshing }) => {
const queue = (downloaderData?.downloadStatus.queue as DownloadType[]) ?? [];
const [options, dispatch] = useChapterOptions(manga.id);
const { data: chaptersData, loading: isLoading } = requestManager.useGetMangaChapters(manga.id);
const {
data: chaptersData,
loading: isLoading,
error,
refetch,
} = requestManager.useGetMangaChapters(manga.id, { notifyOnNetworkStatusChange: true });
const chapters = useMemo(() => chaptersData?.chapters.nodes ?? [], [chaptersData?.chapters.nodes]);
const chapterIds = useMemo(() => chapters.map((chapter) => chapter.id), [chapters]);
@@ -134,15 +140,21 @@ export const ChapterList: React.FC<IProps> = ({ manga, isRefreshing }) => {
if (isLoading || (noChaptersFound && isRefreshing)) {
return (
<div
style={{
margin: '10px auto',
display: 'flex',
justifyContent: 'center',
}}
>
<CircularProgress thickness={5} />
</div>
<Stack sx={{ justifyContent: 'center', alignItems: 'center', position: 'relative', flexGrow: 1 }}>
<LoadingPlaceholder />
</Stack>
);
}
if (error) {
return (
<Stack sx={{ justifyContent: 'center', position: 'relative', flexGrow: 1 }}>
<EmptyView
message={t('global.error.label.failed_to_load_data')}
messageExtra={error.message}
retry={() => refetch().catch(defaultPromiseErrorHandler('ChapterList::refetch'))}
/>
</Stack>
);
}

View File

@@ -20,6 +20,8 @@ import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarC
import { ActiveDevice, DEFAULT_DEVICE } from '@/util/device.ts';
import { Select } from '@/components/atoms/Select.tsx';
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
import { EmptyView } from '@/components/util/EmptyView.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
export const DeviceSetting = () => {
const { t } = useTranslation();
@@ -41,6 +43,7 @@ export const DeviceSetting = () => {
metadata,
settings: { devices },
loading,
request: { error, refetch },
} = useMetadataServerSettings();
const { activeDevice, setActiveDevice } = useContext(ActiveDevice);
@@ -67,6 +70,16 @@ export const DeviceSetting = () => {
return <LoadingPlaceholder />;
}
if (error) {
return (
<EmptyView
message={t('global.error.label.failed_to_load_data')}
messageExtra={error.message}
retry={() => refetch().catch(defaultPromiseErrorHandler('DeviceSetting::refetch'))}
/>
);
}
return (
<List>
<MutableListSetting

View File

@@ -11,8 +11,10 @@
import { useMemo } from 'react';
import Typography from '@mui/material/Typography';
import { useTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useTranslation } from 'react-i18next';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
const ERROR_FACES = ['(・o・;)', 'Σ(ಠ_ಠ)', 'ಥ_ಥ', '(˘・_・˘)', '(; ̄Д ̄)', '(・Д・。'];
@@ -24,30 +26,34 @@ function getRandomErrorFace() {
interface IProps {
message: string;
messageExtra?: JSX.Element | string;
retry?: () => void;
}
export function EmptyView({ message, messageExtra }: IProps) {
export function EmptyView({ message, messageExtra, retry }: IProps) {
const { t } = useTranslation();
const theme = useTheme();
const isMobileWidth = useMediaQuery(theme.breakpoints.down('sm'));
const errorFace = useMemo(() => getRandomErrorFace(), []);
return (
<Box
<Stack
sx={{
position: 'absolute',
left: `calc(50% + ${isMobileWidth ? '0px' : theme.spacing(8 / 2)})`,
top: '50%',
transform: 'translate(-50%, -50%)',
textAlign: 'center',
alignItems: 'center',
}}
>
<Typography variant="h3" gutterBottom>
{errorFace}
</Typography>
{retry && <Button onClick={retry}>{t('global.button.retry')}</Button>}
<Typography variant="h5">{message}</Typography>
{messageExtra}
</Box>
</Stack>
);
}