Apply filters when searching in SourceMangas (#545)
This commit is contained in:
@@ -73,7 +73,6 @@ export enum SourceContentType {
|
|||||||
POPULAR,
|
POPULAR,
|
||||||
LATEST,
|
LATEST,
|
||||||
SEARCH,
|
SEARCH,
|
||||||
FILTER,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPos {
|
interface IPos {
|
||||||
@@ -86,8 +85,7 @@ interface IPos {
|
|||||||
const SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY: { [contentType in SourceContentType]: TranslationKey } = {
|
const SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY: { [contentType in SourceContentType]: TranslationKey } = {
|
||||||
[SourceContentType.POPULAR]: 'manga.error.label.no_mangas_found',
|
[SourceContentType.POPULAR]: 'manga.error.label.no_mangas_found',
|
||||||
[SourceContentType.LATEST]: 'manga.error.label.no_mangas_found',
|
[SourceContentType.LATEST]: 'manga.error.label.no_mangas_found',
|
||||||
[SourceContentType.FILTER]: 'manga.error.label.no_matches',
|
[SourceContentType.SEARCH]: 'manga.error.label.no_matches',
|
||||||
[SourceContentType.SEARCH]: 'manga.error.label.no_mangas_found',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUniqueMangas = (mangas: TPartialManga[]): TPartialManga[] => {
|
const getUniqueMangas = (mangas: TPartialManga[]): TPartialManga[] => {
|
||||||
@@ -128,12 +126,9 @@ const useSourceManga = (
|
|||||||
result = requestManager.useGetSourceLatestMangas(sourceId, initialPages);
|
result = requestManager.useGetSourceLatestMangas(sourceId, initialPages);
|
||||||
break;
|
break;
|
||||||
case SourceContentType.SEARCH:
|
case SourceContentType.SEARCH:
|
||||||
result = requestManager.useSourceSearch(sourceId, searchTerm ?? '', undefined, initialPages);
|
|
||||||
break;
|
|
||||||
case SourceContentType.FILTER:
|
|
||||||
result = requestManager.useSourceSearch(
|
result = requestManager.useSourceSearch(
|
||||||
sourceId,
|
sourceId,
|
||||||
undefined,
|
searchTerm ?? '',
|
||||||
filters.map((filter) => {
|
filters.map((filter) => {
|
||||||
const { position, state, group } = filter;
|
const { position, state, group } = filter;
|
||||||
|
|
||||||
@@ -205,6 +200,7 @@ export function SourceMangas() {
|
|||||||
const { sourceId } = useParams<{ sourceId: string }>();
|
const { sourceId } = useParams<{ sourceId: string }>();
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { search } = useLocation();
|
||||||
const {
|
const {
|
||||||
contentType: currentLocationContentType = SourceContentType.POPULAR,
|
contentType: currentLocationContentType = SourceContentType.POPULAR,
|
||||||
filtersToApply: currentLocationFiltersToApply = [],
|
filtersToApply: currentLocationFiltersToApply = [],
|
||||||
@@ -213,10 +209,17 @@ export function SourceMangas() {
|
|||||||
contentType: SourceContentType;
|
contentType: SourceContentType;
|
||||||
filtersToApply: IPos[];
|
filtersToApply: IPos[];
|
||||||
clearCache: boolean;
|
clearCache: boolean;
|
||||||
|
search: string;
|
||||||
}>().state ?? {};
|
}>().state ?? {};
|
||||||
|
|
||||||
useSetDefaultBackTo('sources');
|
useSetDefaultBackTo('sources');
|
||||||
|
|
||||||
|
const [isFirstRender, setIsFirstRender] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsFirstRender(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const { options } = useLibraryOptionsContext();
|
const { options } = useLibraryOptionsContext();
|
||||||
const [query] = useQueryParam('query', StringParam);
|
const [query] = useQueryParam('query', StringParam);
|
||||||
const [dialogFiltersToApply, setDialogFiltersToApply] = useState<IPos[]>(currentLocationFiltersToApply);
|
const [dialogFiltersToApply, setDialogFiltersToApply] = useState<IPos[]>(currentLocationFiltersToApply);
|
||||||
@@ -250,9 +253,20 @@ export function SourceMangas() {
|
|||||||
) : undefined;
|
) : undefined;
|
||||||
|
|
||||||
const updateContentType = useCallback(
|
const updateContentType = useCallback(
|
||||||
(newContentType: SourceContentType, updateLocationState: boolean = true) => {
|
(
|
||||||
|
newContentType: SourceContentType,
|
||||||
|
{ updateLocationState = true, search: newSearch }: { updateLocationState?: boolean; search?: string } = {},
|
||||||
|
) => {
|
||||||
if (updateLocationState) {
|
if (updateLocationState) {
|
||||||
navigate('', { replace: true, state: { contentType: newContentType } });
|
navigate(
|
||||||
|
{ pathname: '', search: newSearch },
|
||||||
|
{
|
||||||
|
replace: true,
|
||||||
|
state: {
|
||||||
|
contentType: newContentType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentType(newContentType);
|
setContentType(newContentType);
|
||||||
@@ -263,22 +277,26 @@ export function SourceMangas() {
|
|||||||
|
|
||||||
const updateLocationFilters = useCallback(
|
const updateLocationFilters = useCallback(
|
||||||
(updatedFilters: IPos[]) => {
|
(updatedFilters: IPos[]) => {
|
||||||
if (contentType === SourceContentType.FILTER) {
|
if (contentType === SourceContentType.SEARCH) {
|
||||||
navigate('', { replace: true, state: { contentType, filtersToApply: updatedFilters } });
|
navigate(
|
||||||
|
{ pathname: '', search },
|
||||||
|
{
|
||||||
|
replace: true,
|
||||||
|
state: {
|
||||||
|
contentType,
|
||||||
|
filtersToApply: updatedFilters,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[contentType],
|
[contentType, search],
|
||||||
);
|
);
|
||||||
|
|
||||||
const isSearchTermAvailable = searchTerm && query?.length;
|
const isSearchTermAvailable = searchTerm && query?.length;
|
||||||
const setSearchContentType = isSearchTermAvailable && contentType !== SourceContentType.SEARCH;
|
const setSearchContentType = isSearchTermAvailable && contentType !== SourceContentType.SEARCH;
|
||||||
if (setSearchContentType) {
|
if (setSearchContentType) {
|
||||||
updateContentType(SourceContentType.SEARCH, false);
|
updateContentType(SourceContentType.SEARCH, { search });
|
||||||
}
|
|
||||||
|
|
||||||
const closeSearch = !query?.length && contentType === SourceContentType.SEARCH;
|
|
||||||
if (closeSearch) {
|
|
||||||
updateContentType(currentLocationContentType, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadMore = useCallback(() => {
|
const loadMore = useCallback(() => {
|
||||||
@@ -294,7 +312,7 @@ export function SourceMangas() {
|
|||||||
setFiltersToApply([]);
|
setFiltersToApply([]);
|
||||||
updateLocationFilters([]);
|
updateLocationFilters([]);
|
||||||
setResetScrollPosition(true);
|
setResetScrollPosition(true);
|
||||||
}, [sourceId, contentType]);
|
}, [sourceId, contentType, updateLocationFilters]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!clearCache) {
|
if (!clearCache) {
|
||||||
@@ -315,17 +333,16 @@ export function SourceMangas() {
|
|||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => () => {
|
() => () => {
|
||||||
if (contentType !== SourceContentType.SEARCH) {
|
if (contentType !== SourceContentType.SEARCH || isFirstRender) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// INFO:
|
// INFO:
|
||||||
// with strict mode + dev mode the first request will be aborted. due to using SWR there won't be an
|
// with strict mode + dev mode the first request will be aborted. due to using SWR there won't be an
|
||||||
// immediate second request since it's the same key. instead the "second" request will be the error handling of SWR
|
// immediate second request since it's the same key. instead the "second" request will be the error handling of SWR
|
||||||
abortRequest(new Error(`SourceMangas(${sourceId}): search string changed`));
|
abortRequest(new Error(`SourceMangas(${sourceId}): search string changed`));
|
||||||
setResetScrollPosition(true);
|
setResetScrollPosition(true);
|
||||||
},
|
},
|
||||||
[searchTerm, contentType],
|
[searchTerm],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -381,9 +398,9 @@ export function SourceMangas() {
|
|||||||
</ContentTypeButton>
|
</ContentTypeButton>
|
||||||
) : null}
|
) : null}
|
||||||
<ContentTypeButton
|
<ContentTypeButton
|
||||||
variant={contentType === SourceContentType.FILTER ? 'contained' : 'outlined'}
|
variant={contentType === SourceContentType.SEARCH ? 'contained' : 'outlined'}
|
||||||
startIcon={<FilterListIcon />}
|
startIcon={<FilterListIcon />}
|
||||||
onClick={() => updateContentType(SourceContentType.FILTER)}
|
onClick={() => updateContentType(SourceContentType.SEARCH)}
|
||||||
>
|
>
|
||||||
{t('global.button.filter')}
|
{t('global.button.filter')}
|
||||||
</ContentTypeButton>
|
</ContentTypeButton>
|
||||||
@@ -398,7 +415,7 @@ export function SourceMangas() {
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
gridLayout={options.SourcegridLayout}
|
gridLayout={options.SourcegridLayout}
|
||||||
/>
|
/>
|
||||||
{contentType === SourceContentType.FILTER && (
|
{contentType === SourceContentType.SEARCH && (
|
||||||
<SourceOptions
|
<SourceOptions
|
||||||
sourceFilter={filters}
|
sourceFilter={filters}
|
||||||
updateFilterValue={setDialogFiltersToApply}
|
updateFilterValue={setDialogFiltersToApply}
|
||||||
|
|||||||
Reference in New Issue
Block a user