Files
suwayomi-material-you-webui/src/components/library/LibraryMangaGrid.tsx
T

155 lines
5.0 KiB
TypeScript
Raw Normal View History

2021-10-29 20:11:23 +02:00
/*
* 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/.
*/
2023-06-17 16:50:17 +02:00
import React, { useEffect, useMemo } from 'react';
2022-04-07 12:53:14 +02:00
import { StringParam, useQueryParam } from 'use-query-params';
2023-03-23 13:59:32 +01:00
import { useTranslation } from 'react-i18next';
2023-09-06 21:47:13 +02:00
import { LibrarySortMode, NullAndUndefined } from '@/typings';
2023-06-05 01:42:39 +02:00
import { useSearchSettings } from '@/util/searchSettings';
import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext';
import MangaGrid from '@/components/MangaGrid';
2023-09-06 21:47:13 +02:00
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
2021-10-29 20:11:23 +02:00
2023-09-06 21:47:13 +02:00
const unreadFilter = (unread: NullAndUndefined<boolean>, { unreadCount }: MangaType): boolean => {
2021-10-29 20:11:23 +02:00
switch (unread) {
case true:
return !!unreadCount && unreadCount >= 1;
case false:
return unreadCount === 0;
default:
return true;
}
2022-11-24 21:04:30 +01:00
};
2021-10-29 20:11:23 +02:00
2023-09-06 21:47:13 +02:00
const downloadedFilter = (downloaded: NullAndUndefined<boolean>, { downloadCount }: MangaType): boolean => {
switch (downloaded) {
case true:
return !!downloadCount && downloadCount >= 1;
case false:
return downloadCount === 0;
default:
return true;
}
2022-11-24 21:04:30 +01:00
};
2023-09-06 21:47:13 +02:00
const queryFilter = (query: NullAndUndefined<string>, { title }: MangaType): boolean => {
2021-10-31 12:45:34 +01:00
if (!query) return true;
return title.toLowerCase().includes(query.toLowerCase());
2022-11-24 21:04:30 +01:00
};
2021-10-31 12:45:34 +01:00
2023-09-06 21:47:13 +02:00
const queryGenreFilter = (query: NullAndUndefined<string>, { genre }: MangaType): boolean => {
2023-02-16 11:26:09 +05:30
if (!query) return true;
const queries = query.split(',').map((str) => str.toLowerCase().trim());
return queries.every((element) => genre.map((el) => el.toLowerCase()).includes(element));
};
2022-11-24 21:04:30 +01:00
const filterManga = (
2023-09-06 21:47:13 +02:00
mangas: MangaType[],
2022-11-24 21:04:30 +01:00
query: NullAndUndefined<string>,
unread: NullAndUndefined<boolean>,
downloaded: NullAndUndefined<boolean>,
ignoreFilters: boolean,
2023-09-06 21:47:13 +02:00
): MangaType[] =>
2023-03-11 19:12:43 +01:00
mangas.filter((manga) => {
const ignoreFiltersWhileSearching = ignoreFilters && query?.length;
const matchesSearch = queryFilter(query, manga) || queryGenreFilter(query, manga);
const matchesFilters =
ignoreFiltersWhileSearching || (downloadedFilter(downloaded, manga) && unreadFilter(unread, manga));
return matchesSearch && matchesFilters;
});
2022-04-07 12:53:14 +02:00
2023-09-06 21:47:13 +02:00
const sortByUnread = (a: MangaType, b: MangaType): number => (a.unreadCount ?? 0) - (b.unreadCount ?? 0);
2021-10-29 20:11:23 +02:00
2023-09-06 21:47:13 +02:00
const sortByTitle = (a: MangaType, b: MangaType): number => a.title.localeCompare(b.title);
2022-02-24 06:16:21 +00:00
2023-09-06 21:47:13 +02:00
const sortByDateAdded = (a: MangaType, b: MangaType): number => Number(a.inLibraryAt) - Number(b.inLibraryAt);
2022-02-24 06:16:21 +00:00
2023-09-06 21:47:13 +02:00
const sortByLastRead = (a: MangaType, b: MangaType): number =>
Number(b.lastReadChapter?.lastReadAt ?? 0) - Number(a.lastReadChapter?.lastReadAt ?? 0);
2023-03-05 12:26:50 +05:30
2022-11-24 21:04:30 +01:00
const sortManga = (
2023-09-06 21:47:13 +02:00
manga: MangaType[],
2022-11-24 21:04:30 +01:00
sort: NullAndUndefined<LibrarySortMode>,
desc: NullAndUndefined<boolean>,
2023-09-06 21:47:13 +02:00
): MangaType[] => {
2022-11-24 21:04:30 +01:00
const result = [...manga];
2022-02-24 06:16:21 +00:00
2022-11-24 21:04:30 +01:00
switch (sort) {
2023-02-06 10:06:33 +01:00
case 'sortAlph':
result.sort(sortByTitle);
break;
2023-03-04 22:21:39 +05:30
case 'sortDateAdded':
result.sort(sortByDateAdded);
2023-02-06 10:06:33 +01:00
break;
case 'sortToRead':
result.sort(sortByUnread);
break;
2023-03-05 12:26:50 +05:30
case 'sortLastRead':
result.sort(sortByLastRead);
break;
2023-02-06 10:06:33 +01:00
default:
break;
2022-11-24 21:04:30 +01:00
}
2022-02-24 06:16:21 +00:00
2022-11-24 21:04:30 +01:00
if (desc === true) {
result.reverse();
}
2021-10-29 20:11:23 +02:00
2022-11-24 21:04:30 +01:00
return result;
};
interface LibraryMangaGridProps {
2023-09-06 21:47:13 +02:00
mangas: MangaType[];
isLoading: boolean;
message?: string;
}
const LibraryMangaGrid: React.FC<LibraryMangaGridProps & { lastLibraryUpdate: number }> = ({
2023-02-06 10:06:33 +01:00
mangas,
isLoading,
message,
lastLibraryUpdate,
2022-11-24 21:04:30 +01:00
}) => {
2023-03-23 13:59:32 +01:00
const { t } = useTranslation();
2022-04-07 12:53:14 +02:00
const [query] = useQueryParam('query', StringParam);
2022-11-24 09:41:03 +01:00
const { options } = useLibraryOptionsContext();
const { unread, downloaded } = options;
const { settings } = useSearchSettings();
const filteredMangas = useMemo(
() => filterManga(mangas, query, unread, downloaded, settings.ignoreFilters),
[mangas, query, unread, downloaded, settings.ignoreFilters],
);
const sortedMangas = useMemo(
() => sortManga(filteredMangas, options.sorts, options.sortDesc),
[filteredMangas, lastLibraryUpdate, options.sorts, options.sortDesc],
);
2022-11-24 21:04:30 +01:00
2023-02-06 10:06:33 +01:00
const showFilteredOutMessage =
(unread != null || downloaded != null || query) && filteredMangas.length === 0 && mangas.length > 0;
useEffect(() => {
window.scrollTo(0, 0);
}, [filteredMangas]);
2021-10-29 20:11:23 +02:00
return (
<MangaGrid
2023-06-17 16:50:17 +02:00
mangas={sortedMangas}
2021-10-29 20:11:23 +02:00
isLoading={isLoading}
2023-06-17 16:50:17 +02:00
hasNextPage={false}
loadMore={() => undefined}
2023-03-23 13:59:32 +01:00
message={showFilteredOutMessage ? t('library.error.label.no_matches') : message}
2022-03-06 16:45:25 +00:00
gridLayout={options.gridLayout}
2021-10-29 20:11:23 +02:00
/>
);
2022-11-24 21:04:30 +01:00
};
export default LibraryMangaGrid;