From a3d0094cec8d7b2f89f355cc12615e09187a76ae Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Sat, 1 Mar 2025 11:37:34 +0100 Subject: [PATCH] feat: local store read progress for later sync --- .../clear/[libraryId]/[seriesId]/route.ts | 5 +++ src/components/home/MediaRow.tsx | 42 ++++++++++++------- src/components/reader/ClientBookWrapper.tsx | 4 +- .../reader/components/ControlButtons.tsx | 2 +- .../reader/hooks/usePageNavigation.ts | 9 ++-- src/components/reader/types.ts | 4 +- src/components/series/BookGrid.tsx | 13 +++--- src/components/ui/cover.tsx | 4 +- src/components/ui/mark-as-read-button.tsx | 6 ++- src/components/ui/mark-as-unread-button.tsx | 16 +++---- .../services/client-offlinebook.service.ts | 31 ++++++++++++++ 11 files changed, 93 insertions(+), 43 deletions(-) create mode 100644 src/lib/services/client-offlinebook.service.ts diff --git a/src/app/api/komga/cache/clear/[libraryId]/[seriesId]/route.ts b/src/app/api/komga/cache/clear/[libraryId]/[seriesId]/route.ts index 34e8d06..86c5a44 100644 --- a/src/app/api/komga/cache/clear/[libraryId]/[seriesId]/route.ts +++ b/src/app/api/komga/cache/clear/[libraryId]/[seriesId]/route.ts @@ -4,6 +4,7 @@ import { getErrorMessage } from "@/utils/errors"; import { LibraryService } from "@/lib/services/library.service"; import { HomeService } from "@/lib/services/home.service"; import { SeriesService } from "@/lib/services/series.service"; +import { revalidatePath } from "next/cache"; export async function POST( request: Request, @@ -13,13 +14,17 @@ export async function POST( const { libraryId, seriesId } = params; await HomeService.invalidateHomeCache(); + revalidatePath("/"); if (libraryId) { await LibraryService.invalidateLibrarySeriesCache(libraryId); + revalidatePath(`/library/${libraryId}`); } + if (seriesId) { await SeriesService.invalidateSeriesBooksCache(seriesId); await SeriesService.invalidateSeriesCache(seriesId); + revalidatePath(`/series/${seriesId}`); } return NextResponse.json({ message: "🧹 Cache vidé avec succès" }); diff --git a/src/components/home/MediaRow.tsx b/src/components/home/MediaRow.tsx index de04f2c..d48fc08 100644 --- a/src/components/home/MediaRow.tsx +++ b/src/components/home/MediaRow.tsx @@ -4,6 +4,8 @@ import { ChevronLeft, ChevronRight } from "lucide-react"; import { useRef, useState } from "react"; import { Cover } from "@/components/ui/cover"; import { useRouter } from "next/navigation"; +import { ClientOfflineBookService } from "@/lib/services/client-offlinebook.service"; +import { KomgaBook } from "@/types/komga"; interface BaseItem { id: string; @@ -18,12 +20,12 @@ interface OptimizedSeries extends BaseItem { } interface OptimizedBook extends BaseItem { - readProgress:{ - page: number - } + readProgress: { + page: number; + }; media: { pagesCount: number; - } + }; metadata: { title: string; number?: string; @@ -124,19 +126,27 @@ function MediaCard({ item, onClick }: MediaCardProps) { onClick={onClick} className="flex-shrink-0 w-[200px] relative flex flex-col rounded-lg border bg-card text-card-foreground shadow-sm hover:bg-accent hover:text-accent-foreground transition-colors overflow-hidden cursor-pointer" > - {/* Image de couverture */}
- + {isSeries ? ( + + ) : ( + + )} {/* Overlay avec les informations au survol */}

{title}

diff --git a/src/components/reader/ClientBookWrapper.tsx b/src/components/reader/ClientBookWrapper.tsx index 14bffe3..505ec05 100644 --- a/src/components/reader/ClientBookWrapper.tsx +++ b/src/components/reader/ClientBookWrapper.tsx @@ -3,6 +3,7 @@ import { KomgaBook } from "@/types/komga"; import { BookReader } from "./BookReader"; import { useRouter } from "next/navigation"; +import { ClientOfflineBookService } from "@/lib/services/client-offlinebook.service"; interface ClientBookWrapperProps { book: KomgaBook; @@ -12,10 +13,11 @@ interface ClientBookWrapperProps { export function ClientBookWrapper({ book, pages }: ClientBookWrapperProps) { const router = useRouter(); - const handleCloseReader = () => { + const handleCloseReader = (currentPage: number) => { fetch(`/api/komga/cache/clear/${book.libraryId}/${book.seriesId}`, { method: "POST", }); + ClientOfflineBookService.setCurrentPage(book, currentPage); router.back(); }; diff --git a/src/components/reader/components/ControlButtons.tsx b/src/components/reader/components/ControlButtons.tsx index 5662637..42900df 100644 --- a/src/components/reader/components/ControlButtons.tsx +++ b/src/components/reader/components/ControlButtons.tsx @@ -101,7 +101,7 @@ export const ControlButtons = ({ ); } diff --git a/src/components/ui/mark-as-unread-button.tsx b/src/components/ui/mark-as-unread-button.tsx index 606a837..e5664ca 100644 --- a/src/components/ui/mark-as-unread-button.tsx +++ b/src/components/ui/mark-as-unread-button.tsx @@ -1,27 +1,22 @@ "use client"; -import { XCircle } from "lucide-react"; +import { BookX } from "lucide-react"; import { Button } from "./button"; import { useToast } from "./use-toast"; - +import { ClientOfflineBookService } from "@/lib/services/client-offlinebook.service"; interface MarkAsUnreadButtonProps { bookId: string; - isRead: boolean; onSuccess?: () => void; className?: string; } -export function MarkAsUnreadButton({ - bookId, - isRead = false, - onSuccess, - className, -}: MarkAsUnreadButtonProps) { +export function MarkAsUnreadButton({ bookId, onSuccess, className }: MarkAsUnreadButtonProps) { const { toast } = useToast(); const handleMarkAsUnread = async (e: React.MouseEvent) => { e.stopPropagation(); // Empêcher la propagation au parent try { + ClientOfflineBookService.removeCurrentPageById(bookId); const response = await fetch(`/api/komga/books/${bookId}/read-progress`, { method: "DELETE", }); @@ -51,10 +46,9 @@ export function MarkAsUnreadButton({ size="icon" onClick={handleMarkAsUnread} className={`h-8 w-8 p-0 rounded-br-lg rounded-tl-lg ${className}`} - disabled={!isRead} aria-label="Marquer comme non lu" > - + ); } diff --git a/src/lib/services/client-offlinebook.service.ts b/src/lib/services/client-offlinebook.service.ts new file mode 100644 index 0000000..f1dff07 --- /dev/null +++ b/src/lib/services/client-offlinebook.service.ts @@ -0,0 +1,31 @@ +import { KomgaBook } from "@/types/komga"; + +export class ClientOfflineBookService { + static setCurrentPage(book: KomgaBook, page: number) { + localStorage.setItem(`${book.id}-page`, page.toString()); + } + + static getCurrentPage(book: KomgaBook) { + const readProgressPage = book.readProgress?.page || 0; + if (typeof localStorage !== "undefined") { + const cPageLS = localStorage.getItem(`${book.id}-page`) || "0"; + const currentPage = parseInt(cPageLS); + + if (currentPage < readProgressPage) { + return readProgressPage; + } + + return currentPage; + } else { + return readProgressPage; + } + } + + static removeCurrentPage(book: KomgaBook) { + localStorage.removeItem(`${book.id}-page`); + } + + static removeCurrentPageById(bookId: string) { + localStorage.removeItem(`${bookId}-page`); + } +}