Use stable array/object constants

This commit is contained in:
schroda
2026-03-20 03:02:52 +01:00
parent fcf1c7fa3f
commit 9ce273b5ce
19 changed files with 44 additions and 24 deletions

View File

@@ -8,6 +8,7 @@
import type { Ref } from 'react'; import type { Ref } from 'react';
import { useState, useEffect, useCallback, useRef } from 'react'; import { useState, useEffect, useCallback, useRef } from 'react';
import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
@@ -61,7 +62,7 @@ export const SpinnerImage = ({ ref, ...props }: SpinnerImageProps) => {
alt, alt,
onLoad, onLoad,
onError, onError,
spinnerStyle: { small, ...spinnerStyle } = {}, spinnerStyle: { small, ...spinnerStyle } = STABLE_EMPTY_OBJECT,
imgStyle, imgStyle,
hideImgStyle, hideImgStyle,
priority, priority,

View File

@@ -10,11 +10,12 @@ import Box from '@mui/material/Box';
import type { CircularProgressProps } from '@mui/material/CircularProgress'; import type { CircularProgressProps } from '@mui/material/CircularProgress';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts';
export const Progress = ({ export const Progress = ({
progress, progress,
showText = true, showText = true,
progressProps = {}, progressProps = STABLE_EMPTY_OBJECT,
}: { }: {
progress: number; progress: number;
showText?: boolean; showText?: boolean;

View File

@@ -12,6 +12,7 @@
* with a few changes to fix a bug on mobile devices where opening the sub menu immediately triggered the on click of the underlying menu item * with a few changes to fix a bug on mobile devices where opening the sub menu immediately triggered the on click of the underlying menu item
*/ */
import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts';
import type { MenuProps as MuiMenuProps } from '@mui/material/Menu'; import type { MenuProps as MuiMenuProps } from '@mui/material/Menu';
import Menu from '@mui/material/Menu'; import Menu from '@mui/material/Menu';
import type { MenuItemProps as MuiMenuItemProps } from '@mui/material/MenuItem'; import type { MenuItemProps as MuiMenuItemProps } from '@mui/material/MenuItem';
@@ -64,7 +65,7 @@ export const NestedMenuItem = ({ ref, ...props }: NestedMenuItemProps) => {
children, children,
className, className,
tabIndex: tabIndexProp, tabIndex: tabIndexProp,
ContainerProps: ContainerPropsProp = {}, ContainerProps: ContainerPropsProp = STABLE_EMPTY_OBJECT,
MenuProps, MenuProps,
...MenuItemProps ...MenuItemProps
} = props; } = props;

View File

@@ -8,6 +8,7 @@
import type { RefObject } from 'react'; import type { RefObject } from 'react';
import { useLayoutEffect, useState } from 'react'; import { useLayoutEffect, useState } from 'react';
import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts';
export const useIntersectionObserver = ( export const useIntersectionObserver = (
ref: RefObject<HTMLElement | null> | HTMLElement | undefined | null, ref: RefObject<HTMLElement | null> | HTMLElement | undefined | null,
@@ -17,7 +18,7 @@ export const useIntersectionObserver = (
root, root,
rootMargin, rootMargin,
threshold, threshold,
}: IntersectionObserverInit & { ignoreInitialObserve?: boolean } = {}, }: IntersectionObserverInit & { ignoreInitialObserve?: boolean } = STABLE_EMPTY_OBJECT,
): (() => void) => { ): (() => void) => {
const [disconnect, setDisconnect] = useState<() => void>(() => {}); const [disconnect, setDisconnect] = useState<() => void>(() => {});

View File

@@ -46,6 +46,7 @@ import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { makeToast } from '@/base/utils/Toast.ts'; import { makeToast } from '@/base/utils/Toast.ts';
import { ChapterListCard } from '@/features/chapter/components/cards/ChapterListCard.tsx'; import { ChapterListCard } from '@/features/chapter/components/cards/ChapterListCard.tsx';
import { VirtuosoPersisted } from '@/lib/virtuoso/Component/VirtuosoPersisted.tsx'; import { VirtuosoPersisted } from '@/lib/virtuoso/Component/VirtuosoPersisted.tsx';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
type ChapterListHeaderProps = { type ChapterListHeaderProps = {
scrollbarWidth: number; scrollbarWidth: number;
@@ -140,7 +141,7 @@ export const ChapterList = ({
manga.id, manga.id,
{ notifyOnNetworkStatusChange: true }, { notifyOnNetworkStatusChange: true },
); );
const chapters = useMemo(() => chaptersData?.chapters.nodes ?? [], [chaptersData?.chapters.nodes]); const chapters = chaptersData?.chapters.nodes ?? STABLE_EMPTY_ARRAY;
const visibleChapters = useMemo(() => filterAndSortChapters(chapters, options), [chapters, options]); const visibleChapters = useMemo(() => filterAndSortChapters(chapters, options), [chapters, options]);
const visibleChapterIds = useMemo(() => Chapters.getIds(visibleChapters), [visibleChapters]); const visibleChapterIds = useMemo(() => Chapters.getIds(visibleChapters), [visibleChapters]);

View File

@@ -6,6 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
import CheckBoxOutlineBlank from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxOutlineBlank from '@mui/icons-material/CheckBoxOutlineBlank';
import Delete from '@mui/icons-material/Delete'; import Delete from '@mui/icons-material/Delete';
import Download from '@mui/icons-material/Download'; import Download from '@mui/icons-material/Download';
@@ -71,7 +72,7 @@ export const ChapterActionMenuItems = ({
chapter, chapter,
handleSelection, handleSelection,
canBeDownloaded = false, canBeDownloaded = false,
selectedChapters = [], selectedChapters = STABLE_EMPTY_ARRAY,
onClose, onClose,
selectable = true, selectable = true,
}: Props) => { }: Props) => {

View File

@@ -33,6 +33,7 @@ import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
import { useAppAction } from '@/features/navigation-bar/hooks/useAppAction.ts'; import { useAppAction } from '@/features/navigation-bar/hooks/useAppAction.ts';
import type { ChapterDownloadStatus } from '@/features/chapter/Chapter.types.ts'; import type { ChapterDownloadStatus } from '@/features/chapter/Chapter.types.ts';
import { VirtuosoPersisted } from '@/lib/virtuoso/Component/VirtuosoPersisted.tsx'; import { VirtuosoPersisted } from '@/lib/virtuoso/Component/VirtuosoPersisted.tsx';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
export const DownloadQueue: React.FC = () => { export const DownloadQueue: React.FC = () => {
const { t } = useLingui(); const { t } = useLingui();
@@ -49,7 +50,7 @@ export const DownloadQueue: React.FC = () => {
} = requestManager.useGetDownloadStatus({ notifyOnNetworkStatusChange: true }); } = requestManager.useGetDownloadStatus({ notifyOnNetworkStatusChange: true });
const downloaderData = downloadStatusData?.downloadStatus; const downloaderData = downloadStatusData?.downloadStatus;
const queue = downloaderData?.queue ?? []; const queue = downloaderData?.queue ?? STABLE_EMPTY_ARRAY;
const status = downloaderData?.state ?? DownloaderState.Started; const status = downloaderData?.state ?? DownloaderState.Started;
const isQueueEmpty = !queue.length; const isQueueEmpty = !queue.length;

View File

@@ -28,6 +28,7 @@ import { AppbarSearch } from '@/base/components/AppbarSearch.tsx';
import { useDebounce } from '@/base/hooks/useDebounce.ts'; import { useDebounce } from '@/base/hooks/useDebounce.ts';
import type { MangaCardProps } from '@/features/manga/Manga.types.ts'; import type { MangaCardProps } from '@/features/manga/Manga.types.ts';
import { EmptyView } from '@/base/components/feedback/EmptyView.tsx'; import { EmptyView } from '@/base/components/feedback/EmptyView.tsx';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import { LoadingPlaceholder } from '@/base/components/feedback/LoadingPlaceholder.tsx'; import { LoadingPlaceholder } from '@/base/components/feedback/LoadingPlaceholder.tsx';
import { BaseMangaGrid } from '@/features/manga/components/BaseMangaGrid.tsx'; import { BaseMangaGrid } from '@/features/manga/components/BaseMangaGrid.tsx';
@@ -254,7 +255,7 @@ export const SearchAll: React.FC = () => {
} = useMetadataServerSettings(); } = useMetadataServerSettings();
const { data, loading, error, refetch } = requestManager.useGetSourceList({ notifyOnNetworkStatusChange: true }); const { data, loading, error, refetch } = requestManager.useGetSourceList({ notifyOnNetworkStatusChange: true });
const sources = useMemo(() => data?.sources.nodes ?? [], [data?.sources.nodes]); const sources = data?.sources.nodes ?? STABLE_EMPTY_ARRAY;
const [sourceToLoadingStateMap, setSourceToLoadingStateMap] = useState<SourceToLoadingStateMap>(new Map()); const [sourceToLoadingStateMap, setSourceToLoadingStateMap] = useState<SourceToLoadingStateMap>(new Map());
const debouncedSourceToLoadingStateMap = useDebounce(sourceToLoadingStateMap, 500); const debouncedSourceToLoadingStateMap = useDebounce(sourceToLoadingStateMap, 500);
@@ -304,7 +305,7 @@ export const SearchAll: React.FC = () => {
selectedLanguages={shownLangs} selectedLanguages={shownLangs}
setSelectedLanguages={setShownLangs} setSelectedLanguages={setShownLangs}
languages={sourceLanguages} languages={sourceLanguages}
sources={sources ?? []} sources={sources}
/> />
</>, </>,
[shownLangs, setShownLangs, sourceLanguages, sources], [shownLangs, setShownLangs, sourceLanguages, sources],

View File

@@ -21,6 +21,7 @@ import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { ChapterHistoryCard } from '@/features/history/components/ChapterHistoryCard.tsx'; import { ChapterHistoryCard } from '@/features/history/components/ChapterHistoryCard.tsx';
import { Chapters } from '@/features/chapter/services/Chapters.ts'; import { Chapters } from '@/features/chapter/services/Chapters.ts';
import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts'; import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
export const History: React.FC = () => { export const History: React.FC = () => {
const { t } = useLingui(); const { t } = useLingui();
@@ -39,7 +40,7 @@ export const History: React.FC = () => {
}); });
const hasNextPage = !!chapterHistoryData?.chapters.pageInfo.hasNextPage; const hasNextPage = !!chapterHistoryData?.chapters.pageInfo.hasNextPage;
const endCursor = chapterHistoryData?.chapters.pageInfo.endCursor; const endCursor = chapterHistoryData?.chapters.pageInfo.endCursor;
const readEntries = chapterHistoryData?.chapters.nodes ?? []; const readEntries = chapterHistoryData?.chapters.nodes ?? STABLE_EMPTY_ARRAY;
const groupedHistory = useMemo( const groupedHistory = useMemo(
() => Object.entries(Chapters.groupByDate(readEntries, 'lastReadAt')), () => Object.entries(Chapters.groupByDate(readEntries, 'lastReadAt')),
[readEntries], [readEntries],

View File

@@ -50,6 +50,7 @@ import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
import { useAppAction } from '@/features/navigation-bar/hooks/useAppAction.ts'; import { useAppAction } from '@/features/navigation-bar/hooks/useAppAction.ts';
import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts';
import { SearchParam } from '@/base/Base.types.ts'; import { SearchParam } from '@/base/Base.types.ts';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
const TitleWithSizeTag = styled('span')({ const TitleWithSizeTag = styled('span')({
display: 'flex', display: 'flex',
@@ -82,7 +83,7 @@ export function Library() {
const tabsData = categoriesResponse?.categories.nodes.filter( const tabsData = categoriesResponse?.categories.nodes.filter(
(category) => category.id !== 0 || (category.id === 0 && category.mangas.totalCount), (category) => category.id !== 0 || (category.id === 0 && category.mangas.totalCount),
); );
const tabs = tabsData ?? []; const tabs = tabsData ?? STABLE_EMPTY_ARRAY;
const librarySizeResponse = requestManager.useGetMangas< const librarySizeResponse = requestManager.useGetMangas<
GetLibraryMangaCountQuery, GetLibraryMangaCountQuery,
@@ -102,7 +103,7 @@ export function Library() {
loading: mangaLoading, loading: mangaLoading,
refetch: refetchCategoryMangas, refetch: refetchCategoryMangas,
} = requestManager.useGetCategoryMangas(activeTab?.id, { skip: !activeTab, notifyOnNetworkStatusChange: true }); } = requestManager.useGetCategoryMangas(activeTab?.id, { skip: !activeTab, notifyOnNetworkStatusChange: true });
const categoryMangas = categoryMangaResponse?.mangas.nodes ?? []; const categoryMangas = categoryMangaResponse?.mangas.nodes ?? STABLE_EMPTY_ARRAY;
const { const {
visibleMangas: mangas, visibleMangas: mangas,
showFilteredOutMessage, showFilteredOutMessage,
@@ -127,6 +128,7 @@ export function Library() {
} = useSelectableCollection<MangaType['id'], string>(mangas.length, { } = useSelectableCollection<MangaType['id'], string>(mangas.length, {
itemIds: mangaIds, itemIds: mangaIds,
currentKey: activeTab?.id.toString(), currentKey: activeTab?.id.toString(),
initialState: undefined,
}); });
const handleSelect: typeof handleSelection = useCallback( const handleSelect: typeof handleSelection = useCallback(

View File

@@ -37,6 +37,7 @@ import type { MangaAction, MangaDownloadInfo, MangaIdInfo, MangaUnreadInfo } fro
import { MANGA_ACTION_TO_TRANSLATION } from '@/features/manga/Manga.constants.ts'; import { MANGA_ACTION_TO_TRANSLATION } from '@/features/manga/Manga.constants.ts';
import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts';
import { CategorySelect } from '@/features/category/components/CategorySelect.tsx'; import { CategorySelect } from '@/features/category/components/CategorySelect.tsx';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
type BaseProps = { onClose: () => void; setHideMenu: (hide: boolean) => void }; type BaseProps = { onClose: () => void; setHideMenu: (hide: boolean) => void };
@@ -65,7 +66,7 @@ export const MangaActionMenuItems = ({
const [isTrackDialogOpen, setIsTrackDialogOpen] = useState(false); const [isTrackDialogOpen, setIsTrackDialogOpen] = useState(false);
const isSingleMode = !!manga; const isSingleMode = !!manga;
const selectedMangas = passedSelectedMangas ?? []; const selectedMangas = passedSelectedMangas ?? STABLE_EMPTY_ARRAY;
const getMenuItemTitle = createGetMenuItemTitle(isSingleMode, MANGA_ACTION_TO_TRANSLATION); const getMenuItemTitle = createGetMenuItemTitle(isSingleMode, MANGA_ACTION_TO_TRANSLATION);
const shouldShowMenuItem = createShouldShowMenuItem(isSingleMode); const shouldShowMenuItem = createShouldShowMenuItem(isSingleMode);

View File

@@ -9,8 +9,9 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx'; import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx';
import type { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts'; import type { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
export const useAppAction = (action: NavbarContextType['action'], dependencies: any[] = []) => { export const useAppAction = (action: NavbarContextType['action'], dependencies: any[] = STABLE_EMPTY_ARRAY) => {
const { setAction } = useNavBarContext(); const { setAction } = useNavBarContext();
useEffect(() => { useEffect(() => {

View File

@@ -6,6 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
@@ -32,7 +33,7 @@ const BaseReaderNavBarDesktopChapterNavigation = ({
currentChapterNumber, currentChapterNumber,
previousChapter, previousChapter,
nextChapter, nextChapter,
chapters = [], chapters = STABLE_EMPTY_ARRAY,
readerThemeDirection, readerThemeDirection,
}: { }: {
currentChapterId: ChapterIdInfo['id'] | undefined; currentChapterId: ChapterIdInfo['id'] | undefined;

View File

@@ -6,6 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts';
import FilterListIcon from '@mui/icons-material/FilterList'; import FilterListIcon from '@mui/icons-material/FilterList';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
@@ -159,7 +160,7 @@ export function Options({ sourceFilter, group, updateFilterValue, update }: IFil
} }
export function SourceOptions({ export function SourceOptions({
savedSearches = {}, savedSearches = STABLE_EMPTY_OBJECT,
selectSavedSearch, selectSavedSearch,
updateSavedSearches, updateSavedSearches,
sourceFilter, sourceFilter,

View File

@@ -52,6 +52,7 @@ import { GridLayout, SearchParam } from '@/base/Base.types';
import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { Sources } from '@/features/source/services/Sources.ts'; import { Sources } from '@/features/source/services/Sources.ts';
import { STABLE_EMPTY_ARRAY, STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts';
import { useAppTitleAndAction } from '@/features/navigation-bar/hooks/useAppTitleAndAction.ts'; import { useAppTitleAndAction } from '@/features/navigation-bar/hooks/useAppTitleAndAction.ts';
import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx'; import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx';
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx'; import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
@@ -219,7 +220,7 @@ export function SourceMangas() {
useLocation<{ useLocation<{
contentType: SourceContentType; contentType: SourceContentType;
clearCache: boolean; clearCache: boolean;
}>().state ?? {}; }>().state ?? STABLE_EMPTY_OBJECT;
const { const {
settings: { hideLibraryEntries }, settings: { hideLibraryEntries },
@@ -288,7 +289,7 @@ export function SourceMangas() {
{ data, error, isLoading: loading, size: lastPageNum, abortRequest, filteredOutAllItemsOfFetchedPage }, { data, error, isLoading: loading, size: lastPageNum, abortRequest, filteredOutAllItemsOfFetchedPage },
] = useSourceManga(sourceId, contentType, query, filtersToApply, 1, hideLibraryEntries); ] = useSourceManga(sourceId, contentType, query, filtersToApply, 1, hideLibraryEntries);
currentAbortRequest.current = abortRequest; currentAbortRequest.current = abortRequest;
const mangas = data?.fetchSourceManga?.mangas ?? []; const mangas = data?.fetchSourceManga?.mangas ?? STABLE_EMPTY_ARRAY;
const hasNextPage = !!data?.fetchSourceManga?.hasNextPage; const hasNextPage = !!data?.fetchSourceManga?.hasNextPage;
const isLoading = loading || (filteredOutAllItemsOfFetchedPage && hasNextPage); const isLoading = loading || (filteredOutAllItemsOfFetchedPage && hasNextPage);
const { data: sourceData } = requestManager.useGetSource<GetSourceBrowseQuery, GetSourceBrowseQueryVariables>( const { data: sourceData } = requestManager.useGetSource<GetSourceBrowseQuery, GetSourceBrowseQueryVariables>(
@@ -297,7 +298,7 @@ export function SourceMangas() {
); );
const source = sourceData?.source; const source = sourceData?.source;
const filters = source?.filters ?? []; const filters = source?.filters ?? STABLE_EMPTY_ARRAY;
const { savedSearches = {} } = useGetSourceMetadata(source ?? DEFAULT_SOURCE); const { savedSearches = {} } = useGetSourceMetadata(source ?? DEFAULT_SOURCE);
const updateSourceMetadata = createUpdateSourceMetadata<'savedSearches'>(source ?? { id: '-1' }, (e) => const updateSourceMetadata = createUpdateSourceMetadata<'savedSearches'>(source ?? { id: '-1' }, (e) =>
makeToast(t`Failed to save changes`, 'error', getErrorMessage(e)), makeToast(t`Failed to save changes`, 'error', getErrorMessage(e)),

View File

@@ -28,6 +28,7 @@ import { makeToast } from '@/base/utils/Toast.ts';
import type { PreferenceProps } from '@/features/source/Source.types.ts'; import type { PreferenceProps } from '@/features/source/Source.types.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts'; import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
function getPrefComponent(type: string) { function getPrefComponent(type: string) {
switch (type) { switch (type) {
@@ -58,7 +59,7 @@ export function SourceConfigure() {
>(GET_SOURCE_SETTINGS, sourceId, { >(GET_SOURCE_SETTINGS, sourceId, {
notifyOnNetworkStatusChange: true, notifyOnNetworkStatusChange: true,
}); });
const sourcePreferences = data?.source.preferences ?? []; const sourcePreferences = data?.source.preferences ?? STABLE_EMPTY_ARRAY;
const updateValue = const updateValue =
(position: number): PreferenceProps['updateValue'] => (position: number): PreferenceProps['updateValue'] =>

View File

@@ -24,6 +24,7 @@ import type { MangaIdInfo } from '@/features/manga/Manga.types.ts';
import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { EmptyView } from '@/base/components/feedback/EmptyView.tsx'; import { EmptyView } from '@/base/components/feedback/EmptyView.tsx';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
const getTrackerMode = (id: number, trackersInUse: number[], searchModeForTracker?: number): TrackerMode => { const getTrackerMode = (id: number, trackersInUse: number[], searchModeForTracker?: number): TrackerMode => {
if (id === searchModeForTracker) { if (id === searchModeForTracker) {
@@ -46,13 +47,13 @@ export const TrackManga = ({ manga }: { manga: MangaIdInfo & Pick<MangaType, 'ti
const trackerList = requestManager.useGetTrackerList<GetTrackersBindQuery>(GET_TRACKERS_BIND, { const trackerList = requestManager.useGetTrackerList<GetTrackersBindQuery>(GET_TRACKERS_BIND, {
notifyOnNetworkStatusChange: true, notifyOnNetworkStatusChange: true,
}); });
const trackers = trackerList.data?.trackers.nodes ?? []; const trackers = trackerList.data?.trackers.nodes ?? STABLE_EMPTY_ARRAY;
const mangaTrackRecordsList = requestManager.useGetManga<GetMangaTrackRecordsQuery>( const mangaTrackRecordsList = requestManager.useGetManga<GetMangaTrackRecordsQuery>(
GET_MANGA_TRACK_RECORDS, GET_MANGA_TRACK_RECORDS,
manga.id, manga.id,
); );
const mangaTrackRecords = mangaTrackRecordsList.data?.manga.trackRecords.nodes ?? []; const mangaTrackRecords = mangaTrackRecordsList.data?.manga.trackRecords.nodes ?? STABLE_EMPTY_ARRAY;
const loggedInTrackers = Trackers.getLoggedIn(trackers); const loggedInTrackers = Trackers.getLoggedIn(trackers);
const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackRecords, trackers)); const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackRecords, trackers));

View File

@@ -27,6 +27,7 @@ import type { GetTrackersSettingsQuery } from '@/lib/graphql/generated/graphql.t
import type { MetadataTrackingSettings } from '@/features/tracker/Tracker.types.ts'; import type { MetadataTrackingSettings } from '@/features/tracker/Tracker.types.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts'; import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
export const TrackingSettings = () => { export const TrackingSettings = () => {
const { t } = useLingui(); const { t } = useLingui();
@@ -50,7 +51,7 @@ export const TrackingSettings = () => {
} = requestManager.useGetTrackerList<GetTrackersSettingsQuery>(GET_TRACKERS_SETTINGS, { } = requestManager.useGetTrackerList<GetTrackersSettingsQuery>(GET_TRACKERS_SETTINGS, {
notifyOnNetworkStatusChange: true, notifyOnNetworkStatusChange: true,
}); });
const trackers = data?.trackers.nodes ?? []; const trackers = data?.trackers.nodes ?? STABLE_EMPTY_ARRAY;
const loading = areMetadataServerSettingsLoading || areTrackersLoading; const loading = areMetadataServerSettingsLoading || areTrackersLoading;
const error = metadataServerSettingsError ?? trackersError; const error = metadataServerSettingsError ?? trackersError;

View File

@@ -25,6 +25,7 @@ import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx';
import { Chapters } from '@/features/chapter/services/Chapters.ts'; import { Chapters } from '@/features/chapter/services/Chapters.ts';
import { useAppTitleAndAction } from '@/features/navigation-bar/hooks/useAppTitleAndAction.ts'; import { useAppTitleAndAction } from '@/features/navigation-bar/hooks/useAppTitleAndAction.ts';
import { GROUPED_VIRTUOSO_Z_INDEX } from '@/lib/virtuoso/Virtuoso.constants.ts'; import { GROUPED_VIRTUOSO_Z_INDEX } from '@/lib/virtuoso/Virtuoso.constants.ts';
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
export const Updates: React.FC = () => { export const Updates: React.FC = () => {
const { t } = useLingui(); const { t } = useLingui();
@@ -42,7 +43,7 @@ export const Updates: React.FC = () => {
}); });
const hasNextPage = !!chapterUpdateData?.chapters.pageInfo.hasNextPage; const hasNextPage = !!chapterUpdateData?.chapters.pageInfo.hasNextPage;
const endCursor = chapterUpdateData?.chapters.pageInfo.endCursor; const endCursor = chapterUpdateData?.chapters.pageInfo.endCursor;
const updateEntries = chapterUpdateData?.chapters.nodes ?? []; const updateEntries = chapterUpdateData?.chapters.nodes ?? STABLE_EMPTY_ARRAY;
const groupedUpdates = useMemo( const groupedUpdates = useMemo(
() => Object.entries(Chapters.groupByDate(updateEntries, 'fetchedAt')), () => Object.entries(Chapters.groupByDate(updateEntries, 'fetchedAt')),
[updateEntries], [updateEntries],