Archived
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
670101b61e |
@@ -69,7 +69,7 @@ Enable users to search books within the library and discover new books via filte
|
|||||||
- **Search bar** at top: text input with debounced `onChange` → calls API with `q` param
|
- **Search bar** at top: text input with debounced `onChange` → calls API with `q` param
|
||||||
- **Filter row**: genre dropdown, author dropdown, reading status dropdown
|
- **Filter row**: genre dropdown, author dropdown, reading status dropdown
|
||||||
- Genre/Author dropdowns populated from `/api/books/genres/` and `/api/books/authors/`
|
- Genre/Author dropdowns populated from `/api/books/genres/` and `/api/books/authors/`
|
||||||
- Reading status uses static enum values
|
- Reading status uses static enum values (`READING_STATUS_OPTIONS`)
|
||||||
- **Results grid**: card layout showing cover, title, author, reading status badge
|
- **Results grid**: card layout showing cover, title, author, reading status badge
|
||||||
- **Empty state**: "No books found" with clear message when results are empty
|
- **Empty state**: "No books found" with clear message when results are empty
|
||||||
- **Loading state**: spinner/skeleton while fetching
|
- **Loading state**: spinner/skeleton while fetching
|
||||||
@@ -80,6 +80,15 @@ Enable users to search books within the library and discover new books via filte
|
|||||||
- Back button to return to library
|
- Back button to return to library
|
||||||
- Clean, mobile-responsive layout
|
- Clean, mobile-responsive layout
|
||||||
|
|
||||||
|
### API Client — `frontend/src/api/books.ts`
|
||||||
|
|
||||||
|
| Method | Endpoint | Returns |
|
||||||
|
|--------|----------|---------|
|
||||||
|
| `searchBooks(params)` | `GET /api/books/` | `{count, results: BookListItem[]}` |
|
||||||
|
| `getBook(id)` | `GET /api/books/{id}/` | `BookDetail` |
|
||||||
|
| `getGenres()` | `GET /api/books/genres/` | `string[]` |
|
||||||
|
| `getAuthors()` | `GET /api/books/authors/` | `string[]` |
|
||||||
|
|
||||||
## Routes (Frontend)
|
## Routes (Frontend)
|
||||||
| Path | Component | Auth |
|
| Path | Component | Auth |
|
||||||
|------|-----------|------|
|
|------|-----------|------|
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
import api from "./client";
|
import api from "./client";
|
||||||
import type { ContentResponse, EBookDetail, EBookListItem, ReadingProgress, ReadingSettings, TocResponse } from "../types/book";
|
import type {
|
||||||
|
BookDetail,
|
||||||
|
BookListItem,
|
||||||
|
BookSearchParams,
|
||||||
|
ContentResponse,
|
||||||
|
EBookDetail,
|
||||||
|
EBookListItem,
|
||||||
|
ReadingProgress,
|
||||||
|
ReadingSettings,
|
||||||
|
TocResponse,
|
||||||
|
} from "../types/book";
|
||||||
|
|
||||||
export const booksApi = {
|
export const booksApi = {
|
||||||
async getEBooks(): Promise<EBookListItem[]> {
|
async getEBooks(): Promise<EBookListItem[]> {
|
||||||
@@ -12,6 +22,26 @@ export const booksApi = {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async searchBooks(params: BookSearchParams = {}): Promise<{ count: number; results: BookListItem[] }> {
|
||||||
|
const { data } = await api.get<{ count: number; results: BookListItem[] }>("/books/", { params });
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
async getBook(id: number): Promise<BookDetail> {
|
||||||
|
const { data } = await api.get<BookDetail>(`/books/${id}/`);
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
async getGenres(): Promise<string[]> {
|
||||||
|
const { data } = await api.get<string[]>("/books/genres/");
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
async getAuthors(): Promise<string[]> {
|
||||||
|
const { data } = await api.get<string[]>("/books/authors/");
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
async uploadEBook(
|
async uploadEBook(
|
||||||
file: File,
|
file: File,
|
||||||
title: string,
|
title: string,
|
||||||
|
|||||||
@@ -82,3 +82,21 @@ export interface ContentResponse {
|
|||||||
chapter_title: string;
|
chapter_title: string;
|
||||||
format: string;
|
format: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BookSearchParams {
|
||||||
|
q?: string;
|
||||||
|
genre?: string;
|
||||||
|
author?: string;
|
||||||
|
reading_status?: string;
|
||||||
|
ordering?: string;
|
||||||
|
page?: number;
|
||||||
|
page_size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const READING_STATUS_OPTIONS: { value: string; label: string }[] = [
|
||||||
|
{ value: "", label: "All Statuses" },
|
||||||
|
{ value: "want_to_read", label: "Want to Read" },
|
||||||
|
{ value: "reading", label: "Reading" },
|
||||||
|
{ value: "finished", label: "Finished" },
|
||||||
|
{ value: "dnf", label: "Did Not Finish" },
|
||||||
|
];
|
||||||
Reference in New Issue
Block a user