Skip to content

Commit

Permalink
Add Mark filtered as watched functionality (#690)
Browse files Browse the repository at this point in the history
* Add remaining episode types to episode filter

* Add `Mark filtered as watched` functionality

* Fix typo

* Fix comment for `setSeriesEpisodesWatched`
  • Loading branch information
harshithmohan authored Nov 21, 2023
1 parent 7a982b7 commit 4378e1a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 12 deletions.
21 changes: 18 additions & 3 deletions src/core/rtkQuery/splitV3Api/seriesApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ type SeriesImagesQueryResultType = {
Fanarts: ImageType[];
};

export type SeriesEpisodesQueryType = {
type SeriesEpisodesQueryBaseType = {
seriesID: number;
includeMissing?: string;
includeHidden?: string;
includeDataFrom?: DataSourceType[];
includeWatched?: string;
type?: string;
search?: string;
fuzzy?: boolean;
} & PaginationType;
};

export type SeriesEpisodesQueryType =
& SeriesEpisodesQueryBaseType
& { includeDataFrom?: DataSourceType[] }
& PaginationType;

export type SeriesAniDBEpisodesQueryType = {
anidbID: number;
Expand Down Expand Up @@ -81,6 +85,16 @@ const seriesApi = splitV3Api.injectEndpoints({
providesTags: ['SeriesEpisodes', 'UtilitiesRefresh'],
}),

// Set the watched state for all the episodes that fit the query.
setSeriesEpisodesWatched: build.mutation<void, SeriesEpisodesQueryBaseType & { value: boolean }>({
query: ({ seriesID, ...params }) => ({
url: `Series/${seriesID}/Episode/Watched`,
method: 'POST',
params,
}),
invalidatesTags: ['EpisodeUpdated', 'SeriesEpisodes'],
}),

getSeriesAniDBEpisodes: build.query<ListResultType<EpisodeAniDBType[]>, SeriesAniDBEpisodesQueryType>({
query: ({ anidbID, ...params }) => ({ url: `Series/AniDB/${anidbID}/Episode`, params }),
providesTags: ['SeriesEpisodes', 'UtilitiesRefresh'],
Expand Down Expand Up @@ -276,4 +290,5 @@ export const {
useRefreshSeriesTvdbInfoMutation,
useRehashSeriesFilesMutation,
useRescanSeriesFilesMutation,
useSetSeriesEpisodesWatchedMutation,
} = seriesApi;
44 changes: 35 additions & 9 deletions src/pages/collection/series/SeriesEpisodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ import { useVirtualizer } from '@tanstack/react-virtual';
import { debounce, toNumber } from 'lodash';

import SeriesEpisode from '@/components/Collection/Series/SeriesEpisode';
import Button from '@/components/Input/Button';
import Input from '@/components/Input/Input';
import Select from '@/components/Input/Select';
import ShokoPanel from '@/components/Panels/ShokoPanel';
import { useGetSeriesQuery, useLazyGetSeriesEpisodesInfiniteQuery } from '@/core/rtkQuery/splitV3Api/seriesApi';
import toast from '@/components/Toast';
import {
useGetSeriesQuery,
useLazyGetSeriesEpisodesInfiniteQuery,
useSetSeriesEpisodesWatchedMutation,
} from '@/core/rtkQuery/splitV3Api/seriesApi';

const pageSize = 26;

Expand All @@ -27,6 +33,8 @@ const SeriesEpisodes = () => {
refetchOnMountOrArgChange: false,
skip: !seriesId,
});
const [setEpisodesWatched] = useSetSeriesEpisodesWatchedMutation();

const animeId = useMemo(() => seriesData?.data?.IDs.AniDB ?? 0, [seriesData]);
const episodePages = episodesData.data?.pages ?? {};
const episodeTotal = episodesData.data?.total ?? 0;
Expand Down Expand Up @@ -75,6 +83,23 @@ const SeriesEpisodes = () => {
return () => fetchPage.cancel();
}, [search, episodeFilterAvailability, episodeFilterType, episodeFilterWatched, fetchPage]);

const handleMarkWatched = async (watched: boolean) => {
try {
await setEpisodesWatched({
seriesID: toNumber(seriesId),
includeMissing: episodeFilterAvailability,
includeHidden: episodeFilterHidden,
type: episodeFilterType,
includeWatched: episodeFilterWatched,
value: watched,
}).unwrap();
toast.success(`Episodes marked as ${watched ? 'watched' : 'unwatched'}!`);
} catch (error) {
console.error(error);
toast.error(`Failed to mark episodes as ${watched ? 'watched' : 'unwatched'}!`);
}
};

return (
<div className="flex gap-x-8">
<ShokoPanel title="Search & Filter" className="sticky top-0 w-[25rem]" transparent contentClassName="gap-y-8">
Expand All @@ -97,7 +122,8 @@ const SeriesEpisodes = () => {
<option value="Normal">Normal</option>
<option value="Special">Specials</option>
<option value="Other">Others</option>
<option value="Unknown,ThemeVideo,Trailer,Parody">Misc.</option>
<option value="ThemeSong,OpeningSong,EndingSong">Credits</option>
<option value="Unknown,Trailer,Parody,Interview,Extra">Misc.</option>
</Select>
<Select
id="status"
Expand Down Expand Up @@ -141,15 +167,15 @@ const SeriesEpisodes = () => {
</span>
Entries Listed
</div>
<div className="flex gap-x-3">
<div className="flex gap-x-2">
<div className="flex gap-x-6">
<Button className="flex gap-x-2 !font-normal" onClick={() => handleMarkWatched(true)}>
<Icon path={mdiEyeCheckOutline} size={1} />
<span>Mark Filtered As Watched</span>
</div>
<div className="flex gap-x-2">
Mark Filtered As Watched
</Button>
<Button className="flex gap-x-2 !font-normal" onClick={() => handleMarkWatched(false)}>
<Icon path={mdiEyeOutline} size={1} />
<span>Mark Filtered Unwatched</span>
</div>
Mark Filtered As Unwatched
</Button>
</div>
</div>
{episodeTotal !== 0 && (
Expand Down

0 comments on commit 4378e1a

Please sign in to comment.