diff --git a/src/components/Panels/ShokoPanel.tsx b/src/components/Panels/ShokoPanel.tsx index 52fc54cae..95c7b2338 100644 --- a/src/components/Panels/ShokoPanel.tsx +++ b/src/components/Panels/ShokoPanel.tsx @@ -1,4 +1,6 @@ import React, { ReactNode } from 'react'; +import { Icon } from '@mdi/react'; +import { mdiLoading } from '@mdi/js'; type Props = { title: string; @@ -9,7 +11,7 @@ type Props = { titleTabs?: ReactNode; }; -const ShokoPanel = ({ className, title, options, children, titleTabs }: Props) => ( +const ShokoPanel = ({ className, title, options, children, titleTabs, isFetching }: Props) => (
{title}{titleTabs} @@ -22,8 +24,8 @@ const ShokoPanel = ({ className, title, options, children, titleTabs }: Props) =
-
- {children} +
+ {isFetching ?
: children}
); diff --git a/src/core/sagas/dashboard.ts b/src/core/sagas/dashboard.ts index 5d5f2fd46..e090875cd 100644 --- a/src/core/sagas/dashboard.ts +++ b/src/core/sagas/dashboard.ts @@ -5,6 +5,7 @@ import ApiDashboard from '../api/v3/dashboard'; import { setFetched, + unsetFetched, setSeriesSummary, setStats, setRecentEpisodes, @@ -71,9 +72,11 @@ function* getDashboardContinueWatching() { } yield put(setContinueWatching(resultJson.data)); + yield put(setFetched('continueWatching')); } function* getDashboardUpcomingAnime(action: PayloadAction) { + yield put(unsetFetched('upcomingAnime')); const resultJson = yield call(ApiDashboard.getDashboardAniDBCalendar, action.payload); if (resultJson.error) { toast.error(resultJson.message); @@ -81,6 +84,7 @@ function* getDashboardUpcomingAnime(action: PayloadAction) { } yield put(setUpcomingAnime(resultJson.data)); + yield put(setFetched('upcomingAnime')); } export default { diff --git a/src/core/sagas/mainpage.ts b/src/core/sagas/mainpage.ts index 9a277b04d..2dc34f456 100644 --- a/src/core/sagas/mainpage.ts +++ b/src/core/sagas/mainpage.ts @@ -31,7 +31,6 @@ function* eventMainPageLoad() { yield call(SagaImportFolder.getImportFolders), yield call(SagaDashboard.getDashboardRecentlyAddedEpisodes), yield call(SagaDashboard.getDashboardRecentlyAddedSeries), - yield call(SagaFile.getRecentFiles), yield call(SagaFile.getUnrecognizedFiles), yield call(SagaDashboard.getDashboardContinueWatching), yield call(SagaDashboard.getDashboardUpcomingAnime, { type: Events.DASHBOARD_UPCOMING_ANIME, payload: false }), diff --git a/src/pages/dashboard/panels/ContinueWatching.tsx b/src/pages/dashboard/panels/ContinueWatching.tsx index e5c7908d9..2324f3a3a 100644 --- a/src/pages/dashboard/panels/ContinueWatching.tsx +++ b/src/pages/dashboard/panels/ContinueWatching.tsx @@ -6,6 +6,7 @@ import { DashboardEpisodeDetailsType } from '../../../core/types/api/dashboard'; const ContinueWatching = () => { const items = useSelector((state: RootState) => state.mainpage.continueWatching); + const hasFetched = useSelector((state: RootState) => state.mainpage.fetched.continueWatching); const renderDetails = (item: DashboardEpisodeDetailsType ) => { @@ -17,7 +18,7 @@ const ContinueWatching = () => { }; return ( - +
{items.map(item => renderDetails(item))}
); diff --git a/src/pages/dashboard/panels/ImportBreakdown.tsx b/src/pages/dashboard/panels/ImportBreakdown.tsx index 7a095c991..4846bdaf0 100644 --- a/src/pages/dashboard/panels/ImportBreakdown.tsx +++ b/src/pages/dashboard/panels/ImportBreakdown.tsx @@ -1,46 +1,18 @@ -import React, { useState } from 'react'; +import React from 'react'; import { useSelector } from 'react-redux'; -import cx from 'classnames'; import { RootState } from '../../../core/store'; import ShokoPanel from '../../../components/Panels/ShokoPanel'; -import Button from '../../../components/Input/Button'; -import ImportedTab from './ImportBreakdownTabs/ImportedTab'; import UnrecognizedTab from './ImportBreakdownTabs/UnrecognizedTab'; function ImportBreakdown() { - const hasFetchedRecents = useSelector((state: RootState) => state.mainpage.fetched.recentFiles); const hasFetchedUnrecognized = useSelector( (state: RootState) => state.mainpage.fetched.unrecognizedFiles, ); - const [activeTab, setActiveTab] = useState('unrecognized'); - - const renderOptions = () => ( -
- - -
- ); - - const renderContent = () => { - switch (activeTab) { - case 'imported': - return ; - case 'unrecognized': - return ; - default: - return ; - } - }; - return ( - - {renderContent()} + + ); } diff --git a/src/pages/dashboard/panels/ImportBreakdownTabs/ImportedTab.tsx b/src/pages/dashboard/panels/ImportBreakdownTabs/ImportedTab.tsx deleted file mode 100644 index bb511ceb2..000000000 --- a/src/pages/dashboard/panels/ImportBreakdownTabs/ImportedTab.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { forEach, orderBy } from 'lodash'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faCaretDown, faCaretUp, faCircleNotch } from '@fortawesome/free-solid-svg-icons'; -import prettyBytes from 'pretty-bytes'; -import moment from 'moment'; -import cx from 'classnames'; - -import { RootState } from '../../../../core/store'; -import Events from '../../../../core/events'; -import Button from '../../../../components/Input/Button'; - -import type { FileDetailedType } from '../../../../core/types/api/file'; -import TransitionDiv from '../../../../components/TransitionDiv'; - -const epTypes = { - Normal: 'E', - Special: 'S', - Parody: 'P', - ThemeSong: 'C', - Trailer: 'T', - Other: 'O', - Unknown: 'X', -}; - -function ImportedTab() { - const dispatch = useDispatch(); - - const items = useSelector((state: RootState) => state.mainpage.recentFiles); - const recentFileDetails = useSelector((state: RootState) => state.mainpage.recentFileDetails); - - const [expandedItems, setExpandedItems] = useState({} as { [ID: number]: boolean }); - - useEffect(() => { - forEach(items, (item) => { - expandedItems[item.ID] = false; - }); - - setExpandedItems(expandedItems); - }); - - const getDetails = (fileId: number, seriesId: number, episodeId: number) => dispatch( - { type: Events.MAINPAGE_RECENT_FILE_DETAILS, payload: { fileId, seriesId, episodeId } }, - ); - - const handleExpand = (item: FileDetailedType) => { - expandedItems[item.ID] = !expandedItems[item.ID]; - - const { SeriesIDs } = item; - getDetails(item.ID, SeriesIDs[0].SeriesID.ID, SeriesIDs[0].EpisodeIDs[0].ID); - - setExpandedItems(expandedItems); - }; - - const getFileInfo = ( - resolution = 'Unknown', - source = 'Unknown', - audioLanguages: Array = [], - subtitleLanguages: Array = [], - videoCodec = 'Unknown', - ) => { - let info = `${resolution} | ${videoCodec} | ${source.toUpperCase()} | `; - if (audioLanguages.length > 2) info += 'Multi Audio'; - else if (audioLanguages.length === 2) info += 'Dual Audio'; - else if (subtitleLanguages[0] !== 'none') info += 'Subbed'; - else info += 'Raw'; - - return info; - }; - - const renderDate = (item: FileDetailedType) => ( -
- {moment(item.Created).format('yyyy-MM-DD')} / {moment(item.Created).format('hh:mm A')} - -
- ); - - const renderName = (idx: number, serverPath: string) => ( - {serverPath} - ); - - const renderDetails = (item: FileDetailedType) => { - const fileDetails = recentFileDetails[item.ID]; - const { fetched, details } = fileDetails ?? {}; - - return ( -
- { - expandedItems[item.ID] && (!fetched - ? ( -
- -
- ) - : ( - -
- Series - {details.SeriesName ?? 'Unknown'} -
-
- Episode - {`${(epTypes[details.EpisodeType ?? 'Unknown']) + details.EpisodeNumber}: ${details.EpisodeName ?? 'Unknown'}`} -
-
- Group - {details.ReleaseGroup ?? 'Unknown'} -
-
- Size - {prettyBytes(item.Size, { binary: true })} -
-
- Video Info - {getFileInfo( - item.RoundedStandardResolution, - details.Source, - details.AudioLanguages, - details.SubtitleLanguages, - details.VideoCodec, - )} -
-
- ) - ) - } -
- ); - }; - - const sortedItems = orderBy(items, ['ID'], ['desc']); - const files: Array = []; - - forEach(sortedItems, (item) => { - if (item?.SeriesIDs && item?.Locations && item?.Locations?.length !== 0) { - files.push(renderDate(item)); - files.push(renderName(item.ID, item.Locations[0].RelativePath)); - files.push(renderDetails(item)); - } - }); - - if (files.length === 0) { - return (
No imported files!
); - } - - return ({files}); -} - -export default ImportedTab; diff --git a/src/pages/dashboard/panels/ImportFolders.tsx b/src/pages/dashboard/panels/ImportFolders.tsx index 6f8b25e9b..009598ed0 100644 --- a/src/pages/dashboard/panels/ImportFolders.tsx +++ b/src/pages/dashboard/panels/ImportFolders.tsx @@ -68,10 +68,8 @@ function ImportFolders() { }; const renderOptions = () => ( -
-
); diff --git a/src/pages/dashboard/panels/QueueProcessor.tsx b/src/pages/dashboard/panels/QueueProcessor.tsx index 590b3f7d0..771787918 100644 --- a/src/pages/dashboard/panels/QueueProcessor.tsx +++ b/src/pages/dashboard/panels/QueueProcessor.tsx @@ -70,13 +70,13 @@ function QueueProcessor() { return ( {paused ? ( - + ) : ( - + )} ); diff --git a/src/pages/dashboard/panels/RecentlyImported.tsx b/src/pages/dashboard/panels/RecentlyImported.tsx index deb98c5e3..2649a0a79 100644 --- a/src/pages/dashboard/panels/RecentlyImported.tsx +++ b/src/pages/dashboard/panels/RecentlyImported.tsx @@ -10,9 +10,9 @@ import { SeriesType } from '../../../core/types/api/series'; const Title = ({ showSeries, setShowSeries }) => (
> - { setShowSeries(false);}}>Episodes + { setShowSeries(false);}}>Episodes | - { setShowSeries(true);}}>Series + { setShowSeries(true);}}>Series
); diff --git a/src/pages/dashboard/panels/UpcomingAnime.tsx b/src/pages/dashboard/panels/UpcomingAnime.tsx index e92fc2ae8..5ee0df675 100644 --- a/src/pages/dashboard/panels/UpcomingAnime.tsx +++ b/src/pages/dashboard/panels/UpcomingAnime.tsx @@ -18,14 +18,15 @@ const CalendarConfig: moment.CalendarSpec = { const Title = ({ showAll, setShowAll }) => (
> - { setShowAll(false);}}>My Collection + { setShowAll(false);}}>My Collection | - { setShowAll(true);}}>All + { setShowAll(true);}}>All
); const UpcomingAnime = () => { const items = useSelector((state: RootState) => state.mainpage.upcomingAnime); + const hasFetched = useSelector((state: RootState) => state.mainpage.fetched.upcomingAnime); const [showAll, setShowAll] = useState(false); const dispatch = useDispatch(); @@ -49,7 +50,7 @@ const UpcomingAnime = () => { }; return ( - }> + }>
{items.map(item => renderDetails(item))}
);