feat(backoffice): add reading progress management, series page, and live search
- API: add POST /series/mark-read to batch mark all books in a series - API: add GET /series cross-library endpoint with search, library and status filters - API: add library_id to SeriesItem response - Backoffice: mark book as read/unread button on book detail page - Backoffice: mark series as read/unread button on series cards - Backoffice: new /series top-level page with search and filters - Backoffice: new /libraries/[id]/series/[name] series detail page - Backoffice: opacity on fully read books and series cards - Backoffice: live search with debounce on books and series pages - Backoffice: reading status filter on books and series pages - Fix $2 -> $1 parameter binding in mark-series-read SQL Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -112,6 +112,7 @@ export type SeriesDto = {
|
||||
book_count: number;
|
||||
books_read_count: number;
|
||||
first_book_id: string;
|
||||
library_id: string;
|
||||
};
|
||||
|
||||
export function config() {
|
||||
@@ -263,10 +264,12 @@ export async function fetchBooks(
|
||||
series?: string,
|
||||
page: number = 1,
|
||||
limit: number = 50,
|
||||
readingStatus?: string,
|
||||
): Promise<BooksPageDto> {
|
||||
const params = new URLSearchParams();
|
||||
if (libraryId) params.set("library_id", libraryId);
|
||||
if (series) params.set("series", series);
|
||||
if (readingStatus) params.set("reading_status", readingStatus);
|
||||
params.set("page", page.toString());
|
||||
params.set("limit", limit.toString());
|
||||
|
||||
@@ -294,6 +297,23 @@ export async function fetchSeries(
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchAllSeries(
|
||||
libraryId?: string,
|
||||
q?: string,
|
||||
readingStatus?: string,
|
||||
page: number = 1,
|
||||
limit: number = 50,
|
||||
): Promise<SeriesPageDto> {
|
||||
const params = new URLSearchParams();
|
||||
if (libraryId) params.set("library_id", libraryId);
|
||||
if (q) params.set("q", q);
|
||||
if (readingStatus) params.set("reading_status", readingStatus);
|
||||
params.set("page", page.toString());
|
||||
params.set("limit", limit.toString());
|
||||
|
||||
return apiFetch<SeriesPageDto>(`/series?${params.toString()}`);
|
||||
}
|
||||
|
||||
export async function searchBooks(
|
||||
query: string,
|
||||
libraryId?: string,
|
||||
@@ -398,3 +418,10 @@ export async function updateReadingProgress(
|
||||
body: JSON.stringify({ status, current_page: currentPage ?? null }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function markSeriesRead(seriesName: string, status: "read" | "unread" = "read") {
|
||||
return apiFetch<{ updated: number }>("/series/mark-read", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ series: seriesName, status }),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user