diff --git a/devbook.md b/devbook.md index 1b58582..19f1a72 100644 --- a/devbook.md +++ b/devbook.md @@ -9,8 +9,9 @@ Application web moderne pour la lecture de BD/mangas/comics via un serveur Komga ### 📚 Gestion des séries - [x] Système de favoris - - [x] Ajout/suppression des favoris (stockage local) - - [ ] Menu dédié dans la sidebar + - [x] Service de gestion des favoris + - [x] Bouton d'ajout/retrait des favoris + - [x] Menu dédié dans la sidebar avec la liste des séries favorites - [ ] Carousel dédié dans sur la homepage de toutes les séries favorites - [ ] Vue liste/grille configurable - [ ] Filtres et tri avancés diff --git a/src/app/api/komga/series/[seriesId]/route.ts b/src/app/api/komga/series/[seriesId]/route.ts index f091ab6..5a6d502 100644 --- a/src/app/api/komga/series/[seriesId]/route.ts +++ b/src/app/api/komga/series/[seriesId]/route.ts @@ -1,19 +1,12 @@ import { NextResponse } from "next/server"; import { SeriesService } from "@/lib/services/series.service"; +export const dynamic = "force-dynamic"; + export async function GET(request: Request, { params }: { params: { seriesId: string } }) { try { - const { searchParams } = new URL(request.url); - const page = parseInt(searchParams.get("page") || "0"); - const size = parseInt(searchParams.get("size") || "24"); - const unreadOnly = searchParams.get("unread") === "true"; - - const [series, books] = await Promise.all([ - SeriesService.getSeries(params.seriesId), - SeriesService.getSeriesBooks(params.seriesId, page, size, unreadOnly), - ]); - - return NextResponse.json({ series, books }); + const series = await SeriesService.getSeries(params.seriesId); + return NextResponse.json(series); } catch (error) { console.error("API Series - Erreur:", error); return NextResponse.json( diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index fd9eb32..e065bdb 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -1,11 +1,12 @@ -import { BookOpen, Home, Library, Settings, LogOut, RefreshCw } from "lucide-react"; +import { BookOpen, Home, Library, Settings, LogOut, RefreshCw, Star } from "lucide-react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; import { cn } from "@/lib/utils"; import { authService } from "@/lib/services/auth.service"; import { useEffect, useState, useCallback } from "react"; -import { KomgaLibrary } from "@/types/komga"; +import { KomgaLibrary, KomgaSeries } from "@/types/komga"; import { storageService } from "@/lib/services/storage.service"; +import { FavoriteService } from "@/lib/services/favorite.service"; interface SidebarProps { isOpen: boolean; @@ -15,21 +16,19 @@ export function Sidebar({ isOpen }: SidebarProps) { const pathname = usePathname(); const router = useRouter(); const [libraries, setLibraries] = useState([]); + const [favorites, setFavorites] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isRefreshing, setIsRefreshing] = useState(false); - - // Initialiser l'authentification au montage du composant + const [isLoadingFavorites, setIsLoadingFavorites] = useState(true); const fetchLibraries = useCallback(async () => { setIsLoading(true); - console.log("Sidebar - Fetching libraries..."); try { const response = await fetch("/api/komga/libraries"); if (!response.ok) { throw new Error("Erreur lors de la récupération des bibliothèques"); } const data = await response.json(); - console.log("Sidebar - Libraries fetched:", data.length); setLibraries(data); } catch (error) { console.error("Erreur:", error); @@ -40,20 +39,59 @@ export function Sidebar({ isOpen }: SidebarProps) { } }, []); + const fetchFavorites = useCallback(async () => { + setIsLoadingFavorites(true); + try { + const favoriteIds = FavoriteService.getAllFavoriteIds(); + if (favoriteIds.length === 0) { + setFavorites([]); + return; + } + + const promises = favoriteIds.map(async (id) => { + const response = await fetch(`/api/komga/series/${id}`); + if (!response.ok) return null; + return response.json(); + }); + + const results = await Promise.all(promises); + setFavorites(results.filter((series): series is KomgaSeries => series !== null)); + } catch (error) { + console.error("Erreur lors de la récupération des favoris:", error); + setFavorites([]); + } finally { + setIsLoadingFavorites(false); + } + }, []); + + // Chargement initial des données useEffect(() => { fetchLibraries(); - }, [pathname, fetchLibraries]); + fetchFavorites(); + }, []); // Suppression de la dépendance pathname + + // Mettre à jour les favoris quand ils changent dans le localStorage + useEffect(() => { + const handleStorageChange = (e: StorageEvent) => { + if (e.key === "stripstream_favorites") { + fetchFavorites(); + } + }; + + window.addEventListener("storage", handleStorageChange); + return () => window.removeEventListener("storage", handleStorageChange); + }, [fetchFavorites]); const handleRefresh = async () => { setIsRefreshing(true); - await fetchLibraries(); + await Promise.all([fetchLibraries(), fetchFavorites()]); }; const handleLogout = () => { - console.log("Sidebar - Logging out"); authService.logout(); storageService.clearAll(); setLibraries([]); + setFavorites([]); router.push("/login"); }; @@ -95,6 +133,34 @@ export function Sidebar({ isOpen }: SidebarProps) { +
+
+
+

Favoris

+ {favorites.length} +
+ {isLoadingFavorites ? ( +
Chargement...
+ ) : favorites.length === 0 ? ( +
Aucun favori
+ ) : ( + favorites.map((series) => ( + + + {series.metadata.title} + + )) + )} +
+
+