diff --git a/docs/api.md b/docs/api.md index e3eec0c..5abe859 100644 --- a/docs/api.md +++ b/docs/api.md @@ -50,6 +50,18 @@ - **Description** : Liste des bibliothèques - **Réponse** : `Library[]` +### GET /libraries/[libraryId] + +- **Description** : Page d'une bibliothèque +- **Paramètres** : `libraryId` dans l'URL +- **Query Parameters** : + - `page` : Numéro de page (défaut: 1) + - `size` : Nombre d'éléments par page (défaut: 20, valeurs possibles: 20, 50, 100) + - `unread` : Filtrer les séries non lues (défaut: false) + - `search` : Rechercher une série par titre + - `compact` : Mode d'affichage compact (défaut: false) +- **Réponse** : Page HTML avec la liste des séries + ## 📖 Séries ### GET /api/komga/series/[seriesId] diff --git a/docs/services.md b/docs/services.md index 624ae64..52ff504 100644 --- a/docs/services.md +++ b/docs/services.md @@ -35,9 +35,14 @@ Service de gestion des bibliothèques - Récupère une bibliothèque spécifique - Lance une erreur si non trouvée -- `getLibrarySeries(libraryId: string, page: number = 0, size: number = 20, unreadOnly: boolean = false): Promise>` +- `getLibrarySeries(libraryId: string, page: number = 0, size: number = 20, unreadOnly: boolean = false, search?: string): Promise>` - Récupère les séries d'une bibliothèque - Supporte la pagination et le filtrage + - Paramètres : + - `page` : Numéro de page (défaut: 0) + - `size` : Nombre d'éléments par page (défaut: 20, valeurs possibles: 20, 50, 100) + - `unreadOnly` : Filtrer les séries non lues (défaut: false) + - `search` : Rechercher une série par titre (optionnel) ## 📖 SeriesService diff --git a/package.json b/package.json index 470fa2c..081c3da 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@radix-ui/react-dialog": "1.0.5", "@radix-ui/react-dropdown-menu": "^2.1.6", "@radix-ui/react-progress": "^1.1.2", + "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-slot": "1.0.2", "@radix-ui/react-toast": "1.1.5", "@types/bcrypt": "^5.0.2", diff --git a/src/app/libraries/[libraryId]/page.tsx b/src/app/libraries/[libraryId]/page.tsx index f27b996..c39a774 100644 --- a/src/app/libraries/[libraryId]/page.tsx +++ b/src/app/libraries/[libraryId]/page.tsx @@ -13,10 +13,10 @@ import { AppError } from "@/utils/errors"; interface PageProps { params: { libraryId: string }; - searchParams: { page?: string; unread?: string; search?: string }; + searchParams: { page?: string; unread?: string; search?: string; size?: string }; } -const PAGE_SIZE = 20; +const DEFAULT_PAGE_SIZE = 20; async function refreshLibrary(libraryId: string) { "use server"; @@ -36,7 +36,8 @@ async function getLibrarySeries( libraryId: string, page: number = 1, unreadOnly: boolean = false, - search?: string + search?: string, + size: number = DEFAULT_PAGE_SIZE ) { try { const pageIndex = page - 1; @@ -44,7 +45,7 @@ async function getLibrarySeries( const series: LibraryResponse = await LibraryService.getLibrarySeries( libraryId, pageIndex, - PAGE_SIZE, + size, unreadOnly, search ); @@ -61,16 +62,18 @@ async function LibraryPage({ params, searchParams }: PageProps) { const unread = (await searchParams).unread; const search = (await searchParams).search; const page = (await searchParams).page; + const size = (await searchParams).size; const currentPage = page ? parseInt(page) : 1; + const pageSize = size ? parseInt(size) : DEFAULT_PAGE_SIZE; const preferences: UserPreferences = await PreferencesService.getPreferences(); // Utiliser le paramètre d'URL s'il existe, sinon utiliser la préférence utilisateur const unreadOnly = unread !== undefined ? unread === "true" : preferences.showOnlyUnread; - + console.log(unreadOnly); try { const { data: series, library }: { data: LibraryResponse; library: KomgaLibrary } = - await getLibrarySeries(libraryId, currentPage, unreadOnly, search); + await getLibrarySeries(libraryId, currentPage, unreadOnly, search, pageSize); return (
@@ -90,7 +93,7 @@ async function LibraryPage({ params, searchParams }: PageProps) { currentPage={currentPage} totalPages={series.totalPages} totalElements={series.totalElements} - pageSize={PAGE_SIZE} + pageSize={pageSize} defaultShowOnlyUnread={preferences.showOnlyUnread} showOnlyUnread={unreadOnly} /> diff --git a/src/components/library/PaginatedSeriesGrid.tsx b/src/components/library/PaginatedSeriesGrid.tsx index c98e612..292e3a4 100644 --- a/src/components/library/PaginatedSeriesGrid.tsx +++ b/src/components/library/PaginatedSeriesGrid.tsx @@ -4,11 +4,18 @@ import { SeriesGrid } from "./SeriesGrid"; import { Pagination } from "@/components/ui/Pagination"; import { useRouter, usePathname, useSearchParams } from "next/navigation"; import { useState, useEffect } from "react"; -import { Loader2, Filter } from "lucide-react"; +import { Loader2, Filter, LayoutGrid, LayoutList, LayoutTemplate } from "lucide-react"; import { cn } from "@/lib/utils"; import type { KomgaSeries } from "@/types/komga"; import { SearchInput } from "./SearchInput"; import { useTranslate } from "@/hooks/useTranslate"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; interface PaginatedSeriesGridProps { series: KomgaSeries[]; @@ -34,8 +41,25 @@ export function PaginatedSeriesGrid({ const searchParams = useSearchParams(); const [isChangingPage, setIsChangingPage] = useState(false); const [showOnlyUnread, setShowOnlyUnread] = useState(initialShowOnlyUnread); + const [isCompact, setIsCompact] = useState(searchParams.get("compact") === "true"); const { t } = useTranslate(); + const updateUrlParams = async (updates: Record) => { + setIsChangingPage(true); + const params = new URLSearchParams(searchParams.toString()); + + // Mettre à jour les paramètres + Object.entries(updates).forEach(([key, value]) => { + if (value === null) { + params.delete(key); + } else { + params.set(key, value); + } + }); + + await router.push(`${pathname}?${params.toString()}`); + }; + // Reset loading state when series change useEffect(() => { setIsChangingPage(false); @@ -49,31 +73,39 @@ export function PaginatedSeriesGrid({ // Apply default filter on initial load useEffect(() => { if (defaultShowOnlyUnread && !searchParams.has("unread")) { - const params = new URLSearchParams(searchParams.toString()); - params.set("page", "1"); - params.set("unread", "true"); - router.push(`${pathname}?${params.toString()}`); + updateUrlParams({ page: "1", unread: "true" }); } }, [defaultShowOnlyUnread, pathname, router, searchParams]); const handlePageChange = async (page: number) => { - setIsChangingPage(true); - const params = new URLSearchParams(searchParams.toString()); - params.set("page", page.toString()); - params.set("unread", showOnlyUnread.toString()); - await router.push(`${pathname}?${params.toString()}`); + await updateUrlParams({ page: page.toString(), compact: isCompact.toString() }); }; const handleUnreadFilter = async () => { - setIsChangingPage(true); - const params = new URLSearchParams(searchParams.toString()); - params.set("page", "1"); - const newUnreadState = !showOnlyUnread; setShowOnlyUnread(newUnreadState); - params.set("unread", newUnreadState.toString()); + await updateUrlParams({ + page: "1", + unread: newUnreadState ? "true" : "false", + compact: isCompact.toString(), + }); + }; - await router.push(`${pathname}?${params.toString()}`); + const handleCompactToggle = async () => { + const newCompactState = !isCompact; + setIsCompact(newCompactState); + await updateUrlParams({ + page: "1", + compact: newCompactState.toString(), + }); + }; + + const handlePageSizeChange = async (value: string) => { + await updateUrlParams({ + page: "1", + size: value, + compact: isCompact.toString(), + }); }; // Calculate start and end indices for display @@ -92,15 +124,42 @@ export function PaginatedSeriesGrid({ return (
-
-
+
+
-
+

{getShowingText()}

+ +
diff --git a/src/components/library/SeriesGrid.tsx b/src/components/library/SeriesGrid.tsx index bc53aee..cc521a2 100644 --- a/src/components/library/SeriesGrid.tsx +++ b/src/components/library/SeriesGrid.tsx @@ -8,6 +8,7 @@ import { useTranslate } from "@/hooks/useTranslate"; interface SeriesGridProps { series: KomgaSeries[]; + isCompact?: boolean; } // Utility function to get reading status info @@ -42,7 +43,7 @@ const getReadingStatusInfo = (series: KomgaSeries, t: (key: string, options?: an }; }; -export function SeriesGrid({ series }: SeriesGridProps) { +export function SeriesGrid({ series, isCompact = false }: SeriesGridProps) { const router = useRouter(); const { t } = useTranslate(); @@ -55,14 +56,22 @@ export function SeriesGrid({ series }: SeriesGridProps) { } return ( -
+
{series.map((series) => (