mirror of
https://github.com/booklore-app/booklore.git
synced 2026-02-18 00:17:53 +01:00
Persist sidebar filter state when toggling visibility
This commit is contained in:
committed by
Aditya Chandel
parent
0e4fb47580
commit
11289adf79
@@ -44,7 +44,8 @@
|
||||
<i
|
||||
class="pi pi-filter-slash"
|
||||
pTooltip="Clear applied filters"
|
||||
tooltipPosition="top">
|
||||
tooltipPosition="top"
|
||||
style="color: orange;">
|
||||
</i>
|
||||
</a>
|
||||
}
|
||||
@@ -83,7 +84,6 @@
|
||||
</p-popover>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
<a
|
||||
class="topbar-items topbar-item"
|
||||
@@ -117,6 +117,15 @@
|
||||
{{ coverScalePreferenceService.scaleFactor.toFixed(2) }}x
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="flex flex-col gap-2">
|
||||
<label class="font-medium text-sm">Show Sidebar Filters:</label>
|
||||
<div class="flex gap-4 justify-start">
|
||||
<p-toggle-switch
|
||||
[(ngModel)]="sidebarFilterTogglePrefService.selectedShowFilter"
|
||||
(onChange)="sidebarFilterTogglePrefService.selectedShowFilter = $event.checked">
|
||||
</p-toggle-switch>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="font-medium text-sm">Sidebar Filter Sort:</label>
|
||||
<div class="flex gap-4 justify-start">
|
||||
@@ -217,15 +226,13 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
<p-button
|
||||
class="pr-2"
|
||||
icon="pi pi-chevron-right"
|
||||
[outlined]="true"
|
||||
[rounded]="true"
|
||||
(click)="toggleFilterSidebar()"
|
||||
pTooltip="Toggle filter sidebar"
|
||||
tooltipPosition="top"
|
||||
/>
|
||||
<a class="topbar-items topbar-item" (click)="toggleSidebar()">
|
||||
<i
|
||||
[ngClass]="showFilter ? 'pi pi-angle-double-right' : 'pi pi-angle-double-left'"
|
||||
pTooltip="Toggle sidebar filters"
|
||||
tooltipPosition="top">
|
||||
</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -396,19 +403,23 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
@if (this.showFilter) {
|
||||
<div
|
||||
class="mobile-filter-mask"
|
||||
(click)="this.showFilter = false">
|
||||
</div>
|
||||
<app-book-filter
|
||||
[showFilter]="showFilter"
|
||||
class="filter-overlay-container z-50 flex-shrink-0"
|
||||
[ngClass]="{ 'active': showFilter, 'ml-4': showFilter }"
|
||||
[entity$]="entity$"
|
||||
[entityType$]="entityType$"
|
||||
[resetFilter$]="resetFilterSubject"
|
||||
(filterSelected)="onFilterSelected($event)"
|
||||
(filterModeChanged)="onFilterModeChanged($event)">
|
||||
</app-book-filter>
|
||||
}
|
||||
|
||||
<app-book-filter
|
||||
[showFilter]="showFilter"
|
||||
class="filter-overlay-container z-50 flex-shrink-0"
|
||||
[ngClass]="{ 'active': showFilter, 'ml-4': showFilter }"
|
||||
[entity$]="entity$"
|
||||
[entityType$]="entityType$"
|
||||
[resetFilter$]="resetFilterSubject">
|
||||
</app-book-filter>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {AfterViewInit, ChangeDetectorRef, Component, inject, OnInit, ViewChild} from '@angular/core';
|
||||
import {Component, inject, OnInit, ViewChild} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {ConfirmationService, MenuItem, MessageService, PrimeTemplate} from 'primeng/api';
|
||||
import {LibraryService} from '../../service/library.service';
|
||||
@@ -46,6 +46,7 @@ import {BookMenuService} from '../../service/book-menu.service';
|
||||
import {MagicShelf, MagicShelfService} from '../../../magic-shelf.service';
|
||||
import {BookRuleEvaluatorService} from '../../../book-rule-evaluator.service';
|
||||
import {GroupRule} from '../../../magic-shelf-component/magic-shelf-component';
|
||||
import {SidebarFilterTogglePrefService} from './filters/sidebar-filter-toggle-pref-service';
|
||||
|
||||
export enum EntityType {
|
||||
LIBRARY = 'Library',
|
||||
@@ -87,18 +88,19 @@ const SORT_DIRECTION = {
|
||||
providers: [SeriesCollapseFilter],
|
||||
animations: [
|
||||
trigger('slideInOut', [
|
||||
state('void', style({ transform: 'translateY(100%)' })),
|
||||
state('*', style({ transform: 'translateY(0)' })),
|
||||
transition(':enter', [ animate('0.1s ease-in') ]),
|
||||
transition(':leave', [ animate('0.1s ease-out') ])
|
||||
state('void', style({transform: 'translateY(100%)'})),
|
||||
state('*', style({transform: 'translateY(0)'})),
|
||||
transition(':enter', [animate('0.1s ease-in')]),
|
||||
transition(':leave', [animate('0.1s ease-out')])
|
||||
])
|
||||
]
|
||||
})
|
||||
export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
export class BookBrowserComponent implements OnInit {
|
||||
protected userService = inject(UserService);
|
||||
protected coverScalePreferenceService = inject(CoverScalePreferenceService);
|
||||
protected filterSortPreferenceService = inject(FilterSortPreferenceService);
|
||||
protected columnPreferenceService = inject(TableColumnPreferenceService);
|
||||
protected sidebarFilterTogglePrefService = inject(SidebarFilterTogglePrefService);
|
||||
private activatedRoute = inject(ActivatedRoute);
|
||||
private messageService = inject(MessageService);
|
||||
private libraryService = inject(LibraryService);
|
||||
@@ -108,7 +110,6 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
private bookMenuService = inject(BookMenuService);
|
||||
private sortService = inject(SortService);
|
||||
private router = inject(Router);
|
||||
private changeDetectorRef = inject(ChangeDetectorRef);
|
||||
private libraryShelfMenuService = inject(LibraryShelfMenuService);
|
||||
protected seriesCollapseFilter = inject(SeriesCollapseFilter);
|
||||
protected confirmationService = inject(ConfirmationService);
|
||||
@@ -148,14 +149,30 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
private headerFilter = new HeaderFilter(this.searchTerm$);
|
||||
protected bookSorter = new BookSorter(selectedSort => this.applySortOption(selectedSort));
|
||||
|
||||
@ViewChild(BookTableComponent) bookTableComponent!: BookTableComponent;
|
||||
@ViewChild(BookFilterComponent) bookFilterComponent!: BookFilterComponent;
|
||||
@ViewChild(BookTableComponent)
|
||||
bookTableComponent!: BookTableComponent;
|
||||
@ViewChild(BookFilterComponent, { static: false })
|
||||
bookFilterComponent!: BookFilterComponent;
|
||||
|
||||
get currentCardSize() { return this.coverScalePreferenceService.currentCardSize; }
|
||||
get gridColumnMinWidth(): string { return this.coverScalePreferenceService.gridColumnMinWidth; }
|
||||
get viewIcon(): string { return this.currentViewMode === VIEW_MODES.GRID ? 'pi pi-objects-column' : 'pi pi-table'; }
|
||||
get hasSidebarFilters(): boolean { return !!this.selectedFilter.value && Object.keys(this.selectedFilter.value).length > 0; }
|
||||
get isFilterActive(): boolean { return this.selectedFilter.value !== null; }
|
||||
get currentCardSize() {
|
||||
return this.coverScalePreferenceService.currentCardSize;
|
||||
}
|
||||
|
||||
get gridColumnMinWidth(): string {
|
||||
return this.coverScalePreferenceService.gridColumnMinWidth;
|
||||
}
|
||||
|
||||
get viewIcon(): string {
|
||||
return this.currentViewMode === VIEW_MODES.GRID ? 'pi pi-objects-column' : 'pi pi-table';
|
||||
}
|
||||
|
||||
get hasSidebarFilters(): boolean {
|
||||
return !!this.selectedFilter.value && Object.keys(this.selectedFilter.value).length > 0;
|
||||
}
|
||||
|
||||
get isFilterActive(): boolean {
|
||||
return this.selectedFilter.value !== null;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.coverScalePreferenceService.scaleChange$.pipe(debounceTime(1000)).subscribe();
|
||||
@@ -197,23 +214,22 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
() => this.multiBookEditMetadata()
|
||||
);
|
||||
this.tieredMenuItems = this.bookMenuService.getTieredMenuItems(this.selectedBooks);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
combineLatest({
|
||||
paramMap: this.activatedRoute.queryParamMap,
|
||||
user: this.userService.userState$.pipe(
|
||||
filter(userState => !!userState?.user && userState.loaded),
|
||||
take(1)
|
||||
)
|
||||
}).subscribe(({paramMap, user}) => {
|
||||
// --- NEW: Subscribe to query params + user changes for reactive updates ---
|
||||
combineLatest([
|
||||
this.activatedRoute.paramMap,
|
||||
this.activatedRoute.queryParamMap,
|
||||
this.userService.userState$.pipe(filter(u => !!u?.user && u.loaded))
|
||||
]).subscribe(([paramMap, queryParamMap, user]) => {
|
||||
|
||||
const viewParam = paramMap.get(QUERY_PARAMS.VIEW);
|
||||
const sortParam = paramMap.get(QUERY_PARAMS.SORT);
|
||||
const directionParam = paramMap.get(QUERY_PARAMS.DIRECTION);
|
||||
const filterParams = paramMap.get(QUERY_PARAMS.FILTER);
|
||||
const sidebarParam = paramMap.get(QUERY_PARAMS.SIDEBAR);
|
||||
this.showFilter = sidebarParam === null ? true : sidebarParam === 'true';
|
||||
const viewParam = queryParamMap.get(QUERY_PARAMS.VIEW);
|
||||
const sortParam = queryParamMap.get(QUERY_PARAMS.SORT);
|
||||
const directionParam = queryParamMap.get(QUERY_PARAMS.DIRECTION);
|
||||
const filterParams = queryParamMap.get(QUERY_PARAMS.FILTER);
|
||||
|
||||
this.sidebarFilterTogglePrefService.showFilter$.subscribe(value => {
|
||||
this.showFilter = value;
|
||||
});
|
||||
|
||||
const parsedFilters: Record<string, string[]> = {};
|
||||
|
||||
@@ -229,8 +245,10 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
});
|
||||
|
||||
this.selectedFilter.next(parsedFilters);
|
||||
this.bookFilterComponent.setFilters?.(parsedFilters);
|
||||
this.bookFilterComponent.onFiltersChanged?.();
|
||||
if(this.bookFilterComponent) {
|
||||
this.bookFilterComponent.setFilters?.(parsedFilters);
|
||||
this.bookFilterComponent.onFiltersChanged?.();
|
||||
}
|
||||
|
||||
const firstFilter = filterParams.split(',')[0];
|
||||
const [key, ...values] = firstFilter.split(':');
|
||||
@@ -256,7 +274,6 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
this.columnPreferenceService.initPreferences(user.user?.userSettings?.tableColumnPreference);
|
||||
this.visibleColumns = this.columnPreferenceService.visibleColumns;
|
||||
|
||||
|
||||
const override = this.entityViewPreferences?.overrides?.find(o =>
|
||||
o.entityType?.toUpperCase() === currentEntityTypeStr &&
|
||||
o.entityId === this.entity?.id
|
||||
@@ -289,7 +306,7 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
direction: SortDirection.DESCENDING
|
||||
};
|
||||
|
||||
const fromParam = paramMap.get(QUERY_PARAMS.FROM);
|
||||
const fromParam = queryParamMap.get(QUERY_PARAMS.FROM);
|
||||
this.currentViewMode = fromParam === 'toggle'
|
||||
? (viewParam === VIEW_MODES.TABLE || viewParam === VIEW_MODES.GRID
|
||||
? viewParam
|
||||
@@ -306,8 +323,7 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
const queryParams: any = {
|
||||
[QUERY_PARAMS.VIEW]: this.currentViewMode,
|
||||
[QUERY_PARAMS.SORT]: this.bookSorter.selectedSort.field,
|
||||
[QUERY_PARAMS.DIRECTION]: this.bookSorter.selectedSort.direction === SortDirection.ASCENDING ? SORT_DIRECTION.ASCENDING : SORT_DIRECTION.DESCENDING,
|
||||
[QUERY_PARAMS.SIDEBAR]: this.showFilter.toString()
|
||||
[QUERY_PARAMS.DIRECTION]: this.bookSorter.selectedSort.direction === SortDirection.ASCENDING ? SORT_DIRECTION.ASCENDING : SORT_DIRECTION.DESCENDING
|
||||
};
|
||||
|
||||
if (Object.keys(parsedFilters).length > 0) {
|
||||
@@ -316,29 +332,13 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
|
||||
const currentParams = this.activatedRoute.snapshot.queryParams;
|
||||
const changed = Object.keys(queryParams).some(k => currentParams[k] !== queryParams[k]);
|
||||
|
||||
if (changed) {
|
||||
const mergedParams = {...currentParams, ...queryParams};
|
||||
this.router.navigate([], {
|
||||
queryParams,
|
||||
queryParams: mergedParams,
|
||||
replaceUrl: true
|
||||
});
|
||||
}
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
});
|
||||
|
||||
this.bookFilterComponent.filterSelected.subscribe((filters: Record<string, any> | null) => {
|
||||
if (this.settingFiltersFromUrl) return;
|
||||
|
||||
this.selectedFilter.next(filters);
|
||||
this.rawFilterParamFromUrl = null;
|
||||
|
||||
const hasSidebarFilters = !!filters && Object.keys(filters).length > 0;
|
||||
this.currentFilterLabel = hasSidebarFilters ? 'All Books (Filtered)' : 'All Books';
|
||||
});
|
||||
|
||||
this.bookFilterComponent.filterModeChanged.subscribe((mode: 'and' | 'or') => {
|
||||
this.selectedFilterMode.next(mode);
|
||||
});
|
||||
|
||||
this.searchTerm$.subscribe(term => {
|
||||
@@ -346,6 +346,25 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
});
|
||||
}
|
||||
|
||||
onFilterSelected(filters: Record<string, any> | null): void {
|
||||
if (this.settingFiltersFromUrl) return;
|
||||
|
||||
this.selectedFilter.next(filters);
|
||||
this.rawFilterParamFromUrl = null;
|
||||
|
||||
const hasSidebarFilters = !!filters && Object.keys(filters).length > 0;
|
||||
this.currentFilterLabel = hasSidebarFilters ? 'All Books (Filtered)' : 'All Books';
|
||||
}
|
||||
|
||||
onFilterModeChanged(mode: 'and' | 'or'): void {
|
||||
this.selectedFilterMode.next(mode);
|
||||
}
|
||||
|
||||
toggleSidebar(): void {
|
||||
this.showFilter = !this.showFilter;
|
||||
this.sidebarFilterTogglePrefService.selectedShowFilter = this.showFilter;
|
||||
}
|
||||
|
||||
updateScale(): void {
|
||||
this.coverScalePreferenceService.setScale(this.coverScalePreferenceService.scaleFactor);
|
||||
}
|
||||
@@ -476,18 +495,6 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
this.clearSearch();
|
||||
}
|
||||
|
||||
toggleFilterSidebar() {
|
||||
this.showFilter = !this.showFilter;
|
||||
const currentParams = this.activatedRoute.snapshot.queryParams;
|
||||
this.router.navigate([], {
|
||||
queryParams: {
|
||||
...currentParams,
|
||||
[QUERY_PARAMS.SIDEBAR]: this.showFilter.toString()
|
||||
},
|
||||
replaceUrl: true
|
||||
});
|
||||
}
|
||||
|
||||
toggleTableGrid(): void {
|
||||
this.currentViewMode = this.currentViewMode === VIEW_MODES.GRID ? VIEW_MODES.TABLE : VIEW_MODES.GRID;
|
||||
this.router.navigate([], {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component, EventEmitter, ChangeDetectionStrategy, inject, Input, OnDestroy, OnInit, Output} from '@angular/core';
|
||||
import {combineLatest, Observable, of, Subject, debounceTime, distinctUntilChanged, takeUntil, shareReplay} from 'rxjs';
|
||||
import {ChangeDetectionStrategy, Component, EventEmitter, inject, Input, OnDestroy, OnInit, Output} from '@angular/core';
|
||||
import {combineLatest, distinctUntilChanged, Observable, of, shareReplay, Subject, takeUntil} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {BookService} from '../../../service/book.service';
|
||||
import {Library} from '../../../model/library.model';
|
||||
@@ -152,7 +152,7 @@ export class BookFilterComponent implements OnInit, OnDestroy {
|
||||
private filterChangeSubject = new Subject<Record<string, any> | null>();
|
||||
|
||||
@Output() filterSelected = new EventEmitter<Record<string, any> | null>();
|
||||
@Output('filterMode') filterModeChanged = new EventEmitter<'and' | 'or'>();
|
||||
@Output() filterModeChanged = new EventEmitter<'and' | 'or'>();
|
||||
|
||||
@Input() entity$!: Observable<Library | Shelf | MagicShelf | null> | undefined;
|
||||
@Input() entityType$!: Observable<EntityType> | undefined;
|
||||
@@ -204,8 +204,8 @@ export class BookFilterComponent implements OnInit, OnDestroy {
|
||||
this.filterStreams = {
|
||||
// Temporarily disabled until we can optimize for large libraries
|
||||
/*author: this.getFilterStream((book: Book) => book.metadata?.authors!.map(name => ({id: name, name})) || [], 'id', 'name', sortMode),
|
||||
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),*/
|
||||
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) => {
|
||||
let status = book.readStatus;
|
||||
@@ -231,7 +231,6 @@ export class BookFilterComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.filterChangeSubject.pipe(
|
||||
debounceTime(10),
|
||||
takeUntil(this.destroy$)
|
||||
).subscribe(value => this.filterSelected.emit(value));
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {BookFilter} from './BookFilter';
|
||||
import {BookState} from '../../../model/state/book-state.model';
|
||||
import {Observable} from 'rxjs';
|
||||
import {map, debounceTime, distinctUntilChanged} from 'rxjs/operators';
|
||||
import {Observable, of} from 'rxjs';
|
||||
import {map, debounceTime, distinctUntilChanged, switchMap} from 'rxjs/operators';
|
||||
|
||||
export class HeaderFilter implements BookFilter {
|
||||
|
||||
@@ -13,30 +13,35 @@ export class HeaderFilter implements BookFilter {
|
||||
str.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
|
||||
|
||||
return this.searchTerm$.pipe(
|
||||
debounceTime(500),
|
||||
distinctUntilChanged(),
|
||||
map(term => {
|
||||
const normalizedTerm = normalize(term || '');
|
||||
if (normalizedTerm && normalizedTerm.trim() !== '') {
|
||||
const filteredBooks = bookState.books?.filter(book => {
|
||||
const title = book.metadata?.title || '';
|
||||
const series = book.metadata?.seriesName || '';
|
||||
const authors = book.metadata?.authors || [];
|
||||
const categories = book.metadata?.categories || [];
|
||||
const isbn = book.metadata?.isbn10 || '';
|
||||
const isbn13 = book.metadata?.isbn13 || '';
|
||||
|
||||
const matchesTitle = normalize(title).includes(normalizedTerm);
|
||||
const matchesSeries = normalize(series).includes(normalizedTerm);
|
||||
const matchesAuthor = authors.some(author => normalize(author).includes(normalizedTerm));
|
||||
const matchesCategory = categories.some(category => normalize(category).includes(normalizedTerm));
|
||||
const matchesIsbn = normalize(isbn).includes(normalizedTerm) || normalize(isbn13).includes(normalizedTerm);
|
||||
|
||||
return matchesTitle || matchesSeries || matchesAuthor || matchesCategory || matchesIsbn;
|
||||
}) || null;
|
||||
return {...bookState, books: filteredBooks};
|
||||
switchMap(term => {
|
||||
const normalizedTerm = normalize(term || '').trim();
|
||||
if (!normalizedTerm) {
|
||||
return of(bookState);
|
||||
}
|
||||
return bookState;
|
||||
return of(normalizedTerm).pipe(
|
||||
debounceTime(500),
|
||||
map(nTerm => {
|
||||
const filteredBooks = bookState.books?.filter(book => {
|
||||
const title = book.metadata?.title || '';
|
||||
const series = book.metadata?.seriesName || '';
|
||||
const authors = book.metadata?.authors || [];
|
||||
const categories = book.metadata?.categories || [];
|
||||
const isbn = book.metadata?.isbn10 || '';
|
||||
const isbn13 = book.metadata?.isbn13 || '';
|
||||
|
||||
const matchesTitle = normalize(title).includes(nTerm);
|
||||
const matchesSeries = normalize(series).includes(nTerm);
|
||||
const matchesAuthor = authors.some(author => normalize(author).includes(nTerm));
|
||||
const matchesCategory = categories.some(category => normalize(category).includes(nTerm));
|
||||
const matchesIsbn = normalize(isbn).includes(nTerm) || normalize(isbn13).includes(nTerm);
|
||||
|
||||
return matchesTitle || matchesSeries || matchesAuthor || matchesCategory || matchesIsbn;
|
||||
}) || null;
|
||||
|
||||
return {...bookState, books: filteredBooks};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import {inject, Injectable} from '@angular/core';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {MessageService} from 'primeng/api';
|
||||
import {LocalStorageService} from '../../../../core/service/local-storage-service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SidebarFilterTogglePrefService {
|
||||
|
||||
private readonly STORAGE_KEY = 'showSidebarFilter';
|
||||
private readonly messageService = inject(MessageService);
|
||||
private readonly localStorageService = inject(LocalStorageService);
|
||||
|
||||
private readonly showFilterSubject = new BehaviorSubject<boolean>(true);
|
||||
readonly showFilter$ = this.showFilterSubject.asObservable();
|
||||
|
||||
constructor() {
|
||||
this.loadFromStorage();
|
||||
}
|
||||
|
||||
get selectedShowFilter(): boolean {
|
||||
return this.showFilterSubject.value;
|
||||
}
|
||||
|
||||
set selectedShowFilter(value: boolean) {
|
||||
if (this.showFilterSubject.value !== value) {
|
||||
this.showFilterSubject.next(value);
|
||||
this.savePreference(value);
|
||||
}
|
||||
}
|
||||
|
||||
toggle(): void {
|
||||
this.selectedShowFilter = !this.selectedShowFilter;
|
||||
}
|
||||
|
||||
private savePreference(value: boolean): void {
|
||||
try {
|
||||
this.localStorageService.set(this.STORAGE_KEY, value);
|
||||
} catch (e) {
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Save Failed',
|
||||
detail: 'Could not save sidebar filter preference locally.',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private loadFromStorage(): void {
|
||||
const saved = this.localStorageService.get<boolean>(this.STORAGE_KEY);
|
||||
if (saved !== null) {
|
||||
this.showFilterSubject.next(saved);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user