Add missing error handling
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user