Refactor and fix sorting in library (#197)

This commit is contained in:
Valter Martinek
2022-11-24 21:04:30 +01:00
committed by GitHub
parent 154b357c40
commit 62816338f3
5 changed files with 75 additions and 76 deletions

View File

@@ -73,6 +73,7 @@ interface IProps {
manga: IMangaCard manga: IMangaCard
gridLayout: number | undefined gridLayout: number | undefined
dimensions: number dimensions: number
inLibraryIndicator?: boolean
} }
const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref) => { const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref) => {
const { const {
@@ -82,6 +83,7 @@ const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref)
}, },
gridLayout, gridLayout,
dimensions, dimensions,
inLibraryIndicator,
} = props; } = props;
const { options: { showUnreadBadge, showDownloadBadge } } = useLibraryOptionsContext(); const { options: { showUnreadBadge, showDownloadBadge } } = useLibraryOptionsContext();
@@ -119,7 +121,7 @@ const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref)
> >
<BadgeContainer> <BadgeContainer>
{inLibrary && ( {inLibraryIndicator && inLibrary && (
<Typography <Typography
sx={{ backgroundColor: 'primary.dark', zIndex: '1' }} sx={{ backgroundColor: 'primary.dark', zIndex: '1' }}
> >
@@ -145,7 +147,7 @@ const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref)
<SpinnerImage <SpinnerImage
alt={title} alt={title}
src={`${serverAddress}${thumbnailUrl}?useCache=${useCache}`} src={`${serverAddress}${thumbnailUrl}?useCache=${useCache}`}
imgStyle={inLibrary imgStyle={inLibraryIndicator && inLibrary
? { ? {
height: '100%', height: '100%',
width: '100%', width: '100%',

View File

@@ -26,12 +26,14 @@ export interface IMangaGridProps{
gridLayout?: number | undefined gridLayout?: number | undefined
horisontal?: boolean | undefined horisontal?: boolean | undefined
noFaces?: boolean | undefined noFaces?: boolean | undefined
inLibraryIndicator?: boolean
} }
export default function MangaGrid(props: IMangaGridProps) { const MangaGrid: React.FC<IMangaGridProps> = (props) => {
const { const {
mangas, isLoading, message, messageExtra, mangas, isLoading, message, messageExtra,
hasNextPage, lastPageNum, setLastPageNum, gridLayout, horisontal, noFaces, hasNextPage, lastPageNum, setLastPageNum, gridLayout, horisontal, noFaces,
inLibraryIndicator,
} = props; } = props;
let mapped; let mapped;
const lastManga = useRef<HTMLDivElement>(null); const lastManga = useRef<HTMLDivElement>(null);
@@ -90,27 +92,16 @@ export default function MangaGrid(props: IMangaGridProps) {
); );
} }
} else { } else {
mapped = mangas.map((it, idx) => { mapped = mangas.map((it, idx) => (
if (idx === mangas.length - 1) {
return (
<MangaCard <MangaCard
key={it.id} key={it.id}
manga={it} manga={it}
ref={lastManga} ref={idx === mangas.length - 1 ? lastManga : undefined}
gridLayout={gridLayout} gridLayout={gridLayout}
dimensions={dimensions} dimensions={dimensions}
inLibraryIndicator={inLibraryIndicator}
/> />
); ));
}
return (
<MangaCard
key={it.id}
manga={it}
gridLayout={gridLayout}
dimensions={dimensions}
/>
);
});
} }
return ( return (
@@ -135,9 +126,11 @@ export default function MangaGrid(props: IMangaGridProps) {
</Grid> </Grid>
</div> </div>
); );
} };
MangaGrid.defaultProps = { MangaGrid.defaultProps = {
message: '', message: '',
messageExtra: undefined, messageExtra: undefined,
}; };
export default MangaGrid;

View File

@@ -6,14 +6,14 @@
* 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 React from 'react'; import React, { useMemo } from 'react';
import MangaGrid, { IMangaGridProps } from 'components/MangaGrid'; import MangaGrid, { IMangaGridProps } from 'components/MangaGrid';
import { useLibraryOptionsContext } from 'components/context/LibraryOptionsContext'; import { useLibraryOptionsContext } from 'components/context/LibraryOptionsContext';
import { StringParam, useQueryParam } from 'use-query-params'; import { StringParam, useQueryParam } from 'use-query-params';
const FILTERED_OUT_MESSAGE = 'There are no Manga matching this filter'; const FILTERED_OUT_MESSAGE = 'There are no Manga matching this filter';
function unreadFilter(unread: NullAndUndefined<boolean>, { unreadCount }: IMangaCard): boolean { const unreadFilter = (unread: NullAndUndefined<boolean>, { unreadCount }: IMangaCard): boolean => {
switch (unread) { switch (unread) {
case true: case true:
return !!unreadCount && unreadCount >= 1; return !!unreadCount && unreadCount >= 1;
@@ -22,10 +22,10 @@ function unreadFilter(unread: NullAndUndefined<boolean>, { unreadCount }: IManga
default: default:
return true; return true;
} }
} };
function downloadedFilter(downloaded: NullAndUndefined<boolean>, const downloadedFilter = (downloaded: NullAndUndefined<boolean>,
{ downloadCount }: IMangaCard): boolean { { downloadCount }: IMangaCard): boolean => {
switch (downloaded) { switch (downloaded) {
case true: case true:
return !!downloadCount && downloadCount >= 1; return !!downloadCount && downloadCount >= 1;
@@ -34,70 +34,70 @@ function downloadedFilter(downloaded: NullAndUndefined<boolean>,
default: default:
return true; return true;
} }
} };
function queryFilter(query: NullAndUndefined<string>, { title }: IMangaCard): boolean { const queryFilter = (query: NullAndUndefined<string>, { title }: IMangaCard): boolean => {
if (!query) return true; if (!query) return true;
return title.toLowerCase().includes(query.toLowerCase()); return title.toLowerCase().includes(query.toLowerCase());
} };
function filterManga(mangas: IMangaCard[]): IMangaCard[] { const filterManga = (
const [query] = useQueryParam('query', StringParam); manga: IMangaCard[],
query: NullAndUndefined<string>,
unread: NullAndUndefined<boolean>,
downloaded: NullAndUndefined<boolean>,
): IMangaCard[] => manga.filter((m) => downloadedFilter(downloaded, m)
&& unreadFilter(unread, m)
&& queryFilter(query, m));
const { options: { downloaded, unread } } = useLibraryOptionsContext(); const sortByUnread = (a: IMangaCard, b: IMangaCard): number =>
return mangas // eslint-disable-next-line implicit-arrow-linebreak
.filter((manga) => downloadedFilter(downloaded, manga) (a.unreadCount ?? 0) - (b.unreadCount ?? 0);
&& unreadFilter(unread, manga)
&& queryFilter(query, manga));
}
function toReadSort(a: IMangaCard, b: IMangaCard): number { const sortByTitle = (a: IMangaCard, b: IMangaCard): number => a.title.localeCompare(b.title);
if (!a.unreadCount) return -1;
if (!b.unreadCount) return 1;
return a.unreadCount > b.unreadCount ? 1 : -1;
}
function toSortAlph(a: IMangaCard, b: IMangaCard): number { const sortById = (a: IMangaCard, b: IMangaCard): number => a.id - b.id;
return a.title < b.title ? 1 : -1;
}
function toSortID(a: IMangaCard, b: IMangaCard): number { const sortManga = (
return a.id > b.id ? 1 : -1; manga: IMangaCard[],
} sort: NullAndUndefined<LibrarySortMode>,
desc: NullAndUndefined<boolean>,
): IMangaCard[] => {
const result = [...manga];
function sortManga(mangas: IMangaCard[]): IMangaCard[] { switch (sort) {
const { options: { sorts, sortDesc } } = useLibraryOptionsContext(); case 'sortAlph': result.sort(sortByTitle); break;
return (sorts === 'sortID' || sorts === undefined) && !sortDesc ? mangas : mangas.sort((a, b) => { case 'sortID': result.sort(sortById); break;
const c = sortDesc === true ? b : a; case 'sortToRead': result.sort(sortByUnread); break;
const d = sortDesc === true ? a : b; default: break;
if (sorts === 'sortToRead') { return toReadSort(c, d); } }
if (sorts === 'sortAlph') { return toSortAlph(c, d); }
if (sorts === 'sortID' || sorts === undefined) { return toSortID(c, d); }
return 1;
});
}
export default function LibraryMangaGrid(props: IMangaGridProps) { if (desc === true) {
const { result.reverse();
}
return result;
};
const LibraryMangaGrid: React.FC<IMangaGridProps> = ({
mangas, isLoading, hasNextPage, lastPageNum, setLastPageNum, message, mangas, isLoading, hasNextPage, lastPageNum, setLastPageNum, message,
} = props; }) => {
const [query] = useQueryParam('query', StringParam); const [query] = useQueryParam('query', StringParam);
const { options } = useLibraryOptionsContext(); const { options } = useLibraryOptionsContext();
const { unread, downloaded } = options; const { unread, downloaded } = options;
const filteredManga = filterManga(mangas);
const sortedManga = sortManga(filteredManga); const sortedManga = useMemo(() => sortManga(mangas, options.sorts, options.sortDesc),
const DoneManga = sortedManga.map((ele) => { [mangas, options.sorts, options.sortDesc]);
// eslint-disable-next-line no-param-reassign
ele.inLibrary = undefined; const filteredManga = useMemo(() => filterManga(sortedManga, query, unread, downloaded),
return ele; [sortedManga, query, unread, downloaded]);
});
const showFilteredOutMessage = (unread != null || downloaded != null || query) const showFilteredOutMessage = (unread != null || downloaded != null || query)
&& filteredManga.length === 0 && mangas.length > 0; && filteredManga.length === 0 && mangas.length > 0;
return ( return (
<MangaGrid <MangaGrid
mangas={DoneManga} mangas={filteredManga}
isLoading={isLoading} isLoading={isLoading}
hasNextPage={hasNextPage} hasNextPage={hasNextPage}
lastPageNum={lastPageNum} lastPageNum={lastPageNum}
@@ -106,4 +106,6 @@ export default function LibraryMangaGrid(props: IMangaGridProps) {
gridLayout={options.gridLayout} gridLayout={options.gridLayout}
/> />
); );
} };
export default LibraryMangaGrid;

View File

@@ -34,6 +34,7 @@ export default function SourceMangaGrid(props: IMangaGridProps) {
message={showFilteredOutMessage ? FILTERED_OUT_MESSAGE : message} message={showFilteredOutMessage ? FILTERED_OUT_MESSAGE : message}
messageExtra={messageExtra} messageExtra={messageExtra}
gridLayout={gridLayout} gridLayout={gridLayout}
inLibraryIndicator
/> />
); );
} }

View File

@@ -212,6 +212,7 @@ export default function SearchAll() {
horisontal horisontal
noFaces noFaces
message={fetched[id] ? 'No manga was found!' : undefined} message={fetched[id] ? 'No manga was found!' : undefined}
inLibraryIndicator
/> />
</> </>
) )