mirror of
https://github.com/booklore-app/booklore.git
synced 2025-12-23 22:28:11 -05:00
Generalize DashboardScrollerComponent and display Latest Added Books
This commit is contained in:
@@ -37,10 +37,14 @@ public class BookController {
|
||||
@RequestParam(defaultValue = "25") @Min(1) @Max(100) int size,
|
||||
@RequestParam(defaultValue = "lastReadTime") String sortBy,
|
||||
@RequestParam(defaultValue = "desc") String sortDir) {
|
||||
if (!sortBy.equals("lastReadTime") && !sortBy.equals("addedOn")) {
|
||||
return ResponseEntity.badRequest().body(null);
|
||||
}
|
||||
Page<BookDTO> books = booksService.getBooks(page, size, sortBy, sortDir);
|
||||
return ResponseEntity.ok(books);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/search")
|
||||
public ResponseEntity<List<BookDTO>> searchBooks(@RequestParam String title) {
|
||||
List<BookDTO> books = booksService.search(title);
|
||||
|
||||
@@ -15,5 +15,6 @@ public class BookDTO {
|
||||
private String fileName;
|
||||
private String title;
|
||||
private Instant lastReadTime;
|
||||
private Instant addedOn;
|
||||
private List<AuthorDTO> authors = new ArrayList<>();
|
||||
}
|
||||
|
||||
@@ -44,4 +44,7 @@ public class Book {
|
||||
|
||||
@Column(name = "last_read_time")
|
||||
private Instant lastReadTime;
|
||||
|
||||
@Column(name = "added_on")
|
||||
private Instant addedOn;
|
||||
}
|
||||
|
||||
@@ -21,5 +21,7 @@ public interface BookRepository extends JpaRepository<Book, Long>, JpaSpecificat
|
||||
List<Book> findByTitleContainingIgnoreCase(String title);
|
||||
|
||||
Page<Book> findByLastReadTimeIsNotNull(Pageable pageable);
|
||||
|
||||
Page<Book> findByAddedOnIsNotNull(Pageable pageable);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,12 @@ public class BooksService {
|
||||
public Page<BookDTO> getBooks(int page, int size, String sortBy, String sortDir) {
|
||||
Sort sort = Sort.by(Sort.Direction.fromString(sortDir), sortBy);
|
||||
PageRequest pageRequest = PageRequest.of(page, size, sort);
|
||||
Page<Book> bookPage = bookRepository.findByLastReadTimeIsNotNull(pageRequest);
|
||||
Page<Book> bookPage = Page.empty();
|
||||
if (sortBy.equals("addedOn")) {
|
||||
bookPage = bookRepository.findByAddedOnIsNotNull(pageRequest);
|
||||
} else if (sortBy.equals("lastReadTime")) {
|
||||
bookPage = bookRepository.findByLastReadTimeIsNotNull(pageRequest);
|
||||
}
|
||||
List<BookDTO> bookDTOs = bookPage.getContent().stream()
|
||||
.map(BookTransformer::convertToBookDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -14,6 +14,7 @@ public class BookTransformer {
|
||||
bookDTO.setFileName(book.getFileName());
|
||||
bookDTO.setTitle(book.getTitle());
|
||||
bookDTO.setLastReadTime(book.getLastReadTime());
|
||||
bookDTO.setAddedOn(book.getAddedOn());
|
||||
bookDTO.setAuthors(book.getAuthors().stream().map(AuthorTransformer::toAuthorDTO).collect(Collectors.toList()));
|
||||
return bookDTO;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ CREATE TABLE IF NOT EXISTS book
|
||||
library_id BIGINT NOT NULL,
|
||||
path VARCHAR(1000) NOT NULL,
|
||||
last_read_time TIMESTAMP NULL,
|
||||
added_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_library FOREIGN KEY (library_id) REFERENCES library (id) ON DELETE CASCADE,
|
||||
CONSTRAINT unique_file_library UNIQUE (file_name, library_id),
|
||||
INDEX idx_library_id (library_id),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="book-list-container">
|
||||
<h2 class="last-read-title">Last Read</h2>
|
||||
<h2 class="last-read-title">{{ title }}</h2>
|
||||
<div class="book-list"
|
||||
infiniteScroll
|
||||
[infiniteScrollDistance]="2"
|
||||
@@ -7,6 +7,7 @@
|
||||
(scrolled)="loadMore()"
|
||||
#scrollContainer
|
||||
(scroll)="onScroll($event)">
|
||||
|
||||
<div class="book-item" *ngFor="let book of books">
|
||||
<img [src]="coverImageSrc(book.id)" class="book-cover" alt="Cover of {{ book.title }}" loading="lazy"/>
|
||||
<div class="book-info">
|
||||
@@ -17,4 +18,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
|
||||
import { Book } from '../../model/book.model';
|
||||
import { BookService } from '../../service/book.service';
|
||||
import { Button } from 'primeng/button';
|
||||
import { InfiniteScrollDirective } from 'ngx-infinite-scroll';
|
||||
import { NgForOf } from '@angular/common';
|
||||
import {Component, OnInit, ViewChild, ElementRef, Input} from '@angular/core';
|
||||
import {Book} from '../../model/book.model';
|
||||
import {BookService} from '../../service/book.service';
|
||||
import {Button} from 'primeng/button';
|
||||
import {InfiniteScrollDirective} from 'ngx-infinite-scroll';
|
||||
import {NgForOf} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard-scroller',
|
||||
@@ -16,27 +16,45 @@ import { NgForOf } from '@angular/common';
|
||||
styleUrls: ['./dashboard-scroller.component.scss']
|
||||
})
|
||||
export class DashboardScrollerComponent implements OnInit {
|
||||
|
||||
@Input() bookListType: 'lastRead' | 'latestAdded' = 'lastRead';
|
||||
@Input() title: string = 'Last Read Books';
|
||||
|
||||
|
||||
books: Book[] = [];
|
||||
private currentPage: number = 0;
|
||||
|
||||
@ViewChild('scrollContainer') scrollContainer!: ElementRef;
|
||||
|
||||
constructor(private bookService: BookService) {}
|
||||
constructor(private bookService: BookService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadBooks();
|
||||
}
|
||||
|
||||
loadBooks(): void {
|
||||
this.bookService.loadLatestBooks(this.currentPage).subscribe({
|
||||
next: (response) => {
|
||||
this.books = [...this.books, ...response.content];
|
||||
this.currentPage++;
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error loading books:', err);
|
||||
},
|
||||
});
|
||||
if (this.bookListType === 'lastRead') {
|
||||
this.bookService.loadLatestBooks(this.currentPage).subscribe({
|
||||
next: (response) => {
|
||||
this.books = [...this.books, ...response.content];
|
||||
this.currentPage++;
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error loading books:', err);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.bookService.loadLatestAddedBooks(this.currentPage).subscribe({
|
||||
next: (response) => {
|
||||
this.books = [...this.books, ...response.content];
|
||||
this.currentPage++;
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error loading books:', err);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
coverImageSrc(bookId: number): string {
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
</div>
|
||||
|
||||
<ng-template #dashboardScroller>
|
||||
<app-dashboard-scroller></app-dashboard-scroller>
|
||||
<app-dashboard-scroller [bookListType]="'lastRead'" title="Last Read Books"></app-dashboard-scroller>
|
||||
<app-dashboard-scroller [bookListType]="'latestAdded'" title="Latest Added Books"></app-dashboard-scroller>
|
||||
</ng-template>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -30,6 +30,13 @@ export class BookService {
|
||||
);
|
||||
}
|
||||
|
||||
loadLatestAddedBooks(page: number): Observable<PaginatedBooksResponse> {
|
||||
return this.http.get<PaginatedBooksResponse>(
|
||||
`${this.bookUrl}?page=${page}&size=10&sortBy=addedOn&sortDir=desc`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
searchBooks(query: string): Observable<Book[]> {
|
||||
if (query.length < 2) {
|
||||
return new Observable<Book[]>();
|
||||
|
||||
Reference in New Issue
Block a user