diff --git a/src/features/category/components/CategorySelect.tsx b/src/features/category/components/CategorySelect.tsx index 0e113798..a9da321a 100644 --- a/src/features/category/components/CategorySelect.tsx +++ b/src/features/category/components/CategorySelect.tsx @@ -37,8 +37,8 @@ import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; type BaseProps = { - open: boolean; - onClose: (didUpdateCategories: boolean, addToCategories?: number[], removeFromCategories?: number[]) => void; + onCancel: () => void; + onConfirm: (selectedCategories: { addToCategories?: number[]; removeFromCategories?: number[] }) => void; }; type SingleMangaModeProps = { @@ -94,7 +94,7 @@ const getCategoryCheckedState = ( export function CategorySelect(props: CategorySelectProps) { const { t } = useTranslation(); - const { open, onClose, mangaId, mangaIds: passedMangaIds, addToLibrary = false } = props; + const { onCancel, onConfirm, mangaId, mangaIds: passedMangaIds, addToLibrary = false } = props; const isSingleSelectionMode = mangaId !== undefined; const mangaIds = passedMangaIds ?? [mangaId]; @@ -137,7 +137,7 @@ export function CategorySelect(props: CategorySelectProps) { const handleCancel = () => { setSelectionForKey('categoriesToAdd', mangaCategoryIds); setSelectionForKey('categoriesToRemove', []); - onClose(false); + onCancel(); }; const handleOk = () => { @@ -148,7 +148,10 @@ export function CategorySelect(props: CategorySelectProps) { ? mangaCategoryIds.filter((categoryId) => !categoriesToAdd.includes(categoryId)) : categoriesToRemove; - onClose(true, addToCategories, removeFromCategories); + onConfirm({ + addToCategories, + removeFromCategories, + }); if (doNotShowAddToLibraryDialogAgain) { updateMetadataServerSettings('showAddToLibraryCategorySelectDialog', false).catch((e) => @@ -183,7 +186,7 @@ export function CategorySelect(props: CategorySelectProps) { }, }} maxWidth="xs" - open={open} + open onClose={handleCancel} > {t('category.title.set_categories')} diff --git a/src/features/category/hooks/useCategorySelect.tsx b/src/features/category/hooks/useCategorySelect.tsx deleted file mode 100644 index f602786b..00000000 --- a/src/features/category/hooks/useCategorySelect.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) Contributors to the Suwayomi project - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -import { useMemo, useState } from 'react'; -import { CategorySelect, CategorySelectProps } from '@/features/category/components/CategorySelect.tsx'; - -export const useCategorySelect = ({ - mangaId, - mangaIds, - onClose, - addToLibrary, -}: Omit & Pick, 'onClose'>) => { - const [isCategorySelectOpen, setIsCategorySelectOpen] = useState(false); - - const CategorySelectComponent = useMemo(() => { - if (!isCategorySelectOpen) { - return null; - } - - return ( - { - setIsCategorySelectOpen(false); - onClose?.(...args); - }} - mangaId={mangaId!} // either mangaId or mangaIds is undefined, however, ts is not able to infer it correctly and raises an error - mangaIds={mangaIds as undefined} - addToLibrary={addToLibrary} - /> - ); - }, [mangaId, mangaIds, addToLibrary, onClose, isCategorySelectOpen]); - - return { - openCategorySelect: setIsCategorySelectOpen, - CategorySelectComponent, - }; -}; diff --git a/src/features/manga/components/MangaActionMenuItems.tsx b/src/features/manga/components/MangaActionMenuItems.tsx index b5776d9f..f3aa2a5b 100644 --- a/src/features/manga/components/MangaActionMenuItems.tsx +++ b/src/features/manga/components/MangaActionMenuItems.tsx @@ -29,17 +29,16 @@ import { } from '@/base/components/menu/Menu.utils.ts'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { TrackManga } from '@/features/tracker/components/TrackManga.tsx'; -import { useCategorySelect } from '@/features/category/hooks/useCategorySelect.tsx'; import { ChaptersDownloadActionMenuItems } from '@/features/chapter/components/actions/ChaptersDownloadActionMenuItems.tsx'; import { NestedMenuItem } from '@/base/components/menu/NestedMenuItem.tsx'; import { MangaChapterStatFieldsFragment, MangaType } from '@/lib/graphql/generated/graphql.ts'; import { MangaAction, MangaDownloadInfo, MangaIdInfo, MangaUnreadInfo } from '@/features/manga/Manga.types.ts'; import { MANGA_ACTION_TO_TRANSLATION } from '@/features/manga/Manga.constants.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts'; +import { GlobalDialogManager } from '@/base/global-dialog/GlobalDialogManager.tsx'; +import { CategorySelect } from '@/features/category/components/CategorySelect.tsx'; -const ACTION_DISABLES_SELECTION_MODE: MangaAction[] = ['remove_from_library'] as const; - -type BaseProps = { onClose: (selectionModeState: boolean) => void; setHideMenu: (hide: boolean) => void }; +type BaseProps = { onClose: () => void; setHideMenu: (hide: boolean) => void }; export type SingleModeProps = { manga: Pick & MangaDownloadInfo & MangaUnreadInfo; @@ -77,16 +76,9 @@ export const MangaActionMenuItems = ({ const hasUnreadChapters = !!manga?.unreadCount; const hasReadChapters = !!manga && manga.unreadCount !== manga.chapters.totalCount; - const { openCategorySelect, CategorySelectComponent } = useCategorySelect({ - mangaId: manga?.id, - mangaIds: passedSelectedMangas ? Mangas.getIds(selectedMangas) : undefined, - onClose: () => onClose(true), - addToLibrary: false, - }); - const handleSelect = () => { handleSelection?.(manga.id, true); - onClose(true); + onClose(); }; const performAction = (action: MangaAction, mangas: MangaIdInfo[]) => { @@ -94,7 +86,7 @@ export const MangaActionMenuItems = ({ wasManuallyMarkedAsRead: true, }).catch(defaultPromiseErrorHandler(`MangaActionMenuItems:performAction(${action})`)); - onClose(!ACTION_DISABLES_SELECTION_MODE.includes(action)); + onClose(); }; const { downloadableMangas, downloadedMangas, unreadMangas, readMangas } = useMemo( @@ -127,7 +119,7 @@ export const MangaActionMenuItems = ({ > onClose(true)} + closeMenu={onClose} /> )} @@ -176,8 +168,13 @@ export const MangaActionMenuItems = ({ )} { - openCategorySelect(true); + GlobalDialogManager.show(CategorySelect, { + mangaId: manga?.id, + mangaIds: passedSelectedMangas ? Mangas.getIds(selectedMangas) : undefined, + addToLibrary: false, + }); setHideMenu(true); + onClose(); }} Icon={Label} title={getMenuItemTitle('change_categories', selectedMangas.length)} @@ -187,7 +184,6 @@ export const MangaActionMenuItems = ({ Icon={FavoriteBorderIcon} title={getMenuItemTitle('remove_from_library', selectedMangas.length)} /> - {CategorySelectComponent} {isTrackDialogOpen && ( { setIsTrackDialogOpen(false); - onClose(true); + onClose(); }} > diff --git a/src/features/manga/components/MangaToolbarMenu.tsx b/src/features/manga/components/MangaToolbarMenu.tsx index ccd559de..059a3354 100644 --- a/src/features/manga/components/MangaToolbarMenu.tsx +++ b/src/features/manga/components/MangaToolbarMenu.tsx @@ -21,9 +21,10 @@ import SyncAltIcon from '@mui/icons-material/SyncAlt'; import { useTheme } from '@mui/material/styles'; import useMediaQuery from '@mui/material/useMediaQuery'; import { CustomTooltip } from '@/base/components/CustomTooltip.tsx'; -import { useCategorySelect } from '@/features/category/hooks/useCategorySelect.tsx'; import { MangaType } from '@/lib/graphql/generated/graphql.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts'; +import { GlobalDialogManager } from '@/base/global-dialog/GlobalDialogManager.tsx'; +import { CategorySelect } from '@/features/category/components/CategorySelect.tsx'; interface IProps { manga: Pick; @@ -43,9 +44,9 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => { setAnchorEl(null); }; - const { openCategorySelect, CategorySelectComponent } = useCategorySelect({ - mangaId: manga.id, - }); + const openCategorySelection = () => { + GlobalDialogManager.show(CategorySelect, { mangaId: manga.id }); + }; return ( <> @@ -82,7 +83,7 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => { { - openCategorySelect(true); + openCategorySelection(); }} color="inherit" > @@ -142,7 +143,7 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => { { - openCategorySelect(true); + openCategorySelection(); handleClose(); }} > @@ -155,8 +156,6 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => { )} - - {CategorySelectComponent} ); }; diff --git a/src/features/manga/components/cards/MangaCard.tsx b/src/features/manga/components/cards/MangaCard.tsx index 82cfbb83..50b403c8 100644 --- a/src/features/manga/components/cards/MangaCard.tsx +++ b/src/features/manga/components/cards/MangaCard.tsx @@ -49,10 +49,7 @@ export const MangaCard = memo((props: MangaCardProps) => { settings: { showContinueReadingButton }, } = useMetadataServerSettings(); - const { CategorySelectComponent, updateLibraryState, isInLibrary } = useManageMangaLibraryState( - manga, - mode === 'source', - ); + const { updateLibraryState, isInLibrary } = useManageMangaLibraryState(manga, mode === 'source'); const mangaLinkTo = getMangaLinkTo(mode, manga.id, manga.sourceId, manga.title); @@ -158,7 +155,6 @@ export const MangaCard = memo((props: MangaCardProps) => { )} )} - {CategorySelectComponent} )} diff --git a/src/features/manga/components/details/MangaDetails.tsx b/src/features/manga/components/details/MangaDetails.tsx index a8c062ee..8b96c0a2 100644 --- a/src/features/manga/components/details/MangaDetails.tsx +++ b/src/features/manga/components/details/MangaDetails.tsx @@ -227,7 +227,7 @@ export const MangaDetails = ({ } }, [manga.source]); - const { CategorySelectComponent, updateLibraryState } = useManageMangaLibraryState(manga); + const { updateLibraryState } = useManageMangaLibraryState(manga); const copyTitle = async () => { try { @@ -239,59 +239,56 @@ export const MangaDetails = ({ }; return ( - <> - - - - - - - - - {manga.title} - - - - - - - - - {manga.author && ( - - )} - {manga.artist && ( - - )} + + + + + + + + + {manga.title} + + + + + + + + + {manga.author && ( - - - - - - {manga.inLibrary ? : } - {manga.inLibrary ? t('manga.button.in_library') : t('manga.button.add_to_library')} - - - - - - - - {CategorySelectComponent} - + )} + {manga.artist && ( + + )} + + + + + + + {manga.inLibrary ? : } + {manga.inLibrary ? t('manga.button.in_library') : t('manga.button.add_to_library')} + + + + + + + ); }; diff --git a/src/features/manga/hooks/useManageMangaLibraryState.tsx b/src/features/manga/hooks/useManageMangaLibraryState.tsx index 29e26de5..33c7b7be 100644 --- a/src/features/manga/hooks/useManageMangaLibraryState.tsx +++ b/src/features/manga/hooks/useManageMangaLibraryState.tsx @@ -10,7 +10,6 @@ import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import gql from 'graphql-tag'; -import { useCategorySelect } from '@/features/category/hooks/useCategorySelect.tsx'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { makeToast } from '@/base/utils/Toast.ts'; import { getMetadataServerSettings } from '@/features/settings/services/ServerSettingsMetadata.ts'; @@ -22,6 +21,7 @@ import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { GlobalDialogManager } from '@/base/global-dialog/GlobalDialogManager.tsx'; +import { CategorySelect } from '@/features/category/components/CategorySelect'; export const useManageMangaLibraryState = ( manga: Pick & Partial>, @@ -33,11 +33,7 @@ export const useManageMangaLibraryState = ( const [isInLibrary, setIsInLibrary] = useState(!!manga.inLibrary); const addToLibrary = useCallback( - (didSubmit: boolean, addToCategories: number[] = [], removeFromCategories: number[] = []) => { - if (!didSubmit) { - return; - } - + (addToCategories: number[] = [], removeFromCategories: number[] = []) => { requestManager .updateManga(manga.id, { updateManga: { inLibrary: true }, @@ -67,12 +63,6 @@ export const useManageMangaLibraryState = ( setIsInLibrary(false); }, [manga.id, confirmRemoval]); - const { openCategorySelect, CategorySelectComponent } = useCategorySelect({ - mangaId: manga.id, - addToLibrary: true, - onClose: addToLibrary, - }); - const updateLibraryState = useCallback(() => { const update = async () => { if (isInLibrary) { @@ -144,18 +134,26 @@ export const useManageMangaLibraryState = ( const showCategorySelectDialog = showAddToLibraryCategorySelectDialog && !!userCreatedCategories.length; if (!showCategorySelectDialog) { - addToLibrary(true, Categories.getIds(Categories.getDefaults(userCreatedCategories!))); + addToLibrary(Categories.getIds(Categories.getDefaults(userCreatedCategories!))); return; } - openCategorySelect(true); + const { addToCategories, removeFromCategories } = await GlobalDialogManager.show( + `manga-library-state-add-categories-${manga.id}`, + CategorySelect, + { + mangaId: manga.id, + addToLibrary: true, + }, + ); + + addToLibrary(addToCategories, removeFromCategories); }; update().catch(defaultPromiseErrorHandler('useManageMangaLibraryState::updateLibraryState')); }, [isInLibrary, removeFromLibrary, addToLibrary]); return { - CategorySelectComponent, updateLibraryState, /** * In case of browsing the source, the data has to be fetched via a mutation. diff --git a/src/features/reader/overlay/navigation/components/ReaderLibraryButton.tsx b/src/features/reader/overlay/navigation/components/ReaderLibraryButton.tsx index da5f0a70..185a104a 100644 --- a/src/features/reader/overlay/navigation/components/ReaderLibraryButton.tsx +++ b/src/features/reader/overlay/navigation/components/ReaderLibraryButton.tsx @@ -28,22 +28,15 @@ export const ReaderLibraryButton = memo(() => { const { inLibrary } = manga ?? ACTION_FALLBACK_MANGA; const { t } = useTranslation(); - const { CategorySelectComponent, updateLibraryState } = useManageMangaLibraryState( - manga ?? ACTION_FALLBACK_MANGA, - true, - ); + const { updateLibraryState } = useManageMangaLibraryState(manga ?? ACTION_FALLBACK_MANGA, true); return ( - <> - - - {inLibrary ? : } - - - - {CategorySelectComponent} - + + + {inLibrary ? : } + + ); });