Generalize DashboardScrollerComponent and display Latest Added Books

This commit is contained in:
aditya.chandel
2024-12-13 16:58:20 -07:00
parent 033fc95373
commit 96a04621e1
11 changed files with 63 additions and 20 deletions

View File

@@ -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);

View File

@@ -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<>();
}

View File

@@ -44,4 +44,7 @@ public class Book {
@Column(name = "last_read_time")
private Instant lastReadTime;
@Column(name = "added_on")
private Instant addedOn;
}

View File

@@ -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);
}

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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),

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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[]>();