[Codegen] Use gql for "loading chapters"
This commit is contained in:
@@ -11,7 +11,7 @@ import Typography from '@mui/material/Typography';
|
||||
import React, { ComponentProps, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IChapter, IDownloadChapter, IQueue, TranslationKey } from '@/typings';
|
||||
import { IDownloadChapter, IQueue, TranslationKey } from '@/typings';
|
||||
import requestManager from '@/lib/requests/RequestManager.ts';
|
||||
import useSubscription from '@/components/library/useSubscription';
|
||||
import ChapterCard from '@/components/manga/ChapterCard';
|
||||
@@ -22,7 +22,7 @@ import makeToast from '@/components/util/Toast';
|
||||
import ChaptersToolbarMenu from '@/components/manga/ChaptersToolbarMenu';
|
||||
import SelectionFAB from '@/components/manga/SelectionFAB';
|
||||
import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab';
|
||||
import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { ChapterType, MangaType, UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts';
|
||||
|
||||
const StyledVirtuoso = styled(Virtuoso)(({ theme }) => ({
|
||||
listStyle: 'none',
|
||||
@@ -69,25 +69,29 @@ const actionsStrings: {
|
||||
};
|
||||
|
||||
export interface IChapterWithMeta {
|
||||
chapter: IChapter;
|
||||
chapter: ChapterType;
|
||||
downloadChapter: IDownloadChapter | undefined;
|
||||
selected: boolean | null;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
mangaId: string;
|
||||
manga: MangaType;
|
||||
isRefreshing: boolean;
|
||||
}
|
||||
|
||||
const ChapterList: React.FC<IProps> = ({ mangaId }) => {
|
||||
const ChapterList: React.FC<IProps> = ({ manga, isRefreshing }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [selection, setSelection] = useState<number[] | null>(null);
|
||||
const prevQueueRef = useRef<IDownloadChapter[]>();
|
||||
const queue = useSubscription<IQueue>('downloads').data?.queue;
|
||||
|
||||
const [options, dispatch] = useChapterOptions(mangaId);
|
||||
const { data: chaptersData, mutate, isLoading } = requestManager.useGetMangaChapters(mangaId);
|
||||
const chapters = useMemo(() => chaptersData ?? [], [chaptersData]);
|
||||
const [options, dispatch] = useChapterOptions(manga.id);
|
||||
const { data: chaptersData, loading: isLoading, refetch } = requestManager.useGetMangaChapters(manga.id);
|
||||
const chapters = useMemo(
|
||||
() => (chaptersData?.chapters.nodes as ChapterType[]) ?? [],
|
||||
[chaptersData?.chapters.nodes],
|
||||
);
|
||||
const mangaChapterIds = useMemo(() => chapters.map((chapter) => chapter.id), [chapters]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -102,26 +106,17 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
|
||||
});
|
||||
|
||||
if (changedDownloads.length > 0) {
|
||||
mutate();
|
||||
refetch();
|
||||
}
|
||||
}
|
||||
|
||||
prevQueueRef.current = queue;
|
||||
}, [queue]);
|
||||
|
||||
const visibleChapters = useMemo(
|
||||
() => filterAndSortChapters(chapters, options), //
|
||||
[chapters, options],
|
||||
);
|
||||
const visibleChapters = useMemo(() => filterAndSortChapters(chapters, options), [chapters, options]);
|
||||
|
||||
const firstUnreadChapter = useMemo(
|
||||
() =>
|
||||
chapters
|
||||
.slice()
|
||||
.reverse()
|
||||
.find((chapter) => !chapter.read),
|
||||
[chapters],
|
||||
);
|
||||
const nextChapterIndexToRead = (manga.lastReadChapter?.sourceOrder ?? 0) + 1;
|
||||
const isLatestChapterRead = manga.chapters.totalCount === manga.lastReadChapter?.sourceOrder;
|
||||
|
||||
const handleSelection = (index: number) => {
|
||||
const chapter = visibleChapters[index];
|
||||
@@ -174,11 +169,49 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
|
||||
|
||||
actionPromise
|
||||
.then(() => makeToast(t(actionsStrings[action].success, { count: chapterIds.length }), 'success'))
|
||||
.then(() => mutate())
|
||||
.catch(() => makeToast(t(actionsStrings[action].error, { count: chapterIds.length }), 'error'));
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
const noChaptersFound = chapters.length === 0;
|
||||
const noChaptersMatchingFilter = !noChaptersFound && visibleChapters.length === 0;
|
||||
|
||||
const chaptersWithMeta: IChapterWithMeta[] = useMemo(
|
||||
() =>
|
||||
visibleChapters.map((chapter) => {
|
||||
const downloadChapter = queue?.find(
|
||||
(cd) => cd.chapterIndex === chapter.sourceOrder && cd.mangaId === chapter.manga.id,
|
||||
);
|
||||
const selected = selection?.includes(chapter.id) ?? null;
|
||||
return {
|
||||
chapter,
|
||||
downloadChapter,
|
||||
selected,
|
||||
};
|
||||
}),
|
||||
[queue, selection, visibleChapters],
|
||||
);
|
||||
|
||||
const selectedChapters = useMemo(() => {
|
||||
if (!selection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return chaptersWithMeta.filter(({ chapter }) => selection.includes(chapter.id));
|
||||
}, [selection, chapters]);
|
||||
|
||||
const chapterListFAB = useMemo(() => {
|
||||
if (selectedChapters) {
|
||||
return <SelectionFAB selectedChapters={selectedChapters} onAction={handleFabAction} />;
|
||||
}
|
||||
|
||||
if (!isLatestChapterRead) {
|
||||
return <ResumeFab chapterIndex={nextChapterIndexToRead} mangaId={manga.id} />;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [selectedChapters, isLatestChapterRead]);
|
||||
|
||||
if (isLoading || (noChaptersFound && isRefreshing)) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -192,24 +225,6 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
|
||||
);
|
||||
}
|
||||
|
||||
const noChaptersFound = chapters.length === 0;
|
||||
const noChaptersMatchingFilter = !noChaptersFound && visibleChapters.length === 0;
|
||||
|
||||
const chaptersWithMeta: IChapterWithMeta[] = visibleChapters.map((chapter) => {
|
||||
const downloadChapter = queue?.find(
|
||||
(cd) => cd.chapterIndex === chapter.index && cd.mangaId === chapter.mangaId,
|
||||
);
|
||||
const selected = selection?.includes(chapter.id) ?? null;
|
||||
return {
|
||||
chapter,
|
||||
downloadChapter,
|
||||
selected,
|
||||
};
|
||||
});
|
||||
|
||||
const selectedChapters =
|
||||
selection === null ? null : chaptersWithMeta.filter(({ chapter }) => selection.includes(chapter.id));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack direction="column" sx={{ position: 'relative' }}>
|
||||
@@ -273,7 +288,6 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
|
||||
{...chaptersWithMeta[index]}
|
||||
chapterIds={mangaChapterIds}
|
||||
showChapterNumber={options.showChapterNumber}
|
||||
triggerChaptersUpdate={() => mutate()}
|
||||
onSelect={() => handleSelection(index)}
|
||||
/>
|
||||
);
|
||||
@@ -282,11 +296,7 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
|
||||
overscan={window.innerHeight * 0.5}
|
||||
/>
|
||||
</Stack>
|
||||
{selectedChapters !== null ? (
|
||||
<SelectionFAB selectedChapters={selectedChapters} onAction={handleFabAction} />
|
||||
) : (
|
||||
firstUnreadChapter && <ResumeFab chapter={firstUnreadChapter} mangaId={mangaId} />
|
||||
)}
|
||||
{chapterListFAB}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user