From 326eb513c59b4a3a59f80e9569def24df8f32eec Mon Sep 17 00:00:00 2001 From: Rodrigo Verdiani Date: Thu, 16 Apr 2026 14:51:49 -0300 Subject: [PATCH] refactor: improve reading progress synchronization logic and add implementation guidelines --- .../chapter/hooks/useReadingProgressSync.ts | 56 +++++++++++-------- src/pages/Chapter.tsx | 39 ++++++++++--- 2 files changed, 64 insertions(+), 31 deletions(-) diff --git a/src/features/chapter/hooks/useReadingProgressSync.ts b/src/features/chapter/hooks/useReadingProgressSync.ts index b3ee28f..31041c5 100644 --- a/src/features/chapter/hooks/useReadingProgressSync.ts +++ b/src/features/chapter/hooks/useReadingProgressSync.ts @@ -15,19 +15,14 @@ export const useReadingProgressSync = (mangaId: number, chapterId: number) => { if (jsonString) { try { const data: ReadingTrackerData = JSON.parse(jsonString); - return data.chapterPage[chapterId] || 1; + return data.chapterPage[chapterId] ?? null; } catch (e) { console.error("Failed to parse local progress", e); } } - return 1; + return null; }); - const [serverProgress, setServerProgress] = useState<{ - pageNumber: number; - updatedAt: string; - } | null>(null); - const lastSyncedPage = useRef(null); const syncTimerRef = useRef | null>(null); @@ -38,36 +33,36 @@ export const useReadingProgressSync = (mangaId: number, chapterId: number) => { ); const { mutate: updateProgress } = useUpdateProgress(); + const serverProgress = + progressData && + progressData.pageNumber !== undefined && + progressData.updatedAt !== undefined + ? { + pageNumber: progressData.pageNumber, + updatedAt: progressData.updatedAt, + } + : null; + // Sync local progress when chapterId changes useEffect(() => { const jsonString = localStorage.getItem("readingTrackerData"); if (jsonString) { try { const data: ReadingTrackerData = JSON.parse(jsonString); - const localPage = data.chapterPage[chapterId] || 1; + const localPage = data.chapterPage[chapterId] ?? null; setCurrentPage(localPage); lastSyncedPage.current = localPage; } catch (e) { // ignore } } else { - setCurrentPage(1); - lastSyncedPage.current = 1; + setCurrentPage(null); + lastSyncedPage.current = null; } }, [chapterId]); - // Sync server progress when available - useEffect(() => { - if (progressData && progressData.pageNumber !== undefined && progressData.updatedAt !== undefined) { - setServerProgress({ - pageNumber: progressData.pageNumber, - updatedAt: progressData.updatedAt, - }); - } - }, [progressData]); - const saveLocalProgress = useCallback( - (page: number) => { + (page: number, forceSync = false) => { setCurrentPage(page); const jsonString = localStorage.getItem("readingTrackerData"); let data: ReadingTrackerData = { chapterPage: {}, updatedAt: {} }; @@ -85,8 +80,9 @@ export const useReadingProgressSync = (mangaId: number, chapterId: number) => { // Debounced backend sync if (syncTimerRef.current) clearTimeout(syncTimerRef.current); - syncTimerRef.current = setTimeout(() => { - if (page !== lastSyncedPage.current) { + + const performSync = () => { + if (forceSync || page !== lastSyncedPage.current) { updateProgress({ data: { mangaId, @@ -96,11 +92,23 @@ export const useReadingProgressSync = (mangaId: number, chapterId: number) => { }); lastSyncedPage.current = page; } - }, 5000); + }; + + if (forceSync) { + performSync(); + } else { + syncTimerRef.current = setTimeout(performSync, 5000); + } }, [mangaId, chapterId, updateProgress], ); + useEffect(() => { + return () => { + if (syncTimerRef.current) clearTimeout(syncTimerRef.current); + }; + }, []); + const applyServerProgress = useCallback(() => { if (serverProgress) { saveLocalProgress(serverProgress.pageNumber); diff --git a/src/pages/Chapter.tsx b/src/pages/Chapter.tsx index 0a0360d..c7a9852 100644 --- a/src/pages/Chapter.tsx +++ b/src/pages/Chapter.tsx @@ -53,15 +53,33 @@ const Chapter = () => { const localPage = savedPage; const serverPage = serverProgress?.pageNumber; - if (!localPage && !serverPage) { + if (localPage === null) { + // No local history for this chapter, use server or default to 1 + const targetPage = serverPage || 1; + setCurrentPage(targetPage); + setVisibleCount(targetPage); + if (targetPage > 1) { + setIsAutoScrolling(true); + } setHasInitialized(true); return; } - if (localPage && serverPage && localPage !== serverPage) { - setShowConflictDialog(true); + if (serverPage && localPage !== serverPage) { + // If local is just starting out (page 1), just take server + if (localPage <= 1) { + const targetPage = serverPage; + setCurrentPage(targetPage); + setVisibleCount(targetPage); + if (targetPage > 1) { + setIsAutoScrolling(true); + } + setHasInitialized(true); + } else { + setShowConflictDialog(true); + } } else { - const targetPage = localPage || serverPage || 1; + const targetPage = localPage || 1; setCurrentPage(targetPage); setVisibleCount(targetPage); if (targetPage > 1) { @@ -181,7 +199,7 @@ const Chapter = () => { } }, [infiniteScroll]); - if (isLoading || !hasInitialized) { + if (isLoading || (isLoadingProgress && !hasInitialized)) { return (
@@ -245,7 +263,7 @@ const Chapter = () => { - Progress Conflict + Reading Progress Conflict You have different progress saved locally and on the server for this chapter. @@ -258,10 +276,17 @@ const Chapter = () => { - +