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