feat: add authors page to backoffice with dedicated API endpoint
Add a new GET /authors endpoint that aggregates unique authors from books with book/series counts, pagination and search. Add author filter to GET /books. Backoffice gets a list page with search/sort and a detail page showing the author's series and books. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -284,12 +284,14 @@ export async function fetchBooks(
|
||||
limit: number = 50,
|
||||
readingStatus?: string,
|
||||
sort?: string,
|
||||
author?: 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);
|
||||
if (sort) params.set("sort", sort);
|
||||
if (author) params.set("author", author);
|
||||
params.set("page", page.toString());
|
||||
params.set("limit", limit.toString());
|
||||
|
||||
@@ -552,6 +554,38 @@ export async function fetchStats() {
|
||||
return apiFetch<StatsResponse>("/stats");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Authors
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export type AuthorDto = {
|
||||
name: string;
|
||||
book_count: number;
|
||||
series_count: number;
|
||||
};
|
||||
|
||||
export type AuthorsPageDto = {
|
||||
items: AuthorDto[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
};
|
||||
|
||||
export async function fetchAuthors(
|
||||
q?: string,
|
||||
page: number = 1,
|
||||
limit: number = 20,
|
||||
sort?: string,
|
||||
): Promise<AuthorsPageDto> {
|
||||
const params = new URLSearchParams();
|
||||
if (q) params.set("q", q);
|
||||
if (sort) params.set("sort", sort);
|
||||
params.set("page", page.toString());
|
||||
params.set("limit", limit.toString());
|
||||
|
||||
return apiFetch<AuthorsPageDto>(`/authors?${params.toString()}`);
|
||||
}
|
||||
|
||||
export type UpdateBookRequest = {
|
||||
title: string;
|
||||
author: string | null;
|
||||
|
||||
@@ -113,6 +113,20 @@ const en: Record<TranslationKey, string> = {
|
||||
"series.missingCount": "{{count}} missing",
|
||||
"series.readCount": "{{read}}/{{total}} read",
|
||||
|
||||
// Authors page
|
||||
"nav.authors": "Authors",
|
||||
"authors.title": "Authors",
|
||||
"authors.searchPlaceholder": "Search by author name...",
|
||||
"authors.bookCount": "{{count}} book{{plural}}",
|
||||
"authors.seriesCount": "{{count}} serie{{plural}}",
|
||||
"authors.noResults": "No authors found matching your filters",
|
||||
"authors.noAuthors": "No authors available",
|
||||
"authors.matchingQuery": "matching",
|
||||
"authors.sortName": "Name",
|
||||
"authors.sortBooks": "Book count",
|
||||
"authors.booksBy": "Books by {{name}}",
|
||||
"authors.seriesBy": "Series by {{name}}",
|
||||
|
||||
// Libraries page
|
||||
"libraries.title": "Libraries",
|
||||
"libraries.addLibrary": "Add a library",
|
||||
|
||||
@@ -111,6 +111,20 @@ const fr = {
|
||||
"series.missingCount": "{{count}} manquant{{plural}}",
|
||||
"series.readCount": "{{read}}/{{total}} lu{{plural}}",
|
||||
|
||||
// Authors page
|
||||
"nav.authors": "Auteurs",
|
||||
"authors.title": "Auteurs",
|
||||
"authors.searchPlaceholder": "Rechercher par nom d'auteur...",
|
||||
"authors.bookCount": "{{count}} livre{{plural}}",
|
||||
"authors.seriesCount": "{{count}} série{{plural}}",
|
||||
"authors.noResults": "Aucun auteur trouvé correspondant à vos filtres",
|
||||
"authors.noAuthors": "Aucun auteur disponible",
|
||||
"authors.matchingQuery": "correspondant à",
|
||||
"authors.sortName": "Nom",
|
||||
"authors.sortBooks": "Nombre de livres",
|
||||
"authors.booksBy": "Livres de {{name}}",
|
||||
"authors.seriesBy": "Séries de {{name}}",
|
||||
|
||||
// Libraries page
|
||||
"libraries.title": "Bibliothèques",
|
||||
"libraries.addLibrary": "Ajouter une bibliothèque",
|
||||
|
||||
Reference in New Issue
Block a user