Reduce requested manga data in queries
This commit is contained in:
@@ -19,8 +19,14 @@ import SyncAltIcon from '@mui/icons-material/SyncAlt';
|
||||
import { Link } from 'react-router-dom';
|
||||
import SyncIcon from '@mui/icons-material/Sync';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import { TManga } from '@/typings.ts';
|
||||
import { actionToTranslationKey, MangaAction, MangaDownloadInfo, Mangas, MangaUnreadInfo } from '@/lib/data/Mangas.ts';
|
||||
import {
|
||||
actionToTranslationKey,
|
||||
MangaAction,
|
||||
MangaDownloadInfo,
|
||||
MangaIdInfo,
|
||||
Mangas,
|
||||
MangaUnreadInfo,
|
||||
} from '@/lib/data/Mangas.ts';
|
||||
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
||||
import { MenuItem } from '@/components/menu/MenuItem.tsx';
|
||||
import { createGetMenuItemTitle, createIsMenuItemDisabled, createShouldShowMenuItem } from '@/components/menu/util.ts';
|
||||
@@ -29,18 +35,19 @@ import { TrackManga } from '@/components/tracker/TrackManga.tsx';
|
||||
import { useCategorySelect } from '@/components/navbar/action/useCategorySelect.tsx';
|
||||
import { ChaptersDownloadActionMenuItems } from '@/components/chapter/ChaptersDownloadActionMenuItems.tsx';
|
||||
import { NestedMenuItem } from '@/components/menu/NestedMenuItem.tsx';
|
||||
import { MangaChapterStatFieldsFragment, MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
|
||||
const ACTION_DISABLES_SELECTION_MODE: MangaAction[] = ['remove_from_library'] as const;
|
||||
|
||||
type BaseProps = { onClose: (selectionModeState: boolean) => void; setHideMenu: (hide: boolean) => void };
|
||||
|
||||
export type SingleModeProps = {
|
||||
manga: Pick<TManga, 'id' | 'title' | 'source' | 'trackRecords'> & MangaDownloadInfo & MangaUnreadInfo;
|
||||
handleSelection?: SelectableCollectionReturnType<TManga['id']>['handleSelection'];
|
||||
manga: Pick<MangaType, 'id' | 'title' | 'sourceId'> & MangaDownloadInfo & MangaUnreadInfo;
|
||||
handleSelection?: SelectableCollectionReturnType<MangaType['id']>['handleSelection'];
|
||||
};
|
||||
|
||||
type SelectModeProps = {
|
||||
selectedMangas: TManga[];
|
||||
selectedMangas: MangaChapterStatFieldsFragment[];
|
||||
};
|
||||
|
||||
type Props =
|
||||
@@ -82,7 +89,7 @@ export const MangaActionMenuItems = ({
|
||||
onClose(true);
|
||||
};
|
||||
|
||||
const performAction = (action: MangaAction, mangas: TManga[]) => {
|
||||
const performAction = (action: MangaAction, mangas: MangaIdInfo[]) => {
|
||||
Mangas.performAction(action, manga ? [manga.id] : Mangas.getIds(mangas), {
|
||||
wasManuallyMarkedAsRead: true,
|
||||
}).catch(defaultPromiseErrorHandler(`MangaActionMenuItems:performAction(${action})`));
|
||||
@@ -150,7 +157,7 @@ export const MangaActionMenuItems = ({
|
||||
)}
|
||||
{isSingleMode && (
|
||||
<Link
|
||||
to={`/migrate/source/${manga?.source?.id}/manga/${manga?.id}/search?query=${manga?.title}`}
|
||||
to={`/migrate/source/${manga?.sourceId}/manga/${manga?.id}/search?query=${manga?.title}`}
|
||||
state={{ mangaTitle: manga?.title }}
|
||||
style={{ textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
|
||||
@@ -8,24 +8,37 @@
|
||||
|
||||
import { LongPressPointerHandlers, LongPressResult } from 'use-long-press/lib/use-long-press.types';
|
||||
import { PopupState } from 'material-ui-popup-state/hooks';
|
||||
import { TManga, TPartialManga } from '@/typings.ts';
|
||||
import { GridLayout } from '@/components/context/LibraryOptionsContext.tsx';
|
||||
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
||||
import { useManageMangaLibraryState } from '@/components/manga/useManageMangaLibraryState.tsx';
|
||||
import { MangaChapterCountInfo, MangaThumbnailInfo } from '@/lib/data/Mangas.ts';
|
||||
import { ChapterType, MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { SingleModeProps } from '@/components/manga/MangaActionMenuItems.tsx';
|
||||
|
||||
export type MangaCardMode = 'default' | 'source' | 'migrate.search' | 'migrate.select' | 'duplicate';
|
||||
|
||||
type MangaCardBaseProps = Pick<MangaType, 'id' | 'title' | 'sourceId'> &
|
||||
SingleModeProps['manga'] &
|
||||
Partial<Pick<MangaType, 'inLibrary' | 'downloadCount' | 'unreadCount'>> &
|
||||
MangaChapterCountInfo & {
|
||||
latestReadChapter?: Pick<ChapterType, 'id' | 'sourceOrder'> | null;
|
||||
firstUnreadChapter?: Pick<ChapterType, 'id' | 'sourceOrder'> | null;
|
||||
};
|
||||
|
||||
type MangaCardSpecificProps = MangaCardBaseProps & MangaThumbnailInfo;
|
||||
|
||||
export interface MangaCardProps {
|
||||
manga: TPartialManga;
|
||||
manga: MangaCardBaseProps;
|
||||
gridLayout?: GridLayout;
|
||||
inLibraryIndicator?: boolean;
|
||||
selected?: boolean | null;
|
||||
handleSelection?: SelectableCollectionReturnType<TManga['id']>['handleSelection'];
|
||||
handleSelection?: SelectableCollectionReturnType<MangaType['id']>['handleSelection'];
|
||||
mode?: MangaCardMode;
|
||||
}
|
||||
|
||||
export type SpecificMangaCardProps = MangaCardProps &
|
||||
export type SpecificMangaCardProps = Omit<MangaCardProps, 'manga'> &
|
||||
Pick<ReturnType<typeof useManageMangaLibraryState>, 'isInLibrary'> & {
|
||||
manga: MangaCardSpecificProps;
|
||||
longPressBind: LongPressResult<LongPressPointerHandlers>;
|
||||
popupState: PopupState;
|
||||
handleClick: (event: React.MouseEvent | React.TouchEvent) => void;
|
||||
|
||||
@@ -10,22 +10,21 @@ import FavoriteIcon from '@mui/icons-material/Favorite';
|
||||
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
|
||||
import PublicIcon from '@mui/icons-material/Public';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import React, { ComponentProps, useEffect, useMemo } from 'react';
|
||||
import { ComponentProps, useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { t as translate } from 'i18next';
|
||||
import Link from '@mui/material/Link';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { useLongPress } from 'use-long-press';
|
||||
import { TManga } from '@/typings';
|
||||
import { makeToast } from '@/components/util/Toast';
|
||||
import { Mangas } from '@/lib/data/Mangas.ts';
|
||||
import { Mangas, MangaThumbnailInfo, MangaTrackRecordInfo } from '@/lib/data/Mangas.ts';
|
||||
import { SpinnerImage } from '@/components/util/SpinnerImage.tsx';
|
||||
import { CustomIconButton } from '@/components/atoms/CustomIconButton';
|
||||
import { TrackMangaButton } from '@/components/manga/TrackMangaButton.tsx';
|
||||
import { useManageMangaLibraryState } from '@/components/manga/useManageMangaLibraryState.tsx';
|
||||
import { Metadata as BaseMetadata } from '@/components/atoms/Metadata.tsx';
|
||||
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||
import { SourceType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { MangaType, SourceType } from '@/lib/graphql/generated/graphql.ts';
|
||||
|
||||
const DetailsWrapper = styled('div')(({ theme }) => ({
|
||||
width: '100%',
|
||||
@@ -156,10 +155,6 @@ const OpenSourceButton = ({ url }: { url?: string | null }) => {
|
||||
return button;
|
||||
};
|
||||
|
||||
interface IProps {
|
||||
manga: TManga;
|
||||
}
|
||||
|
||||
function getSourceName(source?: Pick<SourceType, 'id' | 'displayName'> | null): string {
|
||||
if (!source) {
|
||||
return translate('global.label.unknown');
|
||||
@@ -172,7 +167,18 @@ function getValueOrUnknown(val?: string | null) {
|
||||
return val ?? translate('global.label.unknown');
|
||||
}
|
||||
|
||||
export const MangaDetails: React.FC<IProps> = ({ manga }) => {
|
||||
export const MangaDetails = ({
|
||||
manga,
|
||||
}: {
|
||||
manga: Pick<
|
||||
MangaType,
|
||||
'id' | 'title' | 'author' | 'artist' | 'status' | 'inLibrary' | 'realUrl' | 'description' | 'genre'
|
||||
> &
|
||||
MangaThumbnailInfo &
|
||||
MangaTrackRecordInfo & {
|
||||
source?: Pick<SourceType, 'id' | 'displayName'> | null;
|
||||
};
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -16,8 +16,8 @@ import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||
import { PopupState } from 'material-ui-popup-state/hooks';
|
||||
import { bindTrigger } from 'material-ui-popup-state';
|
||||
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
||||
import { TManga } from '@/typings.ts';
|
||||
import { MediaQuery } from '@/lib/ui/MediaQuery.tsx';
|
||||
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
|
||||
export const MangaOptionButton = forwardRef(
|
||||
(
|
||||
@@ -30,7 +30,7 @@ export const MangaOptionButton = forwardRef(
|
||||
}: {
|
||||
id: number;
|
||||
selected?: boolean | null;
|
||||
handleSelection?: SelectableCollectionReturnType<TManga['id']>['handleSelection'];
|
||||
handleSelection?: SelectableCollectionReturnType<MangaType['id']>['handleSelection'];
|
||||
asCheckbox?: boolean;
|
||||
popupState: PopupState;
|
||||
},
|
||||
|
||||
@@ -21,11 +21,11 @@ import { Link } from 'react-router-dom';
|
||||
import SyncAltIcon from '@mui/icons-material/SyncAlt';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import { TManga } from '@/typings.ts';
|
||||
import { useCategorySelect } from '@/components/navbar/action/useCategorySelect.tsx';
|
||||
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
|
||||
interface IProps {
|
||||
manga: TManga;
|
||||
manga: Pick<MangaType, 'id' | 'inLibrary' | 'sourceId' | 'title'>;
|
||||
onRefresh: () => any;
|
||||
refreshing: boolean;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => {
|
||||
<>
|
||||
<Tooltip title={t('global.button.migrate')}>
|
||||
<Link
|
||||
to={`/migrate/source/${manga.source?.id}/manga/${manga.id}/search?query=${manga.title}`}
|
||||
to={`/migrate/source/${manga.sourceId}/manga/${manga.id}/search?query=${manga.title}`}
|
||||
state={{ mangaTitle: manga.title }}
|
||||
style={{ textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
@@ -122,7 +122,7 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => {
|
||||
<MenuItem
|
||||
key="migrate"
|
||||
component={Link}
|
||||
to={`/migrate/source/${manga.source?.id}/manga/${manga.id}/search?query=${manga.title}`}
|
||||
to={`/migrate/source/${manga.sourceId}/manga/${manga.id}/search?query=${manga.title}`}
|
||||
state={{ mangaTitle: manga.title }}
|
||||
style={{ textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
|
||||
@@ -16,20 +16,21 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { makeToast } from '@/components/util/Toast.tsx';
|
||||
import { TrackManga } from '@/components/tracker/TrackManga.tsx';
|
||||
import { Trackers } from '@/lib/data/Trackers.ts';
|
||||
import { TManga } from '@/typings.ts';
|
||||
import { CustomIconButton } from '@/components/atoms/CustomIconButton.tsx';
|
||||
import { GetTrackersSettingsQuery } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { GetTrackersSettingsQuery, MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { GET_TRACKERS_SETTINGS } from '@/lib/graphql/queries/TrackerQuery.ts';
|
||||
import { MangaTrackRecordInfo } from '@/lib/data/Mangas.ts';
|
||||
|
||||
export const TrackMangaButton = ({ manga }: { manga: TManga }) => {
|
||||
export const TrackMangaButton = ({ manga }: { manga: MangaTrackRecordInfo & Pick<MangaType, 'title'> }) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const trackerList = requestManager.useGetTrackerList<GetTrackersSettingsQuery>(GET_TRACKERS_SETTINGS);
|
||||
const trackers = trackerList.data?.trackers.nodes ?? [];
|
||||
const mangaTrackers = manga.trackRecords.nodes;
|
||||
|
||||
const loggedInTrackers = Trackers.getLoggedIn(trackerList.data?.trackers.nodes ?? []);
|
||||
const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackers));
|
||||
const loggedInTrackers = Trackers.getLoggedIn(trackers);
|
||||
const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackers, trackers));
|
||||
|
||||
const handleClick = (openPopup: () => void) => {
|
||||
if (trackerList.error) {
|
||||
|
||||
@@ -16,19 +16,18 @@ import { getMetadataServerSettings } from '@/lib/metadata/metadataServerSettings
|
||||
import { Categories } from '@/lib/data/Categories.ts';
|
||||
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||
import { Mangas } from '@/lib/data/Mangas.ts';
|
||||
import { TManga } from '@/typings.ts';
|
||||
import { awaitConfirmation } from '@/lib/ui/AwaitableDialog.tsx';
|
||||
import { GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables, MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts';
|
||||
|
||||
export const useManageMangaLibraryState = (
|
||||
manga: Pick<TManga, 'id' | 'title' | 'inLibrary'>,
|
||||
manga: Pick<MangaType, 'id' | 'title'> & Partial<Pick<MangaType, 'inLibrary'>>,
|
||||
confirmRemoval: boolean = false,
|
||||
) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [isInLibrary, setIsInLibrary] = useState(manga.inLibrary);
|
||||
const [isInLibrary, setIsInLibrary] = useState(!!manga.inLibrary);
|
||||
|
||||
const addToLibrary = useCallback(
|
||||
(didSubmit: boolean, addToCategories: number[] = [], removeFromCategories: number[] = []) => {
|
||||
@@ -162,6 +161,6 @@ export const useManageMangaLibraryState = (
|
||||
*
|
||||
* To work around this issue, the currently known in library state gets returned here
|
||||
*/
|
||||
isInLibrary: Mangas.getFromCache<TManga>(manga.id)?.inLibrary ?? isInLibrary,
|
||||
isInLibrary: Mangas.getFromCache(manga.id)?.inLibrary ?? isInLibrary,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user