]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.ts
LP1859241 Angular holds patron search dialog
[Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / catalog / result / results.component.ts
1 import {Component, OnInit, OnDestroy, Input} from '@angular/core';
2 import {Observable, Subscription} from 'rxjs';
3 import {map, switchMap, distinctUntilChanged} from 'rxjs/operators';
4 import {ActivatedRoute, ParamMap} from '@angular/router';
5 import {CatalogService} from '@eg/share/catalog/catalog.service';
6 import {BibRecordService} from '@eg/share/catalog/bib-record.service';
7 import {CatalogUrlService} from '@eg/share/catalog/catalog-url.service';
8 import {CatalogSearchContext, CatalogSearchState} from '@eg/share/catalog/search-context';
9 import {PcrudService} from '@eg/core/pcrud.service';
10 import {StaffCatalogService} from '../catalog.service';
11 import {IdlObject} from '@eg/core/idl.service';
12 import {BasketService} from '@eg/share/catalog/basket.service';
13
14 @Component({
15   selector: 'eg-catalog-results',
16   templateUrl: 'results.component.html'
17 })
18 export class ResultsComponent implements OnInit, OnDestroy {
19
20     searchContext: CatalogSearchContext;
21
22     // Cache record creator/editor since this will likely be a
23     // reasonably small set of data w/ lots of repitition.
24     userCache: {[id: number]: IdlObject} = {};
25
26     allRecsSelected: boolean;
27
28     searchSub: Subscription;
29     routeSub: Subscription;
30     basketSub: Subscription;
31
32     constructor(
33         private route: ActivatedRoute,
34         private pcrud: PcrudService,
35         private cat: CatalogService,
36         private bib: BibRecordService,
37         private catUrl: CatalogUrlService,
38         private staffCat: StaffCatalogService,
39         private basket: BasketService
40     ) {}
41
42     ngOnInit() {
43         this.searchContext = this.staffCat.searchContext;
44
45         // Our search context is initialized on page load.  Once
46         // ResultsComponent is active, it will not be reinitialized,
47         // even if the route parameters changes (unless we change the
48         // route reuse policy).  Watch for changes here to pick up new
49         // searches.
50         //
51         // This will also fire on page load.
52         this.routeSub =
53             this.route.queryParamMap.subscribe((params: ParamMap) => {
54
55               // TODO: Angular docs suggest using switchMap(), but
56               // it's not firing for some reason.  Also, could avoid
57               // firing unnecessary searches when a param unrelated to
58               // searching is changed by .map()'ing out only the desired
59               // params and running through .distinctUntilChanged(), but
60               // .map() is not firing either.  I'm missing something.
61               this.searchByUrl(params);
62         });
63
64         // After each completed search, update the record selector.
65         this.searchSub = this.cat.onSearchComplete.subscribe(
66             ctx => this.applyRecordSelection());
67
68         // Watch for basket changes applied by other components.
69         this.basketSub = this.basket.onChange.subscribe(
70             () => this.applyRecordSelection());
71     }
72
73     ngOnDestroy() {
74         if (this.routeSub) {
75             this.routeSub.unsubscribe();
76             this.searchSub.unsubscribe();
77             this.basketSub.unsubscribe();
78         }
79     }
80
81     // Apply the select-all checkbox when all visible records
82     // are selected.
83     applyRecordSelection() {
84         const ids = this.searchContext.currentResultIds();
85         let allChecked = true;
86         ids.forEach(id => {
87             if (!this.basket.hasRecordId(id)) {
88                 allChecked = false;
89             }
90         });
91         this.allRecsSelected = allChecked;
92     }
93
94     // Pull values from the URL and run the requested search.
95     searchByUrl(params: ParamMap): void {
96         this.catUrl.applyUrlParams(this.searchContext, params);
97
98         if (this.searchContext.isSearchable()) {
99
100             this.cat.search(this.searchContext)
101             .then(ok => {
102                 this.cat.fetchFacets(this.searchContext);
103                 this.cat.fetchBibSummaries(this.searchContext)
104                 .then(ok2 => this.fleshSearchResults());
105             });
106         }
107     }
108
109     // Records file into place randomly as the server returns data.
110     // To reduce page display shuffling, avoid showing the list of
111     // records until the first few are ready to render.
112     shouldStartRendering(): boolean {
113
114         if (this.searchHasResults()) {
115             const pageCount = this.searchContext.currentResultIds().length;
116             switch (pageCount) {
117                 case 1:
118                     return this.searchContext.result.records[0];
119                 default:
120                     return this.searchContext.result.records[0]
121                         && this.searchContext.result.records[1];
122             }
123         }
124
125         return false;
126     }
127
128     fleshSearchResults(): void {
129         const records = this.searchContext.result.records;
130         if (!records || records.length === 0) { return; }
131
132         // Flesh the creator / editor fields with the user object.
133         this.bib.fleshBibUsers(records.map(r => r.record));
134     }
135
136     searchIsDone(): boolean {
137         return this.searchContext.searchState === CatalogSearchState.COMPLETE;
138     }
139
140     searchIsActive(): boolean {
141         return this.searchContext.searchState === CatalogSearchState.SEARCHING;
142     }
143
144     searchHasResults(): boolean {
145         return this.searchIsDone() && this.searchContext.result.count > 0;
146     }
147
148     toggleAllRecsSelected() {
149         const ids = this.searchContext.currentResultIds();
150
151         if (this.allRecsSelected) {
152             this.basket.addRecordIds(ids);
153         } else {
154             this.basket.removeRecordIds(ids);
155         }
156     }
157 }
158
159