]> git.evergreen-ils.org Git - evergreen/pines.git/blob - Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.html
LP1999304 (follow-up): blank alt text for decorative image
[evergreen/pines.git] / Open-ILS / src / eg2 / src / app / staff / catalog / hold / hold.component.html
1
2 <eg-patron-search-dialog #patronSearch></eg-patron-search-dialog>
3 <eg-barcode-select #barcodeSelect></eg-barcode-select>
4 <eg-worklog-strings-components></eg-worklog-strings-components>
5
6 <eg-alert-dialog #activeDateAlert
7   i18n-dialogTitle i18n-dialogBody
8   dialogTitle="Invalid Hold Activation Date"
9   dialogBody="Hold activation date {{activeDateYmd}} is not valid.
10     Please chose a date in the future">
11 </eg-alert-dialog>
12
13 <div class="row">
14   <div class="col-lg-1">
15     <button class="btn btn-info label-with-material-icon"
16       (click)="goBack()" [disabled]="hasNoHistory()">
17       <span class="material-icons">keyboard_backspace</span>
18       <span i18n>Return</span>
19     </button>
20   </div>
21   <div class="col-lg-5">
22     <ng-container *ngIf="badBarcode">
23       <div class="alert alert-danger" i18n>
24         Barcode '{{badBarcode}}' not found.
25       </div>
26     </ng-container>
27     <ng-container *ngIf="!badBarcode">
28       <h3 i18n>Place Hold
29         <small *ngIf="user">
30         ({{user.pref_family_name() ? user.pref_family_name() : user.family_name()}},
31         {{user.pref_first_given_name() ? user.pref_first_given_name() :user.first_given_name()}})
32         </small>
33       </h3>
34     </ng-container>
35   </div>
36   <div class="col-lg-2">
37     <button class="btn btn-outline-dark btn-sm" (click)="searchPatrons()">
38       <span class="material-icons mat-icon-in-button align-middle"
39         i18n-title title="Search for Patron">search</span>
40       <span class="align-middle" i18n>Search for Patron</span>
41     </button>
42   </div>
43 </div>
44
45 <form class="form form-validated common-form"
46   autocomplete="off" (keydown.enter)="$event.preventDefault()">
47   <div class="row">
48     <div class="col-lg-6 common-form striped-odd">
49       <div class="row mt-2">
50         <div class="col-lg-6">
51           <div class="form-check">
52             <input class="form-check-input" type="radio"
53               (change)="holdForChanged()"
54               id="hold-for-patron"
55               name="holdFor" value="patron" [(ngModel)]="holdFor"/>
56             <label class="form-check-label" for="hold-for-patron" i18n>
57               Place hold for patron by barcode:
58             </label>
59           </div>
60         </div>
61         <div class="col-lg-6">
62           <div class="input-group">
63             <input type='text' class="form-control" name="userBarcode"
64               [disabled]="holdFor!=='patron'" id='patron-barcode'
65               aria-label="Patron barcode" i18n-aria-label
66               (ngModelChange)="debounceUserBarcodeLookup($event)"
67               (paste)="debounceUserBarcodeLookup($event)"
68               [(ngModel)]="userBarcode"/>
69             <div class="input-group-append">
70               <button class="btn btn-outline-dark" (click)="userBarcodeChanged()">Submit</button>
71             </div>
72           </div>
73         </div>
74       </div>
75       <div class="row mt-2">
76         <div class="col-lg-6">
77           <div class="form-check">
78             <input class="form-check-input" type="radio"
79               (change)="holdForChanged()"
80               id="hold-for-staff"
81               name="holdFor" value="staff" [(ngModel)]="holdFor"/>
82             <label class="form-check-label" i18n for="hold-for-staff">
83               Place hold for this staff account:
84             </label>
85           </div>
86         </div>
87         <div class="col-lg-6 font-weight-bold">{{requestor.usrname()}}</div>
88       </div>
89       <div class="row mt-2">
90         <div class="col-lg-6">
91           <label i18n>Pickup Location: </label>
92         </div>
93         <div class="col-lg-6">
94           <eg-org-select (onChange)="pickupLib = $event ? $event.id() : null"
95             [disableOrgs]="disableOrgs" [applyOrgId]="pickupLib"></eg-org-select>
96         </div>
97       </div>
98       <div class="row mt-2">
99         <div class="col-lg-6">
100           <div class="form-check">
101             <input class="form-check-input" type="checkbox" id="suspend"
102               name="suspend" [(ngModel)]="suspend"/>
103             <label class="form-check-label" for="suspend" i18n>Suspend Hold</label>
104           </div>
105         </div>
106         <div class="col-lg-6">
107           <div [ngClass]="{'border border-danger rounded': activeDateInvalid}">
108             <eg-date-select [(ngModel)]="activeDate" name='active-date'
109               (onChangeAsYmd)="activeDateYmd = $event"
110               (onChangeAsDate)="setActiveDate($event)"
111               (onChangeAsIso)="activeDateSelected($event)" [disabled]="!suspend">
112             </eg-date-select>
113           </div>
114         </div>
115       </div>
116       <div class="row mt-2" *ngIf="multiHoldsActive">
117         <div class="col-lg-6">
118           <label for='multi-hold-count' i18n>Number of copies:</label>
119         </div>
120         <div class="col-lg-6">
121           <select class="form-control" name="multi-hold-count"
122             id="multi-hold-count" [(ngModel)]="multiHoldCount">
123             <option [value]="num"
124               *ngFor="let num of holdCountRange()">{{num}}</option>
125           </select>
126         </div>
127       </div>
128
129     </div><!-- left column -->
130     <div class="col-lg-6">
131       <div class="card">
132         <div class="card-header">
133           <h4 i18n>Notifications</h4>
134         </div>
135         <ul class="list-group list-group-flush">
136           <li class="list-group-item d-flex">
137             <div class="flex-1">
138               <div class="form-check">
139                 <input class="form-check-input" type="checkbox" name="notifyEmail"
140                   id="notifyEmail"
141                   [disabled]="!user || !user.email()" [(ngModel)]="notifyEmail"/>
142                 <label class="form-check-label" for="notifyEmail" i18n>Notify by Email</label>
143               </div>
144             </div>
145             <div class="flex-1">
146               <div class="input-group">
147                 <div class="input-group-prepend">
148                   <label for="userEmail" class="input-group-text" i18n>Email Address</label>
149                 </div>
150                 <input type="text" class="form-control" name="userEmail"
151                   id="userEmail"
152                   [disabled]="true" value="{{user ? user.email() : ''}}"/>
153               </div>
154             </div>
155           </li>
156           <li class="list-group-item d-flex">
157             <div class="flex-1">
158               <div class="form-check">
159                 <input class="form-check-input" type="checkbox"
160                   id="notifyPhone"
161                   name="notifyPhone" [(ngModel)]="notifyPhone"/>
162                 <label class="form-check-label" for="notifyPhone" i18n>Notify by Phone</label>
163               </div>
164             </div>
165             <div class="flex-1">
166               <div class="input-group">
167                 <div class="input-group-prepend">
168                   <label for="phoneValue" class="input-group-text" i18n>Phone Number</label>
169                 </div>
170                 <input type="text" class="form-control" [disabled]="!notifyPhone"
171                   name="phoneValue" id="phoneValue" [(ngModel)]="phoneValue"/>
172               </div>
173             </div>
174           </li>
175           <li *ngIf="smsEnabled" class="list-group-item d-flex">
176             <div class="flex-1">
177               <div class="form-check">
178                 <input class="form-check-input" type="checkbox" id="notifySms"
179                   name="notifySms" [(ngModel)]="notifySms"/>
180                 <label class="form-check-label" for="notifySms" i18n>Notify by SMS</label>
181               </div>
182             </div>
183             <div class="flex-1">
184               <div class="input-group">
185                 <div class="input-group-prepend">
186                   <label for="smsValue" class="input-group-text" i18n>SMS Number</label>
187                 </div>
188                 <input type="text" class="form-control" [disabled]="!notifySms"
189                   id="smsValue" name="smsValue" [(ngModel)]="smsValue"
190                   [required]="notifySms"/>
191               </div>
192             </div>
193           </li>
194           <li *ngIf="smsEnabled" class="list-group-item d-flex">
195             <div class="flex-1">
196               <label for="smsCarriers" i18n>SMS Carrier</label>
197             </div>
198             <div class="flex-1">
199               <eg-combobox [disabled]="!notifySms" #smsCbox
200                 domId="smsCarriers" [required]="notifySms"
201                 placeholder="SMS Carriers" i18n-placeholder
202                 [entries]="smsCarriers">
203               </eg-combobox>
204             </div>
205           </li>
206           <li class="list-group-item">
207             <button class="btn btn-success" (click)="placeHolds()"
208               [disabled]="!readyToPlaceHolds()" i18n>Place Hold(s)</button>
209             <button class="btn btn-outline-dark ml-2" (click)="resetForm()" i18n>Reset</button>
210           </li>
211         </ul><!-- col -->
212       </div><!-- row -->
213     </div><!--card -->
214   </div><!-- col -->
215 </form>
216
217 <div class="row"><div class="col-lg-12"><hr/></div></div>
218
219 <div class="row pt-3 ml-1 mr-1 d-flex">
220   <div class="">
221     <span class="font-weight-bold" i18n>Placing
222       <ng-container *ngIf="holdType === 'M'">METARECORD</ng-container>
223       <ng-container *ngIf="holdType === 'T'">TITLE</ng-container>
224       <ng-container *ngIf="holdType === 'V'">CALL NUMBER</ng-container>
225       <ng-container *ngIf="holdType === 'F'">FORCE ITEM</ng-container>
226       <ng-container *ngIf="holdType === 'C'">ITEM</ng-container>
227       <ng-container *ngIf="holdType === 'R'">RECALL</ng-container>
228       <ng-container *ngIf="holdType === 'I'">ISSUANCE</ng-container>
229       <ng-container *ngIf="holdType === 'P'">PARTS</ng-container>
230       hold on record(s)
231     </span>
232   </div>
233   <div class="flex-1"> </div>
234   <div>
235     <span class="pl-3" *ngIf="isItemHold()">
236       <span i18n>Item-Level Hold Options:</span>
237       <span class="pl-2">
238         <a routerLink="/staff/catalog/hold/C" queryParamsHandling="merge">
239           <button [disabled]="holdType === 'C'" class="btn btn-outline-primary"
240             i18n>Item Hold</button>
241         </a>
242       </span>
243       <span class="pl-2">
244         <a routerLink="/staff/catalog/hold/R" queryParamsHandling="merge">
245           <button [disabled]="holdType === 'R'" class="btn btn-outline-primary"
246             i18n>Recall Hold</button>
247         </a>
248       </span>
249       <span class="pl-2">
250         <a routerLink="/staff/catalog/hold/F" queryParamsHandling="merge">
251           <button [disabled]="holdType === 'F'" class="btn btn-outline-primary"
252             i18n>Force Item Hold</button>
253         </a>
254       </span>
255     </span>
256   </div>
257 </div>
258
259 <ng-template #anyValue>
260   <span class="font-italic" i18n>ANY</span>
261 </ng-template>
262
263 <!--
264     TODO: add a section per hold context for metarecord holds
265     listing the possible formats and languages.
266
267     TODO: add a secion per hold context for T holds providing a
268     link to the metarecord hold equivalent (AKA "Advanced Hold
269     Options") for each record that has selectable filters (and
270     only when metarecord holds are enabled).
271 -->
272
273 <div class="hold-records-list common-form striped-even">
274
275   <div class="row mt-2 ml-1 mr-1 font-weight-bold">
276     <div class="col-lg-1" i18n>Format</div>
277     <div class="col-lg-2" i18n>Title</div>
278     <div class="col-lg-1" i18n>Author</div>
279     <div class="col-lg-2" i18n>Part</div>
280     <div class="col-lg-2" i18n>Call Number</div>
281     <div class="col-lg-1" i18n>Barcode</div>
282     <div class="col-lg-2" i18n>Holds Status</div>
283     <div class="col-lg-1" i18n>Override</div>
284   </div>
285   <div class="row mt-1 ml-1 mr-1" *ngIf="showOverrideAll()">
286     <div class="col-lg-12">
287       <div class="row">
288         <div class="col-lg-1 ml-auto">
289           <button class="btn btn-info" i18n
290             (click)="overrideAll()">
291             Override All
292           </button>
293         </div>
294       </div>
295     </div>
296   </div>
297   <div class="row mt-1 ml-1 mr-1" *ngFor="let ctx of holdContexts">
298     <div class="col-lg-12" *ngIf="ctx.holdMeta">
299       <div class="row">
300         <div class="col-lg-1">
301           <ng-container
302             *ngFor="let code of ctx.holdMeta.bibSummary.attributes.icon_format">
303             <img class="pr-1"
304               alt=""
305               src="/images/format_icons/icon_format/{{code}}.png"/>
306           </ng-container>
307         </div>
308         <!-- TODO: link for a metarecord should
309             jump to constituent bib list search page? -->
310         <div class="col-lg-2">
311           <a routerLink="/staff/catalog/record/{{ctx.holdMeta.bibId}}">
312             {{ctx.holdMeta.bibSummary.display.title}}
313           </a>
314         </div>
315         <div class="col-lg-1">{{ctx.holdMeta.bibSummary.display.author}}</div>
316         <div class="col-lg-2">
317           <ng-container *ngIf="ctx.holdMeta.parts.length">
318             <select class="form-control"  (change)="setPart(ctx, $event)"
319               [ngModel]="ctx.holdMeta.part ? ctx.holdMeta.part.id() : ''">
320               <option value="" i18n>Any Part</option>
321               <option *ngFor="let part of ctx.holdMeta.parts"
322                 value="{{part.id()}}">{{part.label()}}</option>
323             </select>
324           </ng-container>
325           <ng-container *ngIf="ctx.holdMeta.parts.length === 0">
326             <ng-container *ngIf="ctx.holdMeta.part">
327               <span>{{ctx.holdMeta.part.label()}}</span>
328             </ng-container>
329             <ng-container *ngIf="!ctx.holdMeta.part">
330               <span i18n>N/A</span>
331             </ng-container>
332           </ng-container>
333         </div>
334         <div class="col-lg-2">
335           <ng-container *ngIf="ctx.holdMeta.callNum; else anyValue">
336             {{ctx.holdMeta.callNum.label()}}
337           </ng-container>
338         </div>
339         <div class="col-lg-1">
340           <ng-container *ngIf="ctx.holdMeta.copy; else anyValue">
341             {{ctx.holdMeta.copy.barcode()}}
342           </ng-container>
343         </div>
344         <div class="col-lg-2">
345           <ng-container *ngIf="!ctx.lastRequest && !ctx.processing">
346             <div class="alert alert-info p-1 ml-2" i18n>Hold Pending</div>
347           </ng-container>
348           <ng-container *ngIf="ctx.processing">
349             <div class="alert alert-primary p-1 ml-2" i18n>Hold Processing...</div>
350           </ng-container>
351           <ng-container *ngIf="ctx.lastRequest">
352             <ng-container *ngIf="ctx.lastRequest.result.success">
353               <div class="alert alert-success p-1 ml-2" i18n>Hold Succeeded</div>
354             </ng-container>
355             <ng-container *ngIf="!ctx.lastRequest.result.success">
356               <div class="alert alert-danger p-1 ml-2"
357                 title="{{ctx.lastRequest.result.evt.textcode}}">
358                 {{ctx.lastRequest.result.evt.textcode}}
359               </div>
360             </ng-container>
361           </ng-container>
362         </div>
363         <div class="col-lg-1">
364           <ng-container *ngIf="canOverride(ctx)">
365             <button class="btn btn-info" (click)="override(ctx)">Override</button>
366           </ng-container>
367         </div>
368       </div>
369       <!-- note: using inline style since class-level styling for rows
370           is superseded by the striped-even styling of the container -->
371       <div class="row" *ngIf="hasMetaFilters(ctx)"
372         style="background-color:inherit; border:none">
373         <div class="col-lg-1"><label i18n>Formats: </label></div>
374         <div class="col-lg-11 d-flex">
375           <ng-container
376             *ngFor="let ccvm of ctx.holdMeta.metarecord_filters.formats">
377             <div class="form-check ml-3">
378               <label class="form-check-label ml-1" for="hold-include-format-{{ccvm.code()}}">
379               <input class="form-check-input" type="checkbox" id="hold-include-format-{{ccvm.code()}}"
380                 [disabled]="ctx.holdMeta.metarecord_filters.formats.length === 1"
381                 [(ngModel)]="ctx.selectedFormats.formats[ccvm.code()]"/>
382               <img class="ml-1"
383                 alt=""
384                 src="/images/format_icons/icon_format/{{ccvm.code()}}.png"/>
385
386                 {{ccvm.search_label() || ccvm.value()}}
387               </label>
388             </div>
389           </ng-container>
390         </div>
391       </div>
392       <div class="row" *ngIf="hasMetaFilters(ctx)"
393         style="background-color:inherit; border:none">
394         <div class="col-lg-1"><label i18n>Languages: </label></div>
395         <div class="col-lg-11 d-flex">
396           <ng-container
397             *ngFor="let ccvm of ctx.holdMeta.metarecord_filters.langs">
398             <div class="form-check ml-3">
399               <label class="form-check-label ml-1" for="hold-include-lang-{{ccvm.value()}}">
400               <input class="form-check-input" type="checkbox" id="hold-include-lang-{{ccvm.value()}}"
401                 [disabled]="ctx.holdMeta.metarecord_filters.langs.length === 1"
402                 [(ngModel)]="ctx.selectedFormats.langs[ccvm.code()]"/>
403
404                 {{ccvm.search_label() || ccvm.value()}}
405               </label>
406             </div>
407           </ng-container>
408         </div>
409       </div>
410     </div>
411   </div>
412 </div>
413
414