]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/catalog/catalog.service.ts
LP1949226 Staff catalog hold recipient more durable
[Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / catalog / catalog.service.ts
1 import {Injectable, EventEmitter} from '@angular/core';
2 import {Router, ActivatedRoute} from '@angular/router';
3 import {IdlObject} from '@eg/core/idl.service';
4 import {OrgService} from '@eg/core/org.service';
5 import {CatalogService} from '@eg/share/catalog/catalog.service';
6 import {CatalogUrlService} from '@eg/share/catalog/catalog-url.service';
7 import {CatalogSearchContext} from '@eg/share/catalog/search-context';
8 import {BibRecordSummary} from '@eg/share/catalog/bib-record.service';
9 import {PatronService} from '@eg/staff/share/patron/patron.service';
10 import {StoreService} from '@eg/core/store.service';
11
12 /**
13  * Shared bits needed by the staff version of the catalog.
14  */
15
16 @Injectable()
17 export class StaffCatalogService {
18
19     searchContext: CatalogSearchContext;
20     routeIndex = 0;
21     defaultSearchOrg: IdlObject;
22     defaultSearchLimit: number;
23     // Track the current template through route changes.
24     selectedTemplate: string;
25
26     // Display the Exclude Electronic checkbox
27     showExcludeElectronic = false;
28
29     // Advanced search filters to display
30     searchFilters: string[];
31
32     // TODO: does unapi support pref-lib for result-page copy counts?
33     prefOrg: IdlObject;
34
35     // Default search tab
36     defaultTab: string;
37
38     // Patron barcode we hope to place a hold for.
39     holdForBarcode: string;
40     // User object for above barcode.
41     holdForUser: IdlObject;
42
43     // Emit that the value has changed so components can detect
44     // the change even when the component is not itself digesting
45     // new values.
46     holdForChange: EventEmitter<void> = new EventEmitter<void>();
47
48     // Cache the currently selected detail record (i.g. catalog/record/123)
49     // summary so the record detail component can avoid duplicate fetches
50     // during record tab navigation.
51     currentDetailRecordSummary: any;
52
53     // Add digital bookplate to search options.
54     enableBookplates = false;
55
56     // Cache of browse results so the browse pager is not forced to
57     // re-run the browse search on each navigation.
58     browsePagerData: any[];
59
60     // whether to redirect to record page upon a single search
61     // result
62     jumpOnSingleHit = false;
63
64     constructor(
65         private router: Router,
66         private route: ActivatedRoute,
67         private store: StoreService,
68         private org: OrgService,
69         private cat: CatalogService,
70         private patron: PatronService,
71         private catUrl: CatalogUrlService
72     ) { }
73
74     createContext(): void {
75         // Initialize the search context from the load-time URL params.
76         // Do this here so the search form and other context data are
77         // applied on every page, not just the search results page.  The
78         // search results pages will handle running the actual search.
79         this.searchContext =
80             this.catUrl.fromUrlParams(this.route.snapshot.queryParamMap);
81
82         this.holdForBarcode = this.store.getLocalItem('eg.circ.patron_hold_target');
83
84         if (this.holdForBarcode) {
85             this.patron.getByBarcode(this.holdForBarcode)
86             .then(user => {
87                 this.holdForUser = user;
88                 this.holdForChange.emit();
89             });
90         }
91
92         this.searchContext.org = this.org; // service, not searchOrg
93         this.searchContext.isStaff = true;
94         this.applySearchDefaults();
95     }
96
97     clearHoldPatron() {
98         this.holdForUser = null;
99         this.holdForBarcode = null;
100         this.store.removeLocalItem('eg.circ.patron_hold_target');
101         this.holdForChange.emit();
102     }
103
104     cloneContext(context: CatalogSearchContext): CatalogSearchContext {
105         const params: any = this.catUrl.toUrlParams(context);
106         const ctx = this.catUrl.fromUrlHash(params);
107         ctx.isStaff = true; // not carried in the URL
108         return ctx;
109     }
110
111     applySearchDefaults(): void {
112         if (!this.searchContext.searchOrg) {
113             this.searchContext.searchOrg =
114                 this.defaultSearchOrg || this.org.root();
115         }
116
117         if (!this.searchContext.pager.limit) {
118             this.searchContext.pager.limit = this.defaultSearchLimit || 10;
119         }
120     }
121
122     /**
123      * Redirect to the search results page while propagating the current
124      * search paramters into the URL.  Let the search results component
125      * execute the actual search.
126      */
127     search(): void {
128         if (!this.searchContext.isSearchable()) { return; }
129
130         // Clear cached detail summary for new searches.
131         this.currentDetailRecordSummary = null;
132
133         const params = this.catUrl.toUrlParams(this.searchContext);
134
135         // Force a new search every time this method is called, even if
136         // it's the same as the active search.  Since router navigation
137         // exits early when the route + params is identical, add a
138         // random token to the route params to force a full navigation.
139         // This also resolves a problem where only removing secondary+
140         // versions of a query param fail to cause a route navigation.
141         // (E.g. going from two query= params to one).  Investigation
142         // pending.
143         params.ridx = '' + this.routeIndex++;
144
145         this.router.navigate(
146           ['/staff/catalog/search'], {queryParams: params});
147     }
148
149     /**
150      * Redirect to the browse results page while propagating the current
151      * browse paramters into the URL.  Let the browse results component
152      * execute the actual browse.
153      */
154     browse(): void {
155         if (!this.searchContext.browseSearch.isSearchable()) { return; }
156         const params = this.catUrl.toUrlParams(this.searchContext);
157
158         // Force a new browse every time this method is called, even if
159         // it's the same as the active browse.  Since router navigation
160         // exits early when the route + params is identical, add a
161         // random token to the route params to force a full navigation.
162         // This also resolves a problem where only removing secondary+
163         // versions of a query param fail to cause a route navigation.
164         // (E.g. going from two query= params to one).
165         params.ridx = '' + this.routeIndex++;
166
167         this.router.navigate(
168             ['/staff/catalog/browse'], {queryParams: params});
169     }
170
171     // Call number browse.
172     // Redirect to cn browse page and let its component perform the search
173     cnBrowse(): void {
174         if (!this.searchContext.cnBrowseSearch.isSearchable()) { return; }
175         const params = this.catUrl.toUrlParams(this.searchContext);
176         params.ridx = '' + this.routeIndex++; // see comments above
177         this.router.navigate(['/staff/catalog/cnbrowse'], {queryParams: params});
178     }
179
180     // Params to genreate a new author search based on a reset
181     // clone of the current page params.
182     getAuthorSearchParams(summary: BibRecordSummary): any {
183         const tmpContext = this.cloneContext(this.searchContext);
184         tmpContext.reset();
185         tmpContext.termSearch.fieldClass = ['author'];
186         tmpContext.termSearch.query = [summary.display.author];
187         return this.catUrl.toUrlParams(tmpContext);
188     }
189 }
190
191