diff --git a/src/app/libraries/[libraryId]/page.tsx b/src/app/libraries/[libraryId]/page.tsx
index 3731c57..df7fac2 100644
--- a/src/app/libraries/[libraryId]/page.tsx
+++ b/src/app/libraries/[libraryId]/page.tsx
@@ -6,7 +6,7 @@ import { RefreshButton } from "@/components/library/RefreshButton";
interface PageProps {
params: { libraryId: string };
- searchParams: { page?: string; unread?: string };
+ searchParams: { page?: string; unread?: string; search?: string };
}
const PAGE_SIZE = 20;
@@ -25,7 +25,12 @@ async function refreshLibrary(libraryId: string) {
}
}
-async function getLibrarySeries(libraryId: string, page: number = 1, unreadOnly: boolean = false) {
+async function getLibrarySeries(
+ libraryId: string,
+ page: number = 1,
+ unreadOnly: boolean = false,
+ search?: string
+) {
try {
const pageIndex = page - 1;
@@ -33,7 +38,8 @@ async function getLibrarySeries(libraryId: string, page: number = 1, unreadOnly:
libraryId,
pageIndex,
PAGE_SIZE,
- unreadOnly
+ unreadOnly,
+ search
);
const library = await LibraryService.getLibrary(libraryId);
@@ -55,7 +61,8 @@ export default async function LibraryPage({ params, searchParams }: PageProps) {
const { data: series, library } = await getLibrarySeries(
params.libraryId,
currentPage,
- unreadOnly
+ unreadOnly,
+ searchParams.search
);
return (
diff --git a/src/components/library/PaginatedSeriesGrid.tsx b/src/components/library/PaginatedSeriesGrid.tsx
index 77e6c6f..ea68c4d 100644
--- a/src/components/library/PaginatedSeriesGrid.tsx
+++ b/src/components/library/PaginatedSeriesGrid.tsx
@@ -7,6 +7,7 @@ import { useState, useEffect } from "react";
import { Loader2, Filter } from "lucide-react";
import { cn } from "@/lib/utils";
import { KomgaSeries } from "@/types/komga";
+import { SearchInput } from "./SearchInput";
interface PaginatedSeriesGridProps {
series: KomgaSeries[];
@@ -87,24 +88,29 @@ export function PaginatedSeriesGrid({
return (
-
- {totalElements > 0 ? (
- <>
- Affichage des séries {startIndex} à{" "}
- {endIndex} sur{" "}
- {totalElements}
- >
- ) : (
- "Aucune série trouvée"
- )}
-
-
+
+
+
+
+
+ {totalElements > 0 ? (
+ <>
+ Affichage des séries {startIndex} à{" "}
+ {endIndex} sur{" "}
+ {totalElements}
+ >
+ ) : (
+ "Aucune série trouvée"
+ )}
+
+
+
diff --git a/src/components/library/SearchInput.tsx b/src/components/library/SearchInput.tsx
new file mode 100644
index 0000000..7f08b26
--- /dev/null
+++ b/src/components/library/SearchInput.tsx
@@ -0,0 +1,54 @@
+import { Search } from "lucide-react";
+import { useRouter, useSearchParams } from "next/navigation";
+import { useCallback, useTransition } from "react";
+import { Input } from "@/components/ui/input";
+import { debounce } from "@/lib/utils";
+
+interface SearchInputProps {
+ placeholder?: string;
+}
+
+export const SearchInput = ({ placeholder = "Rechercher une série..." }: SearchInputProps) => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+ const [isPending, startTransition] = useTransition();
+
+ const createQueryString = useCallback(
+ (name: string, value: string) => {
+ const params = new URLSearchParams(searchParams.toString());
+ if (value) {
+ params.set(name, value);
+ } else {
+ params.delete(name);
+ }
+ return params.toString();
+ },
+ [searchParams]
+ );
+
+ const handleSearch = debounce((term: string) => {
+ startTransition(() => {
+ const query = createQueryString("search", term);
+ router.push(`?${query}`);
+ });
+ }, 300);
+
+ return (
+
+
+
handleSearch(e.target.value)}
+ aria-label="Rechercher une série"
+ />
+ {isPending && (
+
+ )}
+
+ );
+};
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
new file mode 100644
index 0000000..a4f7d29
--- /dev/null
+++ b/src/components/ui/input.tsx
@@ -0,0 +1,23 @@
+import * as React from "react";
+import { cn } from "@/lib/utils";
+
+export interface InputProps extends React.InputHTMLAttributes
{}
+
+const Input = React.forwardRef(
+ ({ className, type, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+Input.displayName = "Input";
+
+export { Input };
diff --git a/src/lib/services/library.service.ts b/src/lib/services/library.service.ts
index f322883..94b25b6 100644
--- a/src/lib/services/library.service.ts
+++ b/src/lib/services/library.service.ts
@@ -33,7 +33,8 @@ export class LibraryService extends BaseApiService {
libraryId: string,
page: number = 0,
size: number = 20,
- unreadOnly: boolean = false
+ unreadOnly: boolean = false,
+ search?: string
): Promise> {
try {
const config = await this.getKomgaConfig();
@@ -42,11 +43,12 @@ export class LibraryService extends BaseApiService {
page: page.toString(),
size: size.toString(),
...(unreadOnly && { read_status: "UNREAD,IN_PROGRESS" }),
+ ...(search && { search }),
});
const headers = this.getAuthHeaders(config);
return this.fetchWithCache>(
- `library-${libraryId}-series-${page}-${size}-${unreadOnly}`,
+ `library-${libraryId}-series-${page}-${size}-${unreadOnly}-${search}`,
async () => this.fetchFromApi>(url, headers),
"SERIES"
);
@@ -56,6 +58,6 @@ export class LibraryService extends BaseApiService {
}
static async clearLibrarySeriesCache(libraryId: string) {
- serverCacheService.delete(`library-${libraryId}-series`);
+ serverCacheService.deleteAll(`library-${libraryId}-series`);
}
}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 5ecd27d..2fa517c 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -13,3 +13,20 @@ export function formatDate(date: string | Date): string {
year: "numeric",
});
}
+
+export function debounce void>(
+ func: T,
+ wait: number
+): (...args: Parameters) => void {
+ let timeout: NodeJS.Timeout;
+
+ return function executedFunction(...args: Parameters) {
+ const later = () => {
+ clearTimeout(timeout);
+ func(...args);
+ };
+
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ };
+}