Extract app routes into constant
This commit is contained in:
70
src/App.tsx
70
src/App.tsx
@@ -22,6 +22,7 @@ import { lazyLoadFallback } from '@/modules/core/utils/LazyLoad.tsx';
|
||||
import { ErrorBoundary } from '@/modules/core/components/ErrorBoundary.tsx';
|
||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||
import { Reader } from '@/modules/reader/screens/Reader.tsx';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const { Browse } = loadable(() => import('@/modules/browse/screens/Browse.tsx'), lazyLoadFallback);
|
||||
const { DownloadQueue } = loadable(() => import('@/modules/downloads/screens/DownloadQueue.tsx'), lazyLoadFallback);
|
||||
@@ -113,48 +114,51 @@ const MainApp = () => {
|
||||
<ErrorBoundary>
|
||||
<Routes>
|
||||
{/* General Routes */}
|
||||
<Route path="/" element={<Navigate to="/library" replace />} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
<Route path="settings">
|
||||
<Route path={AppRoutes.root.match} element={<Navigate to={AppRoutes.library.path} replace />} />
|
||||
<Route path={AppRoutes.matchAll.match} element={<Navigate to={AppRoutes.root.path} replace />} />
|
||||
<Route path={AppRoutes.settings.match}>
|
||||
<Route index element={<Settings />} />
|
||||
<Route path="about" element={<About />} />
|
||||
<Route path="categories" element={<CategorySettings />} />
|
||||
<Route path="reader" element={<GlobalReaderSettings />} />
|
||||
<Route path="library">
|
||||
<Route path={AppRoutes.settings.childRoutes.about.match} element={<About />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.categories.match} element={<CategorySettings />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.reader.match} element={<GlobalReaderSettings />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.library.match}>
|
||||
<Route index element={<LibrarySettings />} />
|
||||
<Route path="duplicates" element={<LibraryDuplicates />} />
|
||||
<Route
|
||||
path={AppRoutes.settings.childRoutes.library.childRoutes.duplicates.match}
|
||||
element={<LibraryDuplicates />}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="download" element={<DownloadSettings />} />
|
||||
<Route path="backup" element={<Backup />} />
|
||||
<Route path="server" element={<ServerSettings />} />
|
||||
<Route path="webui" element={<WebUISettings />} />
|
||||
<Route path="browse" element={<BrowseSettings />} />
|
||||
<Route path="device" element={<DeviceSetting />} />
|
||||
<Route path="tracking" element={<TrackingSettings />} />
|
||||
<Route path="appearance" element={<Appearance />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.download.match} element={<DownloadSettings />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.backup.match} element={<Backup />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.server.match} element={<ServerSettings />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.webui.match} element={<WebUISettings />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.browse.match} element={<BrowseSettings />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.device.match} element={<DeviceSetting />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.tracking.match} element={<TrackingSettings />} />
|
||||
<Route path={AppRoutes.settings.childRoutes.appearance.match} element={<Appearance />} />
|
||||
</Route>
|
||||
|
||||
{/* Manga Routes */}
|
||||
|
||||
<Route path="sources">
|
||||
<Route index element={<Navigate to="/" replace />} />
|
||||
<Route path=":sourceId" element={<SourceMangas />} />
|
||||
<Route path=":sourceId/configure/" element={<SourceConfigure />} />
|
||||
<Route path="all/search/" element={<SearchAll />} />
|
||||
<Route path={AppRoutes.sources.match}>
|
||||
<Route index element={<Navigate to={AppRoutes.root.path} replace />} />
|
||||
<Route path={AppRoutes.sources.childRoutes.browse.match} element={<SourceMangas />} />
|
||||
<Route path={AppRoutes.sources.childRoutes.configure.match} element={<SourceConfigure />} />
|
||||
<Route path={AppRoutes.sources.childRoutes.searchAll.match} element={<SearchAll />} />
|
||||
</Route>
|
||||
<Route path="downloads" element={<DownloadQueue />} />
|
||||
<Route path="manga/:id">
|
||||
<Route path="chapter/:chapterNum" element={null} />
|
||||
<Route path={AppRoutes.downloads.match} element={<DownloadQueue />} />
|
||||
<Route path={AppRoutes.manga.match}>
|
||||
<Route path={AppRoutes.manga.childRoutes.reader.match} element={null} />
|
||||
<Route index element={<Manga />} />
|
||||
</Route>
|
||||
<Route path="library" element={<Library />} />
|
||||
<Route path="updates" element={<Updates />} />
|
||||
<Route path="browse" element={<Browse />} />
|
||||
<Route path="migrate/source/:sourceId">
|
||||
<Route path={AppRoutes.library.match} element={<Library />} />
|
||||
<Route path={AppRoutes.updates.match} element={<Updates />} />
|
||||
<Route path={AppRoutes.browse.match} element={<Browse />} />
|
||||
<Route path={AppRoutes.migrate.match}>
|
||||
<Route index element={<Migrate />} />
|
||||
<Route path="manga/:mangaId/search" element={<SearchAll />} />
|
||||
<Route path={AppRoutes.migrate.childRoutes.search.match} element={<SearchAll />} />
|
||||
</Route>
|
||||
<Route path="tracker/login/oauth" element={<TrackerOAuthLogin />} />
|
||||
<Route path={AppRoutes.tracker.match} element={<TrackerOAuthLogin />} />
|
||||
</Routes>
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
@@ -164,7 +168,7 @@ const MainApp = () => {
|
||||
const ReaderApp = () => (
|
||||
<ErrorBoundary>
|
||||
<Routes>
|
||||
<Route path="*" element={<Reader />} />
|
||||
<Route path={AppRoutes.matchAll.match} element={<Reader />} />
|
||||
</Routes>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
@@ -181,8 +185,8 @@ export const App: React.FC = () => (
|
||||
<DefaultNavBar />
|
||||
</Box>
|
||||
<Routes>
|
||||
<Route path="*" element={<MainApp />} />
|
||||
<Route path="manga/:mangaId/chapter/:chapterIndex/*" element={<ReaderApp />} />
|
||||
<Route path={AppRoutes.matchAll.match} element={<MainApp />} />
|
||||
<Route path={AppRoutes.reader.match} element={<ReaderApp />} />
|
||||
</Routes>
|
||||
</Box>
|
||||
</AppContext>
|
||||
|
||||
@@ -20,6 +20,7 @@ import { VersionUpdateInfoDialog } from '@/modules/app-updates/components/Versio
|
||||
import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts';
|
||||
import { useLocalStorage } from '@/modules/core/hooks/useStorage.tsx';
|
||||
import { getVersion } from '@/modules/app-updates/services/AppUpdateChecker.tsx';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const disabledUpdateCheck = () => Promise.resolve();
|
||||
|
||||
@@ -87,7 +88,7 @@ export const ServerUpdateChecker = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isAboutPage = window.location.pathname === '/settings/about';
|
||||
const isAboutPage = window.location.pathname === AppRoutes.settings.childRoutes.about.path;
|
||||
if (isAboutPage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import { LoadingPlaceholder } from '@/modules/core/components/placeholder/Loadin
|
||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { ServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
type BackupSettingsType = Pick<ServerSettings, 'backupPath' | 'backupTime' | 'backupInterval' | 'backupTTL'>;
|
||||
|
||||
@@ -357,7 +358,7 @@ export function Backup() {
|
||||
<Button
|
||||
onClick={closeInvalidBackupDialog}
|
||||
component={Link}
|
||||
to="/browse"
|
||||
to={AppRoutes.browse.path}
|
||||
autoFocus={!!validationResult?.missingSources.length}
|
||||
variant={validationResult?.missingSources.length ? 'contained' : 'text'}
|
||||
>
|
||||
@@ -368,7 +369,7 @@ export function Backup() {
|
||||
<Button
|
||||
onClick={closeInvalidBackupDialog}
|
||||
component={Link}
|
||||
to="/settings/tracking"
|
||||
to={AppRoutes.tracker.path}
|
||||
autoFocus={!!validationResult?.missingTrackers.length}
|
||||
variant={validationResult?.missingTrackers.length ? 'contained' : 'text'}
|
||||
>
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
} from '@/lib/graphql/generated/graphql.ts';
|
||||
import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts';
|
||||
import { GET_MANGA_CATEGORIES } from '@/lib/graphql/queries/MangaQuery.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
type BaseProps = {
|
||||
open: boolean;
|
||||
@@ -232,7 +233,7 @@ export function CategorySelect(props: CategorySelectProps) {
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Button component={Link} to="/settings/categories">
|
||||
<Button component={Link} to={AppRoutes.settings.childRoutes.categories.path}>
|
||||
{t(allCategories.length ? 'global.button.edit' : 'global.button.create')}
|
||||
</Button>
|
||||
<Stack direction="row">
|
||||
|
||||
@@ -22,6 +22,7 @@ import { CHAPTER_LIST_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts
|
||||
import { DirectionOffset, TranslationKey } from '@/Base.types.ts';
|
||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { ReaderResumeMode } from '@/modules/reader/types/Reader.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
export type ChapterAction = 'download' | 'delete' | 'bookmark' | 'unbookmark' | 'mark_as_read' | 'mark_as_unread';
|
||||
|
||||
@@ -118,7 +119,7 @@ export class Chapters {
|
||||
}
|
||||
|
||||
static getReaderUrl<Chapter extends ChapterMangaInfo & ChapterSourceOrderInfo>(chapter: Chapter): string {
|
||||
return `/manga/${chapter.mangaId}/chapter/${chapter.sourceOrder}`;
|
||||
return AppRoutes.reader.path(chapter.mangaId, chapter.sourceOrder);
|
||||
}
|
||||
|
||||
static isDownloading(id: number): boolean {
|
||||
|
||||
157
src/modules/core/AppRoute.constants.ts
Normal file
157
src/modules/core/AppRoute.constants.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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 { SourceType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { ChapterSourceOrderInfo } from '@/modules/chapter/services/Chapters.ts';
|
||||
|
||||
type AppRouteInfo = {
|
||||
match: string;
|
||||
path?: string | ((...args: any[]) => string);
|
||||
};
|
||||
|
||||
type TAppRoutes = Record<string, AppRouteInfo & { childRoutes?: TAppRoutes }>;
|
||||
|
||||
export const AppRoutes = {
|
||||
root: {
|
||||
match: '/',
|
||||
path: '/',
|
||||
},
|
||||
matchAll: {
|
||||
match: '*',
|
||||
},
|
||||
settings: {
|
||||
path: '/settings',
|
||||
match: 'settings',
|
||||
childRoutes: {
|
||||
about: {
|
||||
match: 'about',
|
||||
path: '/settings/about',
|
||||
},
|
||||
categories: {
|
||||
match: 'categories',
|
||||
path: '/settings/categories',
|
||||
},
|
||||
reader: {
|
||||
match: 'reader',
|
||||
path: '/settings/reader',
|
||||
},
|
||||
library: {
|
||||
match: 'library',
|
||||
path: '/settings/library',
|
||||
|
||||
childRoutes: {
|
||||
duplicates: {
|
||||
match: 'duplicates',
|
||||
path: '/settings/library/duplicates',
|
||||
},
|
||||
},
|
||||
},
|
||||
download: {
|
||||
match: 'download',
|
||||
path: '/settings/download',
|
||||
},
|
||||
backup: {
|
||||
match: 'backup',
|
||||
path: '/settings/backup',
|
||||
},
|
||||
server: {
|
||||
match: 'server',
|
||||
path: '/settings/server',
|
||||
},
|
||||
webui: {
|
||||
match: 'webui',
|
||||
path: '/settings/webui',
|
||||
},
|
||||
browse: {
|
||||
match: 'browse',
|
||||
path: '/settings/browse',
|
||||
},
|
||||
device: {
|
||||
match: 'device',
|
||||
path: '/settings/device',
|
||||
},
|
||||
tracking: {
|
||||
match: 'tracking',
|
||||
path: '/settings/tracking',
|
||||
},
|
||||
appearance: {
|
||||
match: 'appearance',
|
||||
path: '/settings/appearance',
|
||||
},
|
||||
},
|
||||
},
|
||||
sources: {
|
||||
match: 'sources',
|
||||
path: '/sources',
|
||||
|
||||
childRoutes: {
|
||||
browse: {
|
||||
match: ':sourceId',
|
||||
path: (sourceId: SourceType['id']) => `/sources/${sourceId}`,
|
||||
},
|
||||
configure: {
|
||||
match: ':sourceId/configure',
|
||||
path: (sourceId: SourceType['id']) => `/sources/${sourceId}/configure`,
|
||||
},
|
||||
searchAll: {
|
||||
match: 'all/search',
|
||||
path: '/sources/all/search',
|
||||
},
|
||||
},
|
||||
},
|
||||
downloads: {
|
||||
match: 'downloads',
|
||||
path: '/downloads',
|
||||
},
|
||||
manga: {
|
||||
match: 'manga/:id',
|
||||
path: (mangaId: MangaIdInfo['id']) => `/manga/${mangaId}`,
|
||||
|
||||
childRoutes: {
|
||||
reader: {
|
||||
match: 'chapter/:chapterNum',
|
||||
path: (mangaId: MangaIdInfo['id'], chapterNum: ChapterSourceOrderInfo['sourceOrder']) =>
|
||||
`/manga/${mangaId}/chapter/${chapterNum}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
library: {
|
||||
match: 'library',
|
||||
path: '/library',
|
||||
},
|
||||
updates: {
|
||||
match: 'updates',
|
||||
path: '/updates',
|
||||
},
|
||||
browse: {
|
||||
match: 'browse',
|
||||
path: '/browse',
|
||||
},
|
||||
migrate: {
|
||||
match: 'migrate/source/:sourceId',
|
||||
path: (sourceId: SourceType['id']) => `/migrate/source/${sourceId}`,
|
||||
|
||||
childRoutes: {
|
||||
search: {
|
||||
match: 'manga/:mangaId/search',
|
||||
path: (sourceId: SourceType['id'], mangaId: MangaIdInfo['id']) =>
|
||||
`/migrate/source/${sourceId}/manga/${mangaId}/search`,
|
||||
},
|
||||
},
|
||||
},
|
||||
tracker: {
|
||||
match: 'tracker/login/oauth',
|
||||
path: '/tracker/login/oauth',
|
||||
},
|
||||
reader: {
|
||||
match: '/manga/:mangaId/chapter/:chapterIndex',
|
||||
path: (mangaId: MangaIdInfo['id'], chapterIndex: ChapterSourceOrderInfo['sourceOrder']) =>
|
||||
`/manga/${mangaId}/chapter/${chapterIndex}`,
|
||||
},
|
||||
} satisfies TAppRoutes;
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const PAGES_TO_IGNORE: readonly RegExp[] = [/\/manga\/[0-9]+\/chapter\/[0-9]+/g];
|
||||
|
||||
@@ -27,6 +28,6 @@ export const useBackButton = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
navigate('/library');
|
||||
navigate(AppRoutes.library.path);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -35,6 +35,7 @@ import { LoadingPlaceholder } from '@/modules/core/components/placeholder/Loadin
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { ChapterDownloadStatus, ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts';
|
||||
import { DownloaderState, DownloadState } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const HeightPreservingItem = ({ children, ...props }: BoxProps) => (
|
||||
// the height is necessary to prevent the item container from collapsing, which confuses Virtuoso measurements
|
||||
@@ -59,7 +60,7 @@ const DownloadChapterItem = ({
|
||||
return (
|
||||
<Box {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} sx={{ p: 1, pb: 0 }}>
|
||||
<Card>
|
||||
<CardActionArea component={Link} to={`/manga/${item.manga.id}`}>
|
||||
<CardActionArea component={Link} to={AppRoutes.manga.path(item.manga.id)}>
|
||||
<CardContent
|
||||
sx={{
|
||||
display: 'flex',
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
} from '@/modules/extension/Extensions.utils.ts';
|
||||
import { ExtensionAction, ExtensionGroupState, ExtensionState } from '@/modules/extension/Extensions.types.ts';
|
||||
import { EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP } from '@/modules/extension/Extensions.constants.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const LANGUAGE = 0;
|
||||
const EXTENSIONS = 1;
|
||||
@@ -223,7 +224,7 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
||||
}}
|
||||
>
|
||||
<Typography>{t('extension.label.add_repository_info')}</Typography>
|
||||
<Button component={Link} variant="contained" to="/settings/browse">
|
||||
<Button component={Link} variant="contained" to={AppRoutes.browse.path}>
|
||||
{t('settings.title')}
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
@@ -29,6 +29,7 @@ import { SourceType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { BaseMangaGrid } from '@/modules/manga/components/BaseMangaGrid.tsx';
|
||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean };
|
||||
type SourceToLoadingStateMap = Map<string, SourceLoadingState>;
|
||||
@@ -149,7 +150,11 @@ const SourceSearchPreview = React.memo(
|
||||
return (
|
||||
<>
|
||||
<Card sx={{ mb: 1 }}>
|
||||
<CardActionArea component={Link} to={`/sources/${id}?query=${searchString}`} sx={{ p: 3 }}>
|
||||
<CardActionArea
|
||||
component={Link}
|
||||
to={`${AppRoutes.sources.childRoutes.browse.path(id)}?query=${searchString}`}
|
||||
sx={{ p: 3 }}
|
||||
>
|
||||
<Typography variant="h5">{displayName}</Typography>
|
||||
<Typography variant="caption">{translateExtensionLanguage(lang)}</Typography>
|
||||
</CardActionArea>
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts';
|
||||
import { GET_MANGAS_BASE } from '@/lib/graphql/queries/MangaQuery.ts';
|
||||
import { MetadataLibrarySettings } from '@/modules/library/Library.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const removeNonLibraryMangasFromCategories = async (): Promise<void> => {
|
||||
try {
|
||||
@@ -182,7 +183,7 @@ export function LibrarySettings() {
|
||||
secondary={t('library.settings.advanced.database.cleanup.label.description')}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemLink to="duplicates">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.library.childRoutes.duplicates.path}>
|
||||
<ListItemText
|
||||
primary={t('library.settings.advanced.duplicates.label.title')}
|
||||
secondary={t('library.settings.advanced.duplicates.label.description')}
|
||||
|
||||
@@ -10,7 +10,6 @@ import { useTranslation } from 'react-i18next';
|
||||
import Button from '@mui/material/Button';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ChapterReadInfo, Chapters, ChapterSourceOrderInfo } from '@/modules/chapter/services/Chapters.ts';
|
||||
|
||||
@@ -39,7 +38,7 @@ export const ContinueReadingButton = ({
|
||||
size="small"
|
||||
sx={{ minWidth: 'unset', py: 0.5, px: 0.75 }}
|
||||
component={Link}
|
||||
to={`${mangaLinkTo}chapter/${chapter.sourceOrder}`}
|
||||
to={`${mangaLinkTo}/chapter/${chapter.sourceOrder}`}
|
||||
state={{ resumeMode: Chapters.getReaderResumeMode(chapter) }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
|
||||
@@ -35,6 +35,7 @@ import { NestedMenuItem } from '@/modules/core/components/menu/NestedMenuItem.ts
|
||||
import { MangaChapterStatFieldsFragment, MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { MangaAction, MangaDownloadInfo, MangaIdInfo, MangaUnreadInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { actionToTranslationKey } from '@/modules/manga/Manga.constants.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const ACTION_DISABLES_SELECTION_MODE: MangaAction[] = ['remove_from_library'] as const;
|
||||
|
||||
@@ -156,7 +157,7 @@ export const MangaActionMenuItems = ({
|
||||
)}
|
||||
{isSingleMode && (
|
||||
<Link
|
||||
to={`/migrate/source/${manga?.sourceId}/manga/${manga?.id}/search?query=${manga?.title}`}
|
||||
to={`${AppRoutes.migrate.childRoutes.search.path(manga?.sourceId ?? -1, manga?.id ?? -1)}?query=${manga?.title}`}
|
||||
state={{ mangaTitle: manga?.title }}
|
||||
style={{ textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
|
||||
@@ -23,6 +23,7 @@ import { useTheme } from '@mui/material/styles';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import { useCategorySelect } from '@/modules/category/hooks/useCategorySelect.tsx';
|
||||
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
interface IProps {
|
||||
manga: Pick<MangaType, 'id' | 'inLibrary' | 'sourceId' | 'title'>;
|
||||
@@ -65,7 +66,7 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => {
|
||||
<>
|
||||
<Tooltip title={t('global.button.migrate')}>
|
||||
<Link
|
||||
to={`/migrate/source/${manga.sourceId}/manga/${manga.id}/search?query=${manga.title}`}
|
||||
to={`${AppRoutes.migrate.childRoutes.search.path(manga.sourceId, manga.id)}?query=${manga.title}`}
|
||||
state={{ mangaTitle: manga.title }}
|
||||
style={{ textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
@@ -125,7 +126,7 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => {
|
||||
<MenuItem
|
||||
key="migrate"
|
||||
component={Link}
|
||||
to={`/migrate/source/${manga.sourceId}/manga/${manga.id}/search?query=${manga.title}`}
|
||||
to={`${AppRoutes.migrate.childRoutes.search.path(manga.sourceId, manga.id)}?query=${manga.title}`}
|
||||
state={{ mangaTitle: manga.title }}
|
||||
style={{ textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
|
||||
@@ -19,8 +19,8 @@ import { Trackers } from '@/modules/tracker/services/Trackers.ts';
|
||||
import { CustomIconButton } from '@/modules/core/components/buttons/CustomIconButton.tsx';
|
||||
import { GetTrackersSettingsQuery, MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { GET_TRACKERS_SETTINGS } from '@/lib/graphql/queries/TrackerQuery.ts';
|
||||
|
||||
import { MangaTrackRecordInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
export const TrackMangaButton = ({ manga }: { manga: MangaTrackRecordInfo & Pick<MangaType, 'title'> }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -40,7 +40,7 @@ export const TrackMangaButton = ({ manga }: { manga: MangaTrackRecordInfo & Pick
|
||||
}
|
||||
|
||||
if (!loggedInTrackers.length) {
|
||||
navigate('/settings/tracking');
|
||||
navigate(AppRoutes.tracker.path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import { MangaCardMode, MangaCardProps } from '@/modules/manga/Manga.types.ts';
|
||||
import { ContinueReadingButton } from '@/modules/manga/components/ContinueReadingButton.tsx';
|
||||
import { MangaBadges } from '@/modules/manga/components/MangaBadges.tsx';
|
||||
import { GridLayout } from '@/modules/core/Core.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const getMangaLinkTo = (
|
||||
mode: MangaCardMode,
|
||||
@@ -31,9 +32,9 @@ const getMangaLinkTo = (
|
||||
case 'default':
|
||||
case 'source':
|
||||
case 'duplicate':
|
||||
return `/manga/${mangaId}/`;
|
||||
return AppRoutes.manga.path(mangaId);
|
||||
case 'migrate.search':
|
||||
return `/migrate/source/${sourceId}/manga/${mangaId}/search?query=${mangaTitle}`;
|
||||
return `${AppRoutes.migrate.childRoutes.search.path(sourceId ?? '-1', mangaId)}?query=${mangaTitle}`;
|
||||
case 'migrate.select':
|
||||
return '';
|
||||
default:
|
||||
|
||||
@@ -20,6 +20,7 @@ import { Mangas } from '@/modules/manga/services/Mangas.ts';
|
||||
import { awaitConfirmation } from '@/modules/core/utils/AwaitableDialog.tsx';
|
||||
import { GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables, MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
export const useManageMangaLibraryState = (
|
||||
manga: Pick<MangaType, 'id' | 'title'> & Partial<Pick<MangaType, 'inLibrary'>>,
|
||||
@@ -136,7 +137,7 @@ export const useManageMangaLibraryState = (
|
||||
extra: { show: true, title: t('migrate.dialog.action.button.show_entry'), contain: true },
|
||||
confirm: { title: t('global.button.add') },
|
||||
},
|
||||
onExtra: () => navigate(`/manga/${duplicatedLibraryMangas!.data.mangas.nodes[0].id}`),
|
||||
onExtra: () => navigate(AppRoutes.manga.path(duplicatedLibraryMangas!.data.mangas.nodes[0].id)),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { MetadataMigrationSettings } from '@/modules/migration/Migration.types.ts';
|
||||
import { MigrateMode } from '@/modules/manga/Manga.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
export const MigrateDialog = ({ mangaIdToMigrateTo, onClose }: { mangaIdToMigrateTo: number; onClose: () => void }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -63,7 +64,7 @@ export const MigrateDialog = ({ mangaIdToMigrateTo, onClose }: { mangaIdToMigrat
|
||||
deleteChapters,
|
||||
});
|
||||
|
||||
navigate(`/manga/${mangaIdToMigrateTo}`, { replace: true });
|
||||
navigate(AppRoutes.manga.path(mangaIdToMigrateTo), { replace: true });
|
||||
} catch (e) {
|
||||
setIsMigrationInProcess(false);
|
||||
}
|
||||
@@ -108,7 +109,11 @@ export const MigrateDialog = ({ mangaIdToMigrateTo, onClose }: { mangaIdToMigrat
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Button disabled={isMigrationInProcess} component={Link} to={`/manga/${mangaIdToMigrateTo}`}>
|
||||
<Button
|
||||
disabled={isMigrationInProcess}
|
||||
component={Link}
|
||||
to={AppRoutes.manga.path(mangaIdToMigrateTo)}
|
||||
>
|
||||
{t('migrate.dialog.action.button.show_entry')}
|
||||
</Button>
|
||||
<Stack direction="row">
|
||||
|
||||
@@ -19,6 +19,7 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { GetMigratableSourcesQuery } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
export type TMigratableSource = NonNullable<GetMigratableSourcesQuery['mangas']['nodes'][number]['source']> & {
|
||||
mangaCount: number;
|
||||
@@ -33,7 +34,7 @@ export const MigrationCard = ({ id, name, lang, iconUrl, mangaCount }: TMigratab
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardActionArea component={Link} to={`/migrate/source/${id}/`}>
|
||||
<CardActionArea component={Link} to={AppRoutes.migrate.path(id)}>
|
||||
<CardContent
|
||||
sx={{
|
||||
display: 'flex',
|
||||
|
||||
@@ -34,38 +34,39 @@ import { DesktopSideBar } from '@/modules/navigation-bar/components/DesktopSideB
|
||||
import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx';
|
||||
import { MobileBottomBar } from '@/modules/navigation-bar/components/MobileBottomBar.tsx';
|
||||
import { NavbarItem } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const navbarItems: Array<NavbarItem> = [
|
||||
{
|
||||
path: '/library',
|
||||
path: AppRoutes.library.path,
|
||||
title: 'library.title',
|
||||
SelectedIconComponent: CollectionsBookmarkIcon,
|
||||
IconComponent: CollectionsOutlinedBookmarkIcon,
|
||||
show: 'both',
|
||||
},
|
||||
{
|
||||
path: '/updates',
|
||||
path: AppRoutes.updates.path,
|
||||
title: 'updates.title',
|
||||
SelectedIconComponent: NewReleasesIcon,
|
||||
IconComponent: NewReleasesOutlinedIcon,
|
||||
show: 'both',
|
||||
},
|
||||
{
|
||||
path: '/browse',
|
||||
path: AppRoutes.browse.path,
|
||||
title: 'global.label.browse',
|
||||
SelectedIconComponent: ExploreIcon,
|
||||
IconComponent: ExploreOutlinedIcon,
|
||||
show: 'both',
|
||||
},
|
||||
{
|
||||
path: '/downloads',
|
||||
path: AppRoutes.downloads.path,
|
||||
title: 'download.title',
|
||||
SelectedIconComponent: GetAppIcon,
|
||||
IconComponent: GetAppOutlinedIcon,
|
||||
show: 'both',
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
path: AppRoutes.settings.path,
|
||||
title: 'settings.title',
|
||||
SelectedIconComponent: SettingsIcon,
|
||||
IconComponent: SettingsIcon,
|
||||
|
||||
@@ -32,6 +32,7 @@ import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrol
|
||||
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
||||
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
||||
import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const DEFAULT_MANGA = { id: -1, title: '' };
|
||||
const DEFAULT_CHAPTER = { id: -1, name: '', realUrl: '', isBookmarked: false };
|
||||
@@ -79,7 +80,7 @@ export const ReaderOverlayHeaderMobile = ({ isVisible }: MobileHeaderProps) => {
|
||||
<TypographyMaxLines lines={1} component="h1" variant="h5">
|
||||
<Link
|
||||
component={RouterLink}
|
||||
to={`/manga/${mangaId}`}
|
||||
to={AppRoutes.manga.path(mangaId)}
|
||||
sx={{ textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
{title}
|
||||
|
||||
@@ -12,6 +12,7 @@ import Link from '@mui/material/Link';
|
||||
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
export const ReaderNavBarDesktopMetadata = ({
|
||||
mangaId,
|
||||
@@ -25,7 +26,11 @@ export const ReaderNavBarDesktopMetadata = ({
|
||||
<Stack>
|
||||
<Tooltip title={mangaTitle} placement="right">
|
||||
<TypographyMaxLines lines={3} variant="h6" component="h1" sx={{ textAlign: 'center' }}>
|
||||
<Link component={RouterLink} to={`/manga/${mangaId}`} sx={{ textDecoration: 'none', color: 'inherit' }}>
|
||||
<Link
|
||||
component={RouterLink}
|
||||
to={AppRoutes.manga.path(mangaId)}
|
||||
sx={{ textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
{mangaTitle}
|
||||
</Link>
|
||||
</TypographyMaxLines>
|
||||
|
||||
@@ -27,6 +27,7 @@ import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/Read
|
||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||
import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const ChapterInfo = ({
|
||||
title,
|
||||
@@ -173,7 +174,7 @@ export const ReaderTransitionPage = ({
|
||||
e.stopPropagation();
|
||||
}}
|
||||
variant="contained"
|
||||
to={`/manga/${manga?.id}`}
|
||||
to={AppRoutes.manga.path(manga?.id ?? -1)}
|
||||
>
|
||||
{t('reader.transition_page.exit.manga_page')}
|
||||
</Button>
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
} from '@/modules/reader/utils/Reader.utils.ts';
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { Queue } from '@/lib/Queue.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const DIRECTION_TO_INVERTED: Record<Direction, Direction> = {
|
||||
ltr: 'rtl',
|
||||
@@ -330,7 +331,7 @@ export class ReaderService {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
return navigate(`/manga/${manga.id}`);
|
||||
return navigate(AppRoutes.manga.path(manga.id));
|
||||
}, [manga]);
|
||||
|
||||
switch (exitMode) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import { ListItemLink } from '@/modules/core/components/ListItemLink.tsx';
|
||||
import { NavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
export function Settings() {
|
||||
const { t } = useTranslation();
|
||||
@@ -57,43 +58,43 @@ export function Settings() {
|
||||
|
||||
return (
|
||||
<List sx={{ padding: 0 }}>
|
||||
<ListItemLink to="/settings/appearance">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.appearance.path}>
|
||||
<ListItemIcon>
|
||||
<PaletteIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('settings.appearance.title')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/categories">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.categories.path}>
|
||||
<ListItemIcon>
|
||||
<ListAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('category.title.category_other')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/reader">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.reader.path}>
|
||||
<ListItemIcon>
|
||||
<AutoStoriesIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('reader.settings.title.reader_settings')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/library">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.library.path}>
|
||||
<ListItemIcon>
|
||||
<CollectionsOutlinedBookmarkIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('library.title')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/download">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.download.path}>
|
||||
<ListItemIcon>
|
||||
<GetAppOutlinedIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('download.title')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/tracking">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.tracking.path}>
|
||||
<ListItemIcon>
|
||||
<SyncIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('tracking.title')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/backup">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.backup.path}>
|
||||
<ListItemIcon>
|
||||
<BackupIcon />
|
||||
</ListItemIcon>
|
||||
@@ -109,31 +110,31 @@ export function Settings() {
|
||||
secondary={t('settings.clear_cache.label.description')}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemLink to="/settings/browse">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.browse.path}>
|
||||
<ListItemIcon>
|
||||
<ExploreOutlinedIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('global.label.browse')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/device">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.device.path}>
|
||||
<ListItemIcon>
|
||||
<DevicesIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('settings.device.title.device')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/webui">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.webui.path}>
|
||||
<ListItemIcon>
|
||||
<WebIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('settings.webui.title.webui')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/server">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.server.path}>
|
||||
<ListItemIcon>
|
||||
<DnsIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t('settings.server.title.server')} />
|
||||
</ListItemLink>
|
||||
<ListItemLink to="/settings/about">
|
||||
<ListItemLink to={AppRoutes.settings.childRoutes.about.path}>
|
||||
<ListItemIcon>
|
||||
<InfoIcon />
|
||||
</ListItemIcon>
|
||||
|
||||
@@ -23,6 +23,7 @@ import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx';
|
||||
import { GetSourcesListQuery } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
interface IProps {
|
||||
source: GetSourcesListQuery['sources']['nodes'][number];
|
||||
@@ -59,7 +60,7 @@ export const SourceCard: React.FC<IProps> = (props: IProps) => {
|
||||
>
|
||||
<CardActionArea
|
||||
component={Link}
|
||||
to={`/sources/${id}`}
|
||||
to={AppRoutes.sources.childRoutes.browse.path(id)}
|
||||
state={{ contentType: SourceContentType.POPULAR, clearCache: true }}
|
||||
>
|
||||
<CardContent
|
||||
@@ -135,7 +136,7 @@ export const SourceCard: React.FC<IProps> = (props: IProps) => {
|
||||
<Button
|
||||
variant="outlined"
|
||||
component={Link}
|
||||
to={`/sources/${id}`}
|
||||
to={AppRoutes.sources.childRoutes.browse.path(id)}
|
||||
state={{ contentType: SourceContentType.LATEST, clearCache: true }}
|
||||
>
|
||||
{t('global.button.latest')}
|
||||
@@ -145,7 +146,7 @@ export const SourceCard: React.FC<IProps> = (props: IProps) => {
|
||||
<Button
|
||||
variant="outlined"
|
||||
component={Link}
|
||||
to={`/sources/${id}`}
|
||||
to={AppRoutes.sources.childRoutes.browse.path(id)}
|
||||
state={{ contentType: SourceContentType.POPULAR, clearCache: true }}
|
||||
>
|
||||
{t('global.button.popular')}
|
||||
|
||||
@@ -51,6 +51,7 @@ import { EmptyView } from '@/modules/core/components/placeholder/EmptyView.tsx';
|
||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { GridLayout } from '@/modules/core/Core.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const DEFAULT_SOURCE: Pick<SourceType, 'id'> = { id: '-1' };
|
||||
|
||||
@@ -407,7 +408,7 @@ export function SourceMangas() {
|
||||
{source?.isConfigurable && (
|
||||
<Tooltip title={t('settings.title')}>
|
||||
<IconButton
|
||||
onClick={() => navigate(`/sources/${sourceId}/configure/`)}
|
||||
onClick={() => navigate(AppRoutes.sources.childRoutes.configure.path(sourceId))}
|
||||
aria-label="display more actions"
|
||||
edge="end"
|
||||
color="inherit"
|
||||
|
||||
@@ -29,6 +29,7 @@ import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { SourceType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
function sourceToLangList(sources: Pick<SourceType, 'id' | 'lang'>[]) {
|
||||
const result = new Set<string>();
|
||||
@@ -107,7 +108,11 @@ export function Sources() {
|
||||
setAction(
|
||||
<>
|
||||
<Tooltip title={t('search.title.global_search')}>
|
||||
<IconButton onClick={() => navigate('/sources/all/search/')} size="large" color="inherit">
|
||||
<IconButton
|
||||
onClick={() => navigate(AppRoutes.sources.childRoutes.searchAll.path)}
|
||||
size="large"
|
||||
color="inherit"
|
||||
>
|
||||
<TravelExploreIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
@@ -22,6 +22,7 @@ import { GetMangaTrackRecordsQuery, GetTrackersBindQuery, MangaType } from '@/li
|
||||
import { GET_TRACKERS_BIND } from '@/lib/graphql/queries/TrackerQuery.ts';
|
||||
import { GET_MANGA_TRACK_RECORDS } from '@/lib/graphql/queries/MangaQuery.ts';
|
||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const getTrackerMode = (id: number, trackersInUse: number[], searchModeForTracker?: number): TrackerMode => {
|
||||
if (id === searchModeForTracker) {
|
||||
@@ -64,7 +65,7 @@ export const TrackManga = ({ manga }: { manga: MangaIdInfo & Pick<MangaType, 'ti
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && !error && !trackersInUse.length && !loggedInTrackers.length) {
|
||||
navigate('/settings/tracking');
|
||||
navigate(AppRoutes.tracker.path);
|
||||
}
|
||||
}, [loading]);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
export const TrackerOAuthLogin = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -38,7 +39,7 @@ export const TrackerOAuthLogin = () => {
|
||||
makeToast(t('tracking.action.login.label.failure', { name: trackerName }), 'error');
|
||||
}
|
||||
|
||||
navigate('/settings/tracking', { replace: true });
|
||||
navigate(AppRoutes.tracker.path, { replace: true });
|
||||
};
|
||||
|
||||
login();
|
||||
|
||||
@@ -37,6 +37,7 @@ import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines
|
||||
import { ChapterIdInfo, ChapterMangaInfo } from '@/modules/chapter/services/Chapters.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
const groupByDate = (updates: Pick<ChapterType, 'fetchedAt'>[]): [date: string, items: number][] => {
|
||||
if (!updates.length) {
|
||||
@@ -189,7 +190,7 @@ export const Updates: React.FC = () => {
|
||||
<Card>
|
||||
<CardActionArea
|
||||
component={Link}
|
||||
to={`/manga/${chapter.manga.id}/chapter/${chapter.sourceOrder}`}
|
||||
to={AppRoutes.reader.path(chapter.manga.id, chapter.sourceOrder)}
|
||||
state={location.state}
|
||||
sx={{
|
||||
color: (theme) => theme.palette.text[chapter.isRead ? 'disabled' : 'primary'],
|
||||
@@ -204,7 +205,10 @@ export const Updates: React.FC = () => {
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<Link to={`/manga/${chapter.manga.id}`} style={{ textDecoration: 'none' }}>
|
||||
<Link
|
||||
to={AppRoutes.manga.path(chapter.manga.id)}
|
||||
style={{ textDecoration: 'none' }}
|
||||
>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
sx={{
|
||||
|
||||
Reference in New Issue
Block a user