/* * 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 { useContext, useEffect, useLayoutEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { NavBarContext } from '@/components/context/NavbarContext.tsx'; import { requestManager } from '@/lib/requests/requests/RequestManager.ts'; import { TMigratableSource } from '@/components/MigrationCard.tsx'; import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx'; import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx'; import { GridLayouts } from '@/components/source/GridLayouts.tsx'; import { useLocalStorage } from '@/modules/core/hooks/useStorage.tsx'; import { GridLayout } from '@/modules/library/contexts/LibraryOptionsContext.tsx'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { GetSourceMigratableQuery, GetSourceMigratableQueryVariables } from '@/lib/graphql/generated/graphql.ts'; import { GET_SOURCE_MIGRATABLE } from '@/lib/graphql/queries/SourceQuery.ts'; import { SOURCE_BASE_FIELDS } from '@/lib/graphql/fragments/SourceFragments.ts'; import { BaseMangaGrid } from '@/components/source/BaseMangaGrid.tsx'; export const Migrate = () => { const { t } = useTranslation(); const { setTitle, setAction } = useContext(NavBarContext); const { sourceId: paramSourceId } = useParams<{ sourceId: string }>(); const [gridLayout, setGridLayout] = useLocalStorage('migrateGridLayout', GridLayout.List); const fragmentSource = requestManager.graphQLClient.client.cache.readFragment< Pick >({ id: requestManager.graphQLClient.client.cache.identify({ __typename: 'SourceType', id: paramSourceId }), fragment: SOURCE_BASE_FIELDS, }); const [isKnownSource, setIsKnownSource] = useState(fragmentSource !== null ? true : undefined); const { data: migratableSourceData, loading: isSourceLoading, error: sourceError, refetch: refetchSource, } = requestManager.useGetSource( GET_SOURCE_MIGRATABLE, paramSourceId, { skip: !!isKnownSource, notifyOnNetworkStatusChange: true }, ); const { sourceId, name } = { sourceId: paramSourceId, name: paramSourceId, ...fragmentSource, ...migratableSourceData?.source, }; const { data: migratableSourceMangasData, loading: areMangasLoading, error: mangasError, refetch: refetchMangas, } = requestManager.useGetMigratableSourceMangas(sourceId, { skip: !isKnownSource, notifyOnNetworkStatusChange: true, }); useLayoutEffect(() => { setTitle(name ?? sourceId ?? t('migrate.title')); setAction(); return () => { setTitle(''); setAction(null); }; }, [t, name, sourceId, gridLayout]); useEffect(() => { if (isSourceLoading || isKnownSource) { return; } setIsKnownSource( !!migratableSourceData || !!sourceError?.message.includes("The field at path '/source' was declared as a non null type"), ); }, [isSourceLoading, sourceError]); const isLoadingSource = isSourceLoading || (!sourceError && !isKnownSource); const isLoading = isLoadingSource || areMangasLoading; if (isLoading) { return ; } const hasErrorSource = sourceError && isKnownSource === false; const hasError = hasErrorSource || mangasError; if (hasError) { const error = (hasErrorSource ? sourceError : mangasError)!; return ( { if (hasErrorSource) { refetchSource().catch(defaultPromiseErrorHandler('Migrate::refetchSource')); } if (mangasError) { refetchMangas().catch(defaultPromiseErrorHandler('Migrate::refetchMangas')); } }} /> ); } return ( {}} isLoading={areMangasLoading} mangas={migratableSourceMangasData?.mangas.nodes ?? []} gridLayout={gridLayout} mode="migrate.search" /> ); };