Use gql for "mangas" I - get manga

This commit is contained in:
schroda
2023-09-08 00:44:01 +02:00
parent a5b4b95bce
commit 89dc053f00
14 changed files with 170 additions and 126 deletions

View File

@@ -11,6 +11,7 @@ import { CircularProgress, IconButton, Stack, Tooltip, Box } from '@mui/material
import React, { useContext, useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import { isNetworkRequestInFlight } from '@apollo/client/core/networkStatus';
import requestManager from '@/lib/requests/RequestManager.ts';
import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext';
import ChapterList from '@/components/manga/ChapterList';
@@ -19,8 +20,9 @@ import MangaDetails from '@/components/manga/MangaDetails';
import MangaToolbarMenu from '@/components/manga/MangaToolbarMenu';
import EmptyView from '@/components/util/EmptyView';
import LoadingPlaceholder from '@/components/util/LoadingPlaceholder';
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
const AUTOFETCH_AGE = 60 * 60 * 24; // 24 hours
const AUTOFETCH_AGE = 1000 * 60 * 60 * 24; // 24 hours
const Manga: React.FC = () => {
const { t } = useTranslation();
@@ -29,21 +31,26 @@ const Manga: React.FC = () => {
const { id } = useParams<{ id: string }>();
const autofetchedRef = useRef(false);
const { data: manga, error, isLoading, isValidating, mutate } = requestManager.useGetManga(id);
const { data, error, loading: isLoading, networkStatus, refetch } = requestManager.useGetManga(id);
const isValidating = isNetworkRequestInFlight(networkStatus);
const manga = data?.manga as MangaType | undefined;
const [refresh, { loading: refreshing }] = useRefreshManga(id);
useSetDefaultBackTo('library');
useEffect(() => {
// Automatically fetch manga from source if data is older then 24 hours
// Automatically fetch manga from source if data is older then 24 hours OR manga is not initialized yet
// Automatic fetch is done only once, to prevent issues when server does
// not update age for some reason (ie. error on source side)
if (manga == null) return;
if (
manga.inLibrary &&
(manga.age > AUTOFETCH_AGE || manga.chaptersAge > AUTOFETCH_AGE) &&
autofetchedRef.current === false
) {
const isOutdated =
Date.now() - Number(manga.lastFetchedAt) * 1000 > AUTOFETCH_AGE ||
Date.now() - Number(manga.chaptersLastFetchedAt) * 1000 > AUTOFETCH_AGE;
const refetchBecauseOutdated = manga.inLibrary && isOutdated;
const doFetch = !autofetchedRef.current && (refetchBecauseOutdated || !manga.initialized);
if (doFetch) {
autofetchedRef.current = true;
refresh();
}
@@ -67,7 +74,7 @@ const Manga: React.FC = () => {
</>
}
>
<IconButton onClick={() => mutate()}>
<IconButton onClick={() => refetch()}>
<Warning color="error" />
</IconButton>
</Tooltip>
@@ -80,7 +87,7 @@ const Manga: React.FC = () => {
{manga && <MangaToolbarMenu manga={manga} onRefresh={refresh} refreshing={refreshing} />}
</Stack>,
);
}, [t, error, isValidating, refreshing, mutate, manga, refresh]);
}, [t, error, isValidating, refreshing, manga, refresh]);
if (error && !manga) {
return <EmptyView message={t('manga.error.label.request_failure')} messageExtra={error.message ?? error} />;

View File

@@ -7,11 +7,11 @@
*/
import CircularProgress from '@mui/material/CircularProgress';
import { useCallback, useContext, useEffect, useState } from 'react';
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { Box } from '@mui/material';
import { useTranslation } from 'react-i18next';
import { ChapterOffset, IChapter, IManga, IMangaCard, IReaderSettings, ReaderType, TranslationKey } from '@/typings';
import { ChapterOffset, IChapter, IReaderSettings, ReaderType, TranslationKey } from '@/typings';
import requestManager from '@/lib/requests/RequestManager.ts';
import {
checkAndHandleMissingStoredReaderSettings,
@@ -27,6 +27,7 @@ import VerticalPager from '@/components/reader/pager/VerticalPager';
import ReaderNavBar from '@/components/navbar/ReaderNavBar';
import NavbarContext from '@/components/context/NavbarContext';
import makeToast from '@/components/util/Toast';
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
const isDupChapter = async (chapterIndex: number, currentChapter: IChapter) => {
const nextChapter = await requestManager.getChapter(currentChapter.mangaId, chapterIndex).response;
@@ -93,17 +94,22 @@ export default function Reader() {
const location = useLocation();
const { chapterIndex, mangaId } = useParams<{ chapterIndex: string; mangaId: string }>();
const {
data: manga = {
id: +mangaId,
title: '',
thumbnailUrl: '',
genre: [],
inLibraryAt: 0,
lastReadAt: 0,
} as IMangaCard | IManga,
isLoading: isMangaLoading,
} = requestManager.useGetManga(mangaId);
const initialManga = useMemo(
() =>
({
id: +mangaId,
title: '',
thumbnailUrl: '',
genre: [],
inLibraryAt: 0,
lastReadAt: 0,
}) as unknown as MangaType,
[mangaId],
);
const { data, loading: isMangaLoading } = requestManager.useGetManga(mangaId);
const manga = (data?.manga as MangaType) ?? initialManga;
const { data: chapter = initialChapter, isLoading: isChapterLoading } = requestManager.useGetChapter(
mangaId,
chapterIndex,

View File

@@ -11,7 +11,7 @@ import { Box } from '@mui/material';
import CircularProgress from '@mui/material/CircularProgress';
import { useTranslation } from 'react-i18next';
import { IReaderSettings } from '@/typings';
import { requestUpdateServerMetadata } from '@/util/metadata';
import { convertToGqlMeta, requestUpdateServerMetadata } from '@/util/metadata';
import {
checkAndHandleMissingStoredReaderSettings,
getDefaultSettings,
@@ -34,7 +34,7 @@ export default function DefaultReaderSettings() {
useSetDefaultBackTo('settings');
const setSettingValue = (key: keyof IReaderSettings, value: string | boolean) => {
requestUpdateServerMetadata(metadata ?? {}, [[key, value]]).catch(() =>
requestUpdateServerMetadata(convertToGqlMeta(metadata)! ?? {}, [[key, value]]).catch(() =>
makeToast(t('reader.settings.error.label.failed_to_save_settings'), 'warning'),
);
};
@@ -54,7 +54,11 @@ export default function DefaultReaderSettings() {
);
}
checkAndHandleMissingStoredReaderSettings({ meta: metadata }, 'server', getDefaultSettings()).catch(() => {});
checkAndHandleMissingStoredReaderSettings(
{ meta: convertToGqlMeta(metadata)! },
'server',
getDefaultSettings(),
).catch(() => {});
return (
<ReaderSettingsOptions

View File

@@ -12,7 +12,7 @@ import ListItemIcon from '@mui/material/ListItemIcon';
import SearchIcon from '@mui/icons-material/Search';
import { useTranslation } from 'react-i18next';
import { SearchMetadataKeys } from '@/typings';
import { requestUpdateServerMetadata } from '@/util/metadata';
import { convertToGqlMeta, requestUpdateServerMetadata } from '@/util/metadata';
import { useSearchSettings } from '@/util/searchSettings';
import makeToast from '@/components/util/Toast';
import { useSetDefaultBackTo } from '@/components/context/NavbarContext';
@@ -24,7 +24,7 @@ export default function SearchSettings() {
useSetDefaultBackTo('settings');
const setSettingValue = (key: SearchMetadataKeys, value: boolean) => {
requestUpdateServerMetadata(metadata ?? {}, [[key, value]]).catch(() =>
requestUpdateServerMetadata(convertToGqlMeta(metadata)! ?? {}, [[key, value]]).catch(() =>
makeToast(t('search.error.label.failed_to_save_settings'), 'warning'),
);
};