mirror of
https://github.com/adityachandelgit/BookLore.git
synced 2025-07-22 00:35:25 +00:00
Fix read status filter showing only “Unknown” with no results
This commit is contained in:

committed by
Aditya Chandel

parent
538854b397
commit
480eb92f7d
@ -58,23 +58,31 @@ public class BookService {
|
||||
public List<Book> getBookDTOs(boolean includeDescription) {
|
||||
BookLoreUser user = authenticationService.getAuthenticatedUser();
|
||||
boolean isAdmin = user.getPermissions().isAdmin();
|
||||
List<Book> books;
|
||||
if (isAdmin) {
|
||||
books = bookQueryService.getAllBooks(includeDescription);
|
||||
} else {
|
||||
Set<Long> libraryIds = user.getAssignedLibraries().stream()
|
||||
.map(Library::getId)
|
||||
.collect(Collectors.toSet());
|
||||
books = bookQueryService.getAllBooksByLibraryIds(libraryIds, includeDescription);
|
||||
}
|
||||
Map<Long, UserBookProgressEntity> progressMap = userProgressService.fetchUserProgress(user.getId(), books.stream().map(Book::getId).collect(Collectors.toSet()));
|
||||
|
||||
List<Book> books = isAdmin
|
||||
? bookQueryService.getAllBooks(includeDescription)
|
||||
: bookQueryService.getAllBooksByLibraryIds(
|
||||
user.getAssignedLibraries().stream()
|
||||
.map(Library::getId)
|
||||
.collect(Collectors.toSet()),
|
||||
includeDescription
|
||||
);
|
||||
|
||||
Map<Long, UserBookProgressEntity> progressMap =
|
||||
userProgressService.fetchUserProgress(
|
||||
user.getId(),
|
||||
books.stream().map(Book::getId).collect(Collectors.toSet())
|
||||
);
|
||||
|
||||
books.forEach(book -> {
|
||||
UserBookProgressEntity progress = progressMap.get(book.getId());
|
||||
if (progress != null) {
|
||||
setBookProgress(book, progress);
|
||||
book.setLastReadTime(progress.getLastReadTime());
|
||||
book.setReadStatus(String.valueOf(progress.getReadStatus()));
|
||||
}
|
||||
});
|
||||
|
||||
return books;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Component, EventEmitter, inject, Input, OnDestroy, OnInit, Output} from '@angular/core';
|
||||
import {BehaviorSubject, combineLatest, Observable, of, Subject, takeUntil} from 'rxjs';
|
||||
import {distinctUntilChanged, filter, map, take} from 'rxjs/operators';
|
||||
import {combineLatest, Observable, of, Subject, takeUntil} from 'rxjs';
|
||||
import {distinctUntilChanged, map} from 'rxjs/operators';
|
||||
import {BookService} from '../../../service/book.service';
|
||||
import {Library} from '../../../model/library.model';
|
||||
import {Shelf} from '../../../model/shelf.model';
|
||||
@ -25,7 +25,7 @@ export const ratingRanges = [
|
||||
{id: '4.5plus', label: '4.5+', min: 4.5, max: Infinity, sortIndex: 5}
|
||||
];
|
||||
|
||||
export const ratingOptions10 = Array.from({ length: 10 }, (_, i) => ({
|
||||
export const ratingOptions10 = Array.from({length: 10}, (_, i) => ({
|
||||
id: `${i + 1}`,
|
||||
label: `${i + 1}`,
|
||||
value: i + 1,
|
||||
@ -83,7 +83,7 @@ function getRatingRangeFilters(rating?: number): { id: string; name: string; sor
|
||||
function getRatingRangeFilters10(rating?: number): { id: string; name: string; sortIndex?: number }[] {
|
||||
if (!rating || rating < 1 || rating > 10) return [];
|
||||
const idx = ratingOptions10.find(r => r.value === rating || +r.id === rating);
|
||||
return idx ? [{ id: idx.id, name: idx.label, sortIndex: idx.sortIndex }] : [];
|
||||
return idx ? [{id: idx.id, name: idx.label, sortIndex: idx.sortIndex}] : [];
|
||||
}
|
||||
|
||||
function extractPublishedYearFilter(book: Book): { id: number; name: string }[] {
|
||||
@ -119,10 +119,11 @@ const readStatusLabels: Record<ReadStatus, string> = {
|
||||
[ReadStatus.READ]: 'Read',
|
||||
[ReadStatus.WONT_READ]: 'Won’t Read',
|
||||
[ReadStatus.ABANDONED]: 'Abandoned',
|
||||
[ReadStatus.UNSET]: 'Unset'
|
||||
};
|
||||
|
||||
function getReadStatusName(status?: ReadStatus | null): string {
|
||||
return status != null ? readStatusLabels[status] ?? 'Unknown' : 'Unknown';
|
||||
return status != null ? readStatusLabels[status] ?? 'Unset' : 'Unset';
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -198,7 +199,13 @@ export class BookFilterComponent implements OnInit, OnDestroy {
|
||||
category: this.getFilterStream((book: Book) => book.metadata?.categories!.map(name => ({id: name, name})) || [], 'id', 'name', sortMode),
|
||||
series: this.getFilterStream((book) => (book.metadata?.seriesName ? [{id: book.metadata.seriesName, name: book.metadata.seriesName}] : []), 'id', 'name', sortMode),
|
||||
publisher: this.getFilterStream((book) => (book.metadata?.publisher ? [{id: book.metadata.publisher, name: book.metadata.publisher}] : []), 'id', 'name', sortMode),
|
||||
readStatus: this.getFilterStream((book: Book) => [{id: book.readStatus ?? ReadStatus.UNREAD, name: getReadStatusName(book.readStatus)}], 'id', 'name', sortMode),
|
||||
readStatus: this.getFilterStream((book: Book) => {
|
||||
let status = book.readStatus;
|
||||
if (status == null || !(status in readStatusLabels)) {
|
||||
status = ReadStatus.UNSET;
|
||||
}
|
||||
return [{id: status, name: getReadStatusName(status)}];
|
||||
}, 'id', 'name', sortMode),
|
||||
matchScore: this.getFilterStream((book: Book) => getMatchScoreRangeFilters(book.metadataMatchScore), 'id', 'name', 'sortIndex'),
|
||||
personalRating: this.getFilterStream((book: Book) => getRatingRangeFilters10(book.metadata?.personalRating!), 'id', 'name', 'sortIndex'),
|
||||
amazonRating: this.getFilterStream((book: Book) => getRatingRangeFilters(book.metadata?.amazonRating!), 'id', 'name', 'sortIndex'),
|
||||
|
@ -3,6 +3,7 @@ import {map} from 'rxjs/operators';
|
||||
import {BookFilter} from './BookFilter';
|
||||
import {BookState} from '../../../model/state/book-state.model';
|
||||
import {fileSizeRanges, matchScoreRanges, pageCountRanges, ratingRanges} from '../book-filter/book-filter.component';
|
||||
import {Book, ReadStatus} from '../../../model/book.model';
|
||||
|
||||
export function isRatingInRange(rating: number | undefined | null, rangeId: string): boolean {
|
||||
if (rating == null) return false;
|
||||
@ -37,6 +38,11 @@ export function isMatchScoreInRange(score: number | undefined | null, rangeId: s
|
||||
return score >= range.min && score < range.max;
|
||||
}
|
||||
|
||||
export function doesBookMatchReadStatus(book: Book, selected: string[]): boolean {
|
||||
const status = book.readStatus ?? ReadStatus.UNSET;
|
||||
return selected.includes(status);
|
||||
}
|
||||
|
||||
export class SideBarFilter implements BookFilter {
|
||||
|
||||
constructor(private selectedFilter$: Observable<any>, private selectedFilterMode$: Observable<'and' | 'or'>) {
|
||||
@ -69,7 +75,7 @@ export class SideBarFilter implements BookFilter {
|
||||
? filterValues.every(val => book.metadata?.seriesName === val)
|
||||
: filterValues.some(val => book.metadata?.seriesName === val);
|
||||
case 'readStatus':
|
||||
return filterValues.some(val => book.readStatus === val);
|
||||
return doesBookMatchReadStatus(book, filterValues);
|
||||
case 'amazonRating':
|
||||
return filterValues.some(range => isRatingInRange(book.metadata?.amazonRating, range));
|
||||
case 'goodreadsRating':
|
||||
|
@ -466,7 +466,7 @@ export class MetadataViewerComponent implements OnInit, OnChanges {
|
||||
}));
|
||||
|
||||
getStatusLabel(value: string): string {
|
||||
return this.readStatusOptions.find(o => o.value === value)?.label.toUpperCase() ?? 'N/A';
|
||||
return this.readStatusOptions.find(o => o.value === value)?.label.toUpperCase() ?? 'UNSET';
|
||||
}
|
||||
|
||||
updateReadStatus(status: ReadStatus): void {
|
||||
|
@ -222,5 +222,6 @@ export enum ReadStatus {
|
||||
PARTIALLY_READ = 'PARTIALLY_READ',
|
||||
PAUSED = 'PAUSED',
|
||||
WONT_READ = 'WONT_READ',
|
||||
ABANDONED = 'ABANDONED'
|
||||
ABANDONED = 'ABANDONED',
|
||||
UNSET = 'UNSET'
|
||||
}
|
||||
|
@ -403,6 +403,19 @@ export class BookService {
|
||||
);
|
||||
}
|
||||
|
||||
updateBookReadStatus(id: number, status: ReadStatus): Observable<void> {
|
||||
return this.http.put<void>(`${this.url}/${id}/read-status`, {status}).pipe(
|
||||
tap(() => {
|
||||
const currentState = this.bookStateSubject.value;
|
||||
if (!currentState.books) return;
|
||||
const updatedBooks = currentState.books.map(book =>
|
||||
book.id === id ? {...book, readStatus: status} : book
|
||||
);
|
||||
this.bookStateSubject.next({...currentState, books: updatedBooks});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*------------------ All the websocket handlers go below ------------------*/
|
||||
|
||||
@ -506,8 +519,4 @@ export class BookService {
|
||||
getBackupMetadata(bookId: number) {
|
||||
return this.http.get<any>(`${this.url}/${bookId}/metadata/restore`);
|
||||
}
|
||||
|
||||
updateBookReadStatus(id: number, status: ReadStatus): Observable<void> {
|
||||
return this.http.put<void>(`${this.url}/${id}/read-status`, {status});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user