diff --git a/src/components/library/LibraryMangaGrid.tsx b/src/components/library/LibraryMangaGrid.tsx index c65e5b45..e0a7a67e 100644 --- a/src/components/library/LibraryMangaGrid.tsx +++ b/src/components/library/LibraryMangaGrid.tsx @@ -79,18 +79,18 @@ const sortManga = ( return result; }; -const LibraryMangaGrid: React.FC = ({ - mangas, isLoading, hasNextPage, lastPageNum, setLastPageNum, message, +const LibraryMangaGrid: React.FC = ({ + mangas, isLoading, hasNextPage, lastPageNum, setLastPageNum, message, lastLibraryUpdate, }) => { const [query] = useQueryParam('query', StringParam); const { options } = useLibraryOptionsContext(); const { unread, downloaded } = options; const sortedManga = useMemo(() => sortManga(mangas, options.sorts, options.sortDesc), - [mangas, options.sorts, options.sortDesc]); + [mangas, lastLibraryUpdate, options.sorts, options.sortDesc]); const filteredManga = useMemo(() => filterManga(sortedManga, query, unread, downloaded), - [sortedManga, query, unread, downloaded]); + [sortedManga, lastLibraryUpdate, query, unread, downloaded]); const showFilteredOutMessage = (unread != null || downloaded != null || query) && filteredManga.length === 0 && mangas.length > 0; diff --git a/src/components/library/UpdateChecker.tsx b/src/components/library/UpdateChecker.tsx index b7310b56..f1ed0249 100644 --- a/src/components/library/UpdateChecker.tsx +++ b/src/components/library/UpdateChecker.tsx @@ -27,7 +27,11 @@ function Progress({ progress }: IProgressProps) { const baseWebsocketUrl = JSON.parse(window.localStorage.getItem('serverBaseURL')!).replace('http', 'ws'); -function UpdateChecker() { +interface IUpdateCheckerProps { + handleFinishedUpdate: (time: number) => void +} + +function UpdateChecker({ handleFinishedUpdate }: IUpdateCheckerProps) { const [loading, setLoading] = useState(false); const [progress, setProgress] = useState(0); @@ -44,16 +48,36 @@ function UpdateChecker() { useEffect(() => { const wsc = new WebSocket(`${baseWebsocketUrl}/api/v1/update`); - wsc.onmessage = (e) => { - const data = JSON.parse(e.data) as IUpdateStatus; - const { COMPLETE = [], RUNNING = [], PENDING = [] } = data.statusMap; - setLoading(data.running); + // "loading" can't be used since it will be outdated once the state gets changed + // it could be used by adding it as a dependency of "useEffect" but then the socket would + // get closed and connected again every time it changes + let updateStarted = false; + + wsc.onmessage = (e) => { + const { running, statusMap } = JSON.parse(e.data) as IUpdateStatus; + const { COMPLETE = [], RUNNING = [], PENDING = [] } = statusMap; + const currentProgress = 100 * ( COMPLETE.length / (COMPLETE.length + RUNNING.length + PENDING.length) ); + const isUpdateFinished = currentProgress === 100; + const ignoreFaultyMessage = !updateStarted && !running && isUpdateFinished; + + // for some reason the server sends 100% completed manga updates when connecting to the + // socket while no update is running + if (ignoreFaultyMessage) { + return; + } + + updateStarted = running; + setLoading(running); setProgress(Number.isNaN(currentProgress) ? 0 : currentProgress); + + if (isUpdateFinished) { + handleFinishedUpdate(Date.now()); + } }; return () => wsc.close(); diff --git a/src/screens/Library.tsx b/src/screens/Library.tsx index 75838f24..b8f4d690 100644 --- a/src/screens/Library.tsx +++ b/src/screens/Library.tsx @@ -21,6 +21,7 @@ import { useQuery } from 'util/client'; import UpdateChecker from '../components/library/UpdateChecker'; export default function Library() { + const [lastLibraryUpdate, setLastLibraryUpdate] = useState(Date.now()); const { data: tabsData, error: tabsError, loading } = useQuery('/api/v1/category'); const tabs = tabsData ?? []; @@ -43,7 +44,7 @@ export default function Library() { <> - + , ); return () => { @@ -76,6 +77,7 @@ export default function Library() { return (