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