Bug 32788: Order curbside pickup slots chronologically
[koha-ffzg.git] / koha-tmpl / intranet-tmpl / prog / en / modules / circ / curbside_pickups.tt
1 [% USE KohaDates %]
2 [% USE Koha %]
3 [% USE ItemTypes %]
4 [% USE Branches %]
5 [% USE AuthorisedValues %]
6 [% USE Asset %]
7 [% USE raw %]
8 [% USE To %]
9 [% SET footerjs = 1 %]
10 [% INCLUDE 'doc-head-open.inc' %]
11 <title>Curbside pickups &rsaquo; Circulation &rsaquo; Koha</title>
12 <style>
13     #pickup-times {
14         width: 50%;
15     }
16     .pickup_time input[type='radio'] {
17         display: none;
18     }
19     .pickup_time {
20         margin: .2em;
21     }
22     .pickup_time label {
23         background-color: #ffffcc;
24         display: inline-block;
25         cursor: pointer;
26         width: 5rem;
27         text-align: center;
28     }
29     .pickup_time input[type='radio']:checked + label {
30         background-color: #bcdb89;
31     }
32     .pickup_time input[type='radio']:disabled+ label {
33         background-color: #ff9090;
34     }
35 </style>
36 [% INCLUDE 'doc-head-close.inc' %]
37 </head>
38
39 [% SET today_iso = date.format(date.now, format = '%Y-%m-%d') %]
40
41 <body id="circ_curbside-pickups" class="circ">
42     [% INCLUDE 'header.inc' %]
43     [% INCLUDE 'cat-search.inc' %]
44
45
46 <nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
47     <ol>
48         <li>
49             <a href="/cgi-bin/koha/mainpage.pl">Home</a>
50         </li>
51         <li>
52             <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a>
53         </li>
54         <li>
55             <a href="#" aria-current="page">Curbside pickups</a>
56         </li>
57     </ol>
58 </nav>
59
60
61 [% BLOCK waiting_holds %]
62     [% SET waiting_holds = cp.patron.holds.search( found => 'W', branchcode => Branches.GetLoggedInBranchcode ) %]
63     [% FOREACH h IN waiting_holds %]
64        <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% h.biblionumber | uri %]">[% h.biblio.title | html %]</a> ([% h.biblio.author | html %], <a href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% h.itemnumber | html %]&biblionumber=[% h.biblionumber | html %]#item[% h.itemnumber | html %]">[% h.item.barcode | html %]</a>)<br/>
65     [% END %]
66 [% END %]
67
68 [% BLOCK patron_info %]
69     <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% cp.borrowernumber | uri %]">[% cp.patron.firstname | html %] [% cp.patron.surname | html %] ([% cp.patron.cardnumber | html %])</a>
70     [% IF cp.notes %]
71         <br/>
72         <span>Notes: </span>[% cp.notes | html %]
73     [% END %]
74     [% IF cp.patron.debarred %]
75         <br/>
76         <span class="patron_restricted">Patron's account is restricted</span>
77     [% END %]
78     [% IF cp.patron.has_overdues %]
79         <br />
80         <span class="patron_overdues">Patron has items overdue</span>
81     [% END %]
82 [% END %]
83
84 <div class="main container-fluid">
85     <div class="row">
86         <div class="col-sm-12">
87             <main>
88                 <div class="row">
89                 [% IF Koha.Preference('CircSidebar') %]
90                     <div class="col-sm-10 col-sm-push-2">
91                 [% ELSE %]
92                     <div class="col-sm-12">
93                 [% END %]
94
95                 <h1>Curbside pickups</h1>
96
97                 [% UNLESS policy.enabled %]
98                     <div class="dialog alert">
99                         Curbside pickups are not enabled for your library.
100                     </div>
101                     [% INCLUDE 'intranet-bottom.inc' %]
102                     [% STOP %]
103                 [% END %]
104
105                 [% FOR m IN messages %]
106                     <div class="dialog [% m.type | html %]">
107                         [% SWITCH m.code %]
108                         [% CASE 'not_enabled' %]
109                             <span>The curbside pickup feature is not enabled for this library.</span>
110                         [% CASE 'library_is_closed' %]
111                             <span>Cannot create a curbside pickup for this day, it is a holiday.</span>
112                         [% CASE 'no_waiting_holds' %]
113                             <span>This patron does not have waiting holds.</span>
114                         [% CASE 'too_many_pickups' %]
115                             <span>This patron already has a scheduled pickup for this library.</span>
116                         [% CASE 'no_matching_slots' %]
117                             <span>Wrong slot selected.</span>
118                         [% CASE 'no_more_pickups_available' %]
119                             <span>There are no more pickups available for this slot. Please choose another one.</span>
120                         [% CASE 'cannot_checkout' %]
121                             <span>Unable to check the items out to [% INCLUDE 'patron-title.inc' patron=m.patron %]</span>
122                         [% CASE %]
123                             <span>[% m.code | html %]</span>
124                         [% END %]
125                     </div>
126                 [% END %]
127
128                 <form method="post" class="refresh-form">
129                     <p>
130                         <input type="hidden" name="tab" id="current-tab" value="[% tab | html %]" />
131                         <button type="submit" class="btn btn-default"><i class="fa fa-refresh" aria-hidden="true"></i> Refresh</button>
132
133                         <label>
134                             [% IF auto_refresh %]
135                                 <input type="checkbox" id="auto_refresh" name="auto_refresh" checked="checked" />
136                             [% ELSE %]
137                                 <input type="checkbox" id="auto_refresh" name="auto_refresh" />
138                             [% END %]
139                             Refresh automatically every <input type="text" inputmode="numeric" pattern="[0-9]*" id="refresh_delay" name="refresh_delay" value="[% refresh_delay || 60 | html %]" size="3" /> seconds.
140                         </label>
141
142                         <span id="refresh_info"></span>
143                     </p>
144                 </form>
145
146                 [% SET to_be_staged = curbside_pickups.filter_by_to_be_staged %]
147                 [% SET staged_and_ready = curbside_pickups.filter_by_staged_and_ready %]
148                 [% SET patron_outside = curbside_pickups.filter_by_patron_outside %]
149                 [% SET delivered_today = curbside_pickups.filter_by_delivered %]
150                 <div id="pickup-tabs" class="toptabs">
151                     <ul class="nav nav-tabs" role="tablist">
152                         [% IF !tab OR tab == 'to-be-staged' %]
153                         <li role="presentation" class="active">
154                         [% ELSE %]
155                         <li role="presentation">
156                         [% END %]
157                             <a id="to-be-staged-tab"      href="#to-be-staged" role="tab" data-toggle="tab">To be staged ([% to_be_staged.count | html %])</a>
158                         </li>
159                         [% IF tab == 'staged-and-ready' %]
160                         <li role="presentation" class="active">
161                         [% ELSE %]
162                         <li role="presentation">
163                         [% END %]
164                             <a id="staged-and-ready-tab"  href="#staged-and-ready" role="tab" data-toggle="tab">Staged & ready ([% staged_and_ready.count | html %])</a>
165                         </li>
166                         [% IF tab == 'patron-is-outside' %]
167                         <li role="presentation" class="active">
168                         [% ELSE %]
169                         <li role="presentation">
170                         [% END %]
171                             <a id="patron-is-outside-tab" href="#patron-is-outside" role="tab" data-toggle="tab">Patron is outside ([% patron_outside.count | html %])</a>
172                         </li>
173                         [% IF tab == 'delivered-today' %]
174                         <li role="presentation" class="active">
175                         [% ELSE %]
176                         <li role="presentation">
177                         [% END %]
178                             <a id="delivered-today-tab"   href="#delivered-today" role="tab" data-toggle="tab">Delivered today ([% delivered_today.count | html %])</a>
179                         </li>
180                         [% IF tab == 'schedule-pickup' %]
181                         <li role="presentation" class="active">
182                         [% ELSE %]
183                         <li role="presentation">
184                         [% END %]
185                             <a id="schedule-pickup-tab"   href="#schedule-pickup" role="tab" data-toggle="tab">Schedule pickup</a>
186                         </li>
187                     </ul>
188
189                     <div class="tab-content">
190                         [% IF !tab OR tab == 'to-be-staged' %]
191                         <div id="to-be-staged" role="tabpanel" class="tab-pane active">
192                         [% ELSE %]
193                         <div id="to-be-staged" role="tabpanel" class="tab-pane">
194                         [% END %]
195                             [% IF to_be_staged.count %]
196                                 <table class="table table-striped">
197                                     <thead>
198                                         <tr>
199                                             <th>Pickup date/time</th>
200                                             <th>Patron</th>
201                                             <th>Items for pickup</th>
202                                             <th>Action</th>
203                                         </tr>
204                                     </thead>
205                                     <tbody>
206                                         [% FOREACH cp IN to_be_staged %]
207                                             [% UNLESS cp.staged_datetime %]
208                                                 <tr class="[% class | html %]">
209                                                     <td>[% cp.scheduled_pickup_datetime | $KohaDates with_hours = 1 %]</td>
210                                                     <td>
211                                                         [% PROCESS patron_info %]
212                                                     </td>
213                                                     <td>
214                                                         [% PROCESS waiting_holds %]
215                                                     </td>
216                                                     <td>
217                                                         <form method="post" class="form">
218                                                             <input type="hidden" name="op" value="mark-as-staged"/>
219                                                             <input type="hidden" name="tab" value="to-be-staged"/>
220                                                             <input type="hidden" name="id" value="[% cp.id | html %]"/>
221                                                             <p>
222                                                                 <button type="submit" class="btn btn-default mark-as-staged-and-ready-btn"><i class="fa fa-check" aria-hidden="true"></i> Mark as <i>staged & ready</i></button>
223                                                             </p>
224                                                         </form>
225
226                                                         <form method="post" class="form">
227                                                             <input type="hidden" name="op" value="cancel"/>
228                                                             <input type="hidden" name="tab" value="to-be-staged"/>
229                                                             <input type="hidden" name="id" value="[% cp.id | html %]"/>
230                                                             <p>
231                                                                 <button type="submit" class="btn btn-default cancel-btn"><i class="fa fa-ban" aria-hidden="true"></i> Cancel</button>
232                                                             </p>
233                                                         </form>
234                                                     </td>
235                                                 </tr>
236                                             [% END %]
237                                         [% END %]
238                                     </tbody>
239                                 </table>
240                             [% ELSE %]
241                                 <span>There are no pickups to be staged.</span>
242                             [% END %]
243                         </div>
244
245                         [% IF tab == "staged-and-ready" %]
246                         <div id="staged-and-ready" role="tabpanel" class="tab-pane active">
247                         [% ELSE %]
248                         <div id="staged-and-ready" role="tabpanel" class="tab-pane">
249                         [% END %]
250                             [% IF staged_and_ready.count %]
251                                 <table class="table table-striped">
252                                     <thead>
253                                         <tr>
254                                             <th>Pickup date/time</th>
255                                             <th>Patron</th>
256                                             <th>Items for pickup</th>
257                                             <th>Staged by</th>
258                                             <th>Action</th>
259                                         </tr>
260                                     </thead>
261                                     <tbody>
262                                         [% FOREACH cp IN staged_and_ready %]
263                                             [% IF cp.staged_datetime && !cp.arrival_datetime %]
264                                                 <tr class="[% class | html %]">
265                                                     <td>[% cp.scheduled_pickup_datetime | $KohaDates with_hours = 1 %]</td>
266                                                     <td>
267                                                         [% PROCESS patron_info %]
268                                                     </td>
269                                                     <td>
270                                                         [% PROCESS waiting_holds %]
271                                                     </td>
272                                                     <td>
273                                                         [% cp.staged_by_staff.firstname | html %] [% cp.staged_by_staff.surname | html %]
274                                                     </td>
275                                                     <td>
276                                                         <form method="post" class="form">
277                                                             <input type="hidden" name="op" value="mark-patron-has-arrived"/>
278                                                             <input type="hidden" name="tab" value="staged-and-ready"/>
279                                                             <input type="hidden" name="id" value="[% cp.id | html %]"/>
280                                                             <p>
281                                                                 <button type="submit" class="btn btn-default patron-has-arrived-btn"><i class="fa fa-map-marker" aria-hidden="true"></i> Patron has arrived</button>
282                                                             </p>
283                                                         </form>
284
285                                                         <form method="post" class="form">
286                                                             <input type="hidden" name="op" value="mark-as-delivered"/>
287                                                             <input type="hidden" name="tab" value="staged-and-ready"/>
288                                                             <input type="hidden" name="id" value="[% cp.id | html %]"/>
289                                                             <p>
290                                                                 <button type="submit" class="btn btn-default mark-as-delivered-btn"><i class="fa fa-envelope" aria-hidden="true"></i> Mark as <i>delivered</i></button>
291                                                             </p>
292                                                         </form>
293
294                                                         <form method="post" class="form">
295                                                             <input type="hidden" name="op" value="mark-as-unstaged"/>
296                                                             <input type="hidden" name="tab" value="staged-and-ready"/>
297                                                             <input type="hidden" name="id" value="[% cp.id | html %]"/>
298                                                             <p>
299                                                                 <button type="submit" class="btn btn-default mark-as-to-be-staged-btn"><i class="fa fa-undo" aria-hidden="true"></i> Mark as <i>to be staged</i></button>
300                                                             </p>
301                                                         </form>
302                                                     </td>
303                                                 </tr>
304                                             [% END %]
305                                         [% END %]
306                                     </tbody>
307                                 </table>
308                             [% ELSE %]
309                                 <span>There are no pickups staged and ready.</span>
310                             [% END %]
311                         </div>
312
313                         [% IF tab == "patron-is-outside" %]
314                         <div id="patron-is-outside" role="tabpanel" class="tab-pane active">
315                         [% ELSE %]
316                         <div id="patron-is-outside" role="tabpanel" class="tab-pane">
317                         [% END %]
318                             [% IF patron_outside.count %]
319                                 <table class="table table-striped">
320                                     <thead>
321                                         <tr>
322                                             <th>Pickup date/time</th>
323                                             <th>Patron</th>
324                                             <th>Items for pickup</th>
325                                             <th>Staged by</th>
326                                             <th>Action</th>
327                                         </tr>
328                                     </thead>
329                                     <tbody>
330                                         [% FOREACH cp IN patron_outside %]
331                                             [% IF cp.arrival_datetime && !cp.delivered_datetime %]
332                                                 <tr class="[% class | html %]">
333                                                     <td>[% cp.scheduled_pickup_datetime | $KohaDates with_hours = 1 %]</td>
334                                                     <td>
335                                                         [% PROCESS patron_info %]
336                                                     </td>
337                                                     <td>
338                                                         [% PROCESS waiting_holds %]
339                                                     </td>
340                                                     <td>
341                                                         [% cp.staged_by_staff.firstname | html %] [% cp.staged_by_staff.surname | html %]
342                                                     </td>
343                                                     <td>
344                                                         <form method="post" class="form">
345                                                             <input type="hidden" name="op" value="mark-as-delivered"/>
346                                                             <input type="hidden" name="tab" value="patron-is-outside"/>
347                                                             <input type="hidden" name="id" value="[% cp.id | html %]"/>
348                                                             <p>
349                                                                 <button type="submit" class="btn btn-default mark-as-delivered-btn"><i class="fa fa-envelope" aria-hidden="true"></i> Mark as delivered</button>
350                                                             </p>
351                                                         </form>
352
353                                                         <form method="post" class="form">
354                                                             <input type="hidden" name="op" value="mark-as-staged"/>
355                                                             <input type="hidden" name="tab" value="patron-is-outside"/>
356                                                             <input type="hidden" name="id" value="[% cp.id | html %]"/>
357                                                             <p>
358                                                                 <button type="submit" class="btn btn-default mark-as-staged-and-ready-btn"><i class="fa fa-undo" aria-hidden="true"></i> Mark as <i>staged & ready</i></button>
359                                                             </p>
360                                                         </form>
361
362                                                         <form method="post" class="form">
363                                                             <input type="hidden" name="op" value="mark-as-unstaged"/>
364                                                             <input type="hidden" name="tab" value="patron-is-outside"/>
365                                                             <input type="hidden" name="id" value="[% cp.id | html %]"/>
366                                                             <p>
367                                                                 <button type="submit" class="btn btn-default mark-as-to-be-staged-btn"><i class="fa fa-undo" aria-hidden="true"></i> Mark as <i>to be staged</i></button>
368                                                             </p>
369                                                         </form>
370                                                     </td>
371                                                 </tr>
372                                             [% END %]
373                                         [% END %]
374                                     </tbody>
375                                 </table>
376                             [% ELSE %]
377                                 <span>There are no patrons waiting outside.</span>
378                             [% END %]
379                         </div>
380
381                         [% IF tab == "delivered-today" %]
382                         <div id="delivered-today" role="tabpanel" class="tab-pane active">
383                         [% ELSE %]
384                         <div id="delivered-today" role="tabpanel" class="tab-pane">
385                         [% END %]
386                             [% IF delivered_today.count %]
387                                 <table class="table table-striped">
388                                     <thead>
389                                         <tr>
390                                             <th>Deliver date/time</th>
391                                             <th>Patron</th>
392                                             <th>Items checked out</th>
393                                         </tr>
394                                     </thead>
395                                     <tbody>
396                                         [% FOREACH cp IN delivered_today %]
397                                             [% IF cp.delivered_datetime %]
398                                                 <tr class="[% class | html %]">
399                                                     <td>[% cp.delivered_datetime | $KohaDates with_hours = 1 %]</td>
400                                                     <td>
401                                                         [% PROCESS patron_info %]
402                                                     </td>
403                                                     <td>
404                                                     [% FOREACH c IN cp.checkouts %]
405                                                         [% IF date.format(c.issuedate, format = '%Y-%m-%d') == today_iso %]
406                                                             <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% c.item.biblionumber | uri %]">[% c.item.biblio.title | html %]</a> ([% c.item.biblio.author | html %], <a href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% c.itemnumber | html %]&biblionumber=[% c.item.biblionumber | html %]#item[% c.itemnumber | html %]">[% c.item.barcode | html %]</a>)<br/>
407                                                         [% END %]
408                                                     [% END %]
409                                                 </td>
410                                             </tr>
411                                         [% END %]
412                                     [% END %]
413                                 </tbody>
414                             </table>
415                         [% ELSE %]
416                             <span>No pickups have been delivered today.</span>
417                         [% END %]
418                     </div>
419
420                     [% IF tab == "schedule-pickup" %]
421                     <div id="schedule-pickup" role="tabpanel" class="tab-pane active">
422                     [% ELSE %]
423                     <div id="schedule-pickup" role="tabpanel" class="tab-pane">
424                     [% END %]
425                         [% IF !patron || ( patron && existing_curbside_pickups.count >= 1 ) %]
426                             [% IF existing_curbside_pickups.count >= 1 %]
427                                 <div class="dialog alert">
428                                     [% patron.firstname | html %] [% patron.surname | html %] ([% patron.cardnumber | html %]) already has a scheduled pickup for this library.
429                                 </div>
430                             [% END %]
431                             <div class="form-group">
432                                 <label class="sr-only" for="input-patron-cardnumber">Cardnumber</label>
433                                 <div class="input-group">
434                                     <div class="input-group-addon">Search a patron</div>
435                                     <input autocomplete="off" id="find-patron" class="form-control" type="text" style="width:25%" class="noEnterSubmit" placeholder="Enter patron cardnumber or name"//>
436                                 </div>
437                             </div>
438                         [% ELSE %]
439                             [% SET waiting_holds = patron.holds.search( found => 'W', branchcode => Branches.GetLoggedInBranchcode ) %]
440                             [% IF !policy.enable_waiting_holds_only || waiting_holds.count > 0 %]
441                                 <form id="create-pickup" method="post">
442                                     <fieldset class="rows" style="float: none;">
443                                         <input type="hidden" name="borrowernumber" value="[% patron.id | html %]"/>
444                                         <input type="hidden" name="op" value="create-pickup"/>
445                                         <input type="hidden" name="tab" value="schedule-pickup"/>
446                                         <ol>
447                                             <li>
448                                                 <label>Patron: </label>
449                                                 <span>[% INCLUDE 'patron-title.inc' patron=patron %]</span>
450                                                 <a title="Search for another patron" href="/cgi-bin/koha/circ/curbside_pickups.pl?tab=schedule-pickup"><i class="fa fa-search"></i></a>
451                                             </li>
452
453                                             <li>
454                                                 <label>Items ready for pickup: </label>
455                                                 <span>
456                                                     [% IF waiting_holds.count %]
457                                                         [% FOREACH h IN waiting_holds %]
458                                                             <p>
459                                                                 <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% h.biblionumber | uri %]">[% h.biblio.title | html %]</a> ([% h.biblio.author | html %], <a href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% h.itemnumber | html %]&biblionumber=[% h.biblionumber | html %]#item[% h.itemnumber | html %]">[% h.item.barcode | html %]</a>)
460                                                             </p>
461                                                         [% END %]
462                                                     [% ELSE %]
463                                                         <span>There are no waiting holds for this patron at this library.</span>
464                                                     [% END %]
465                                                 </span>
466                                             </li>
467
468                                             <li>
469                                                 <label for="pickup_date">Pickup date: </label>
470                                                 <input id="pickup_date" name="pickup_date" required="required" class="flatpickr" data-flatpickr-futureinclusive="true" />
471                                             </li>
472
473                                             <li id="pickup-times" class="radio"></li>
474
475                                             <li>
476                                                 <label for="notes">Notes: </label>
477                                                 <input id="notes" name="notes" type="text" />
478                                             </li>
479                                         </ol>
480                                     </fieldset>
481
482                                     <fieldset class="action">
483                                         <input type="submit" id="schedule-pickup-button" class="btn btn-primary" value="Submit" />
484                                     </fieldset>
485                                 </form>
486                             [% ELSE %]
487                                 <div class="dialog alert">The patron does not have waitings holds.</div>
488                             [% END %]
489                         [% END %]
490                     </div>
491                 </div>
492                 </div>
493                 [% IF Koha.Preference('CircSidebar') %]
494                     </div> <!-- /.col-sm-10.col-sm-push-2 -->
495                         <div class="col-sm-2 col-sm-pull-10">
496                             <aside>
497                                 [% INCLUDE 'circ-nav.inc' %]
498                             </aside>
499                         </div> <!-- /.col-sm-2.col-sm-pull-10 -->
500                     </div> <!-- /.row -->
501                 [% END %]
502             </main>
503         </div>
504     </div> <!-- /.row -->
505
506 [% MACRO jsinclude BLOCK %]
507     [% Asset.js("lib/dayjs/dayjs.min.js") | $raw %]
508     [% Asset.js("lib/dayjs/plugin/isSameOrAfter.js") | $raw %]
509     [% Asset.js("lib/dayjs/plugin/customParseFormat.js") | $raw %]
510     <script>dayjs.extend(window.dayjs_plugin_isSameOrAfter)</script>
511     <script>dayjs.extend(window.dayjs_plugin_customParseFormat)</script>
512     [% INCLUDE 'calendar.inc' %]
513     [% INCLUDE 'js-patron-format.inc' %]
514     <script>
515         let pickups = [% To.json(curbside_pickups.unblessed) | $raw %];
516         let policy = [% To.json(policy.unblessed) | $raw %];
517
518         let existingPickupMoments = [];
519         pickups.forEach(function(pickup){
520             let scheduled_pickup_datetime = pickup.scheduled_pickup_datetime;
521             let pickupMoment = dayjs(scheduled_pickup_datetime);
522
523             existingPickupMoments.push(pickupMoment);
524         });
525
526         let opening_slots = [% To.json(policy.opening_slots.unblessed) | $raw %];
527         let slots_per_day = {};
528         opening_slots.forEach(function(slot){
529             let day = slot.day;
530             if(!slots_per_day[day]) slots_per_day[day] = [];
531             slots_per_day[day].push(slot);
532         });
533
534         $(document).ready(function() {
535
536             $('#schedule-pickup-tab').on('click', function() {
537                 $('#input-patron-cardnumber').focus();
538             });
539
540             const pickup_date = document.querySelector("#pickup_date");
541             if ( pickup_date ) {
542                 const fp = pickup_date._flatpickr;
543                 fp.set('disable', [function(date) {
544                     return !slots_per_day.hasOwnProperty(date.getDay());
545                 }]);
546             }
547
548             $("#pickup_date").on('change', function() {
549
550                 $('#pickup-times').empty();
551                 $('#schedule-pickup-button').prop( 'disabled', 1 );
552
553                 var currentDate = $(this).val();
554
555                 let selectedDate = dayjs(currentDate);
556
557                 let pickupSlots = [];
558                 let available_count = 0;
559                 let dow = selectedDate.day(); // Sunday is 0 (at least for now)
560                 if (!slots_per_day[dow]){
561                     $('#pickup-times').html("<div>"+_("No pickup time defined for this day.")+"</div>");
562                     return;
563                 }
564
565                 slots_per_day[dow].sort((a, b) => a.start_hour - b.start_hour).forEach(function(slot){
566                     let pickup_interval = policy.pickup_interval;
567                     if (!pickup_interval) {
568                         $('#pickup-times').html("<div>"+_("No pickup time defined for this day.")+"</div>");
569                         return;
570                     }
571
572                     let listStartMoment = selectedDate.hour(slot.start_hour).minute(slot.start_minute);
573                     let listEndMoment = selectedDate.hour(slot.end_hour).minute(slot.end_minute);
574
575                     let keep_going = true;
576                     let now = dayjs();
577
578                     // Initialize pickup slots starting at opening time
579                     let pickupIntervalStartMoment = listStartMoment;
580                     let pickupIntervalEndMoment   = listStartMoment.add(pickup_interval, 'minutes');
581                     while (keep_going) {
582                         let available = true;
583                         let display_slot = true
584
585                         if (pickupIntervalStartMoment.isBefore(now)) {
586                             // Slots in the past are unavailable
587                             available = false;
588                             display_slot = false;
589                         }
590
591                         if (pickupIntervalEndMoment.isAfter(listEndMoment)) {
592                             // Slots after the end of pickup times for the day are unavailable
593                             available = false;
594                         }
595
596                         let pickups_scheduled = 0;
597                         existingPickupMoments.forEach(function(pickupMoment){
598                             // An existing pickup time
599                             if (pickupMoment.isSameOrAfter(pickupIntervalStartMoment) && pickupMoment.isBefore(pickupIntervalEndMoment)) {
600                                 // This calculated pickup is in use by another scheduled pickup
601                                 pickups_scheduled++;
602                             }
603                         });
604
605                         if (pickups_scheduled >= policy.patrons_per_interval) {
606                             available = false;
607                         }
608
609                         if ( display_slot ) {
610                             pickupSlots.push(
611                                 {
612                                     "available": available,
613                                     "moment": pickupIntervalStartMoment,
614                                     "pickups_scheduled": pickups_scheduled
615                                 }
616                             );
617                         }
618
619                         if ( available ) {
620                             available_count++;
621                         }
622
623                         pickupIntervalStartMoment = pickupIntervalEndMoment;
624                         pickupIntervalEndMoment = pickupIntervalStartMoment.add(pickup_interval, 'minutes');
625                         if (pickupIntervalEndMoment.isAfter(listEndMoment)) {
626                             // This latest slot is after the end of pickup times for the day, so we can stop
627                             keep_going = false;
628                         }
629                     }
630                 });
631
632                 for (let i = 0; i < pickupSlots.length; i++) {
633                     let pickupSlot = pickupSlots[i];
634                     let optText = pickupSlot.moment.format("HH:mm");
635                     let optValue = pickupSlot.moment.format("YYYY-MM-DD HH:mm:ss");
636                     let pickups_scheduled = pickupSlot.pickups_scheduled;
637                     let disabled = pickupSlot.available ? "" : "disabled";
638                     $("#pickup-times").append(`<span class="pickup_time"><input type="radio" id="slot_${i}" name="pickup_time" value="${optValue}" ${disabled} /> <label for="slot_${i}">${optText} (${pickups_scheduled})</label></span>`);
639                 }
640
641                 $('#pickup-times').show();
642                 $('#schedule-pickup-button').prop( 'disabled', available_count <= 0 );
643             });
644
645             $("#create-pickup").on('submit', function(){
646                 if ( ! $("input[type='radio']:checked").length ) {
647                     alert(_("Please select a date and a pickup time"))
648                     return false;
649                 }
650                 return true;
651             });
652
653             if ( $("#find-patron").length ) {
654                 patron_autocomplete($("#find-patron"), { 'on-select-callback': function( event, ui ) {
655                         window.location.href = "/cgi-bin/koha/circ/curbside_pickups.pl?op=find-patron&borrowernumber=" + ui.item.patron_id;
656                         return false;
657                     }
658                 });
659             }
660
661             $("#pickup-tabs a[data-toggle='tab']").on("shown.bs.tab", function (e) {
662                 $("#current-tab").val($(this).attr('href').substring(1)); // Remove #
663             });
664             $("#auto_refresh,#refresh_delay").on("change", function(){
665                 set_interval_if_needed();
666             });
667
668             set_interval_if_needed();
669
670         });
671
672         let refresh_interval_id = 0;
673         let countdown_interval_id = 0;
674         function set_interval(refresh_delay_ms){
675             clear_intervals();
676             let next_refresh = new Date();
677             next_refresh.setSeconds(next_refresh.getSeconds() + refresh_delay_ms / 1000);
678
679             countdown_interval_id = setInterval(function() {
680                 const now = new Date().getTime();
681                 const seconds = Math.floor(( next_refresh - now + 1 ) / 1000);
682                 if ( seconds > 0 ) {
683                     $("#refresh_info").text(_("Refresh in %s seconds").format(seconds));
684                 } else {
685                     $("#refresh_info").text(""); // In case something is going wrong
686                 }
687             }, 1000);
688
689             setInterval(function() {
690                 $(".refresh-form:visible").submit();
691             }, refresh_delay_ms);
692         }
693         function clear_intervals(){
694             if (refresh_interval_id) {
695                 clearInterval(refresh_interval_id);
696                 refresh_interval_id = 0;
697             }
698             if (countdown_interval_id) {
699                 clearInterval(countdown_interval_id);
700                 countdown_interval_id = 0;
701             }
702         }
703
704         function set_interval_if_needed(){
705             const refresh_delay = $("#refresh_delay").val();
706             const auto_refresh = $("#auto_refresh").is(":checked");
707
708             if (auto_refresh && refresh_delay){
709                 set_interval(refresh_delay * 1000);
710             } else {
711                 clear_intervals();
712             }
713         }
714     </script>
715 [% END %]
716
717
718 [% INCLUDE 'intranet-bottom.inc' %]