Bug 30055: (QA follow-up) Minor QA fixes
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / modules / members / search.tt
1 [% USE raw %]
2 [% USE To %]
3 [% USE Asset %]
4 [% USE Koha %]
5 [% USE Branches %]
6 [% USE Categories %]
7 [% SET footerjs = 1 %]
8 [% INCLUDE 'doc-head-open.inc' %]
9 [% SET libraries = Branches.all %]
10 [% SET categories = Categories.all.unblessed %]
11 <title>Patron search &rsaquo; Koha</title>
12 [% INCLUDE 'doc-head-close.inc' %]
13 <style> .modal-body .close { display: none; } </style>
14 </head>
15
16 <body id="common_patron_search" class="common">
17 <div id="patron_search" class="yui-t7">
18     <div class="container-fluid">
19
20         <form id="searchform">
21             <fieldset class="brief">
22                 <h3>Search for patron</h3>
23                 <ol>
24                     <li>
25                         <label for="searchmember_filter">Search:</label>
26                         <input type="text" id="searchmember_filter" value="[% searchmember | html %]" class="focus" />
27                     </li>
28
29                     [% FOR column IN columns %]
30                         [% SWITCH column %]
31                         [% CASE 'branch' %]
32                             <li>
33                                 <label for="branchcode_filter">Library:</label>
34                                 <select id="branchcode_filter">
35                                     [% SET libraries = Branches.all( only_from_group => 1 ) %]
36                                     [% IF libraries.size != 1 %]
37                                         <option value="">Any</option>
38                                     [% END %]
39                                     [% FOREACH l IN libraries %]
40                                         <option value="[% l.branchcode | html %]">[% l.branchname | html %]</option>
41                                     [% END %]
42                                 </select>
43                             </li>
44                         [% CASE 'category' %]
45                             <li>
46                                 <label for="categorycode_filter">Category:</label>
47                                 <select id="categorycode_filter">
48                                     <option value="">Any</option>
49                                     [% FOREACH category IN categories %]
50                                         <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
51                                     [% END %]
52                                 </select>
53                             </li>
54                         [% END %]
55                     [% END %]
56                 </ol>
57                 <fieldset class="action">
58                     <input type="submit" value="Search" />
59                 </fieldset>
60             </fieldset>
61         </form>
62
63         [% IF filter == 'suggestions_managers' %]
64             <div class="hint">Only staff with superlibrarian or suggestions_manage permissions are returned in the search results</div>
65         [% ELSIF filter == 'orders_managers' %]
66             <div class="hint">Only staff with superlibrarian or acquisitions permissions (or order_manage permission if granular permissions are enabled) are returned in the search results</div>
67         [% ELSIF filter == 'funds_owners' OR filter == 'funds_users' %]
68             <div class="hint">Only staff with superlibrarian or acquisitions permissions (or budget_modify permission if granular permissions are enabled) are returned in the search results</div>
69         [% END %]
70
71         <div class="browse">
72             Browse by last name:
73             [% FOREACH letter IN alphabet.split(' ') %]
74                 <a href="#" class="filterByLetter">[% letter | html %]</a>
75             [% END %]
76         </div>
77
78         <div id="info" class="dialog message" style="display: none;"></div>
79         <div id="error" class="dialog alert" style="display: none;"></div>
80
81         <input type="hidden" id="firstletter_filter" value="" />
82         <div id="searchresults" style="display:none;">
83             <table id="memberresultst">
84                 <thead>
85                     <tr>
86                         [% FOR column IN columns %]
87                             [% SWITCH column %]
88                                 [% CASE 'cardnumber' %]<th>Card</th>
89                                 [% CASE 'dateofbirth' %]<th>Date of birth</th>
90                                 [% CASE 'address' %]<th>Address</th>
91                                 [% CASE 'name' %]<th>Name</th>
92                                 [% CASE 'branch' %]<th data-filter="libraries">Library</th>
93                                 [% CASE 'category' %]<th data-filter="categories">Category</th>
94                                 [% CASE 'dateexpiry' %]<th>Expires on</td>
95                                 [% CASE 'borrowernotes' %]<th>Notes</th>
96                                 [% CASE 'action' %]<th>&nbsp;</th>
97                             [% END %]
98                         [% END %]
99                     </tr>
100                   </thead>
101                 <tbody></tbody>
102             </table>
103         </div>
104
105 <div id="closewindow"><a href="#" class="btn btn-default btn-default close">Close</a></div>
106
107 <!-- Patron preview modal -->
108 <div class="modal" id="patronPreview" tabindex="-1" role="dialog" aria-labelledby="patronPreviewLabel">
109     <div class="modal-dialog" role="document">
110         <div class="modal-content">
111             <div class="modal-header">
112                 <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
113                 <h4 class="modal-title" id="patronPreviewLabel"></h4>
114             </div>
115             <div class="modal-body">
116                 <div id="loading">
117                     <img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading
118                 </div>
119             </div>
120             <div class="modal-footer">
121                 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
122             </div>
123         </div>
124     </div>
125 </div>
126
127 </div>
128 </div>
129
130 [% MACRO jsinclude BLOCK %]
131     <script>
132         let categories = [% To.json(categories) | $raw %];
133         let categories_map = categories.reduce((map, c) => {
134             map[c.categorycode] = c;
135             return map;
136         }, {});
137         let libraries  = [% To.json(libraries) | $raw %];
138         let libraries_map = libraries.reduce((map, l) => {
139             map[l.branchcode] = l;
140             return map;
141         }, {});
142
143         [% IF Koha.Preference('ExtendedPatronAttributes') %]
144             let extended_attribute_types = [% To.json(attribute_type_codes || []) | $raw %];
145         [% END %]
146     </script>
147     [% INCLUDE 'datatables.inc' %]
148     [% INCLUDE 'js-date-format.inc' %]
149     [% INCLUDE 'js-patron-get-age.inc' %]
150     [% INCLUDE 'js-patron-format.inc' %]
151     [% INCLUDE 'js-patron-format-address.inc' %]
152
153     <script>
154         var search = 0;
155         let patrons_table;
156         $(document).ready(function(){
157             $("#info").hide();
158             $("#error").hide();
159
160             $("#searchresults").hide();
161
162             let additional_filters = {
163                 surname: function(){
164                     let start_with = $("#firstletter_filter").val()
165                     if (!start_with) return "";
166                     return { "like": start_with + "%" }
167                 },
168                 "-and": function(){
169                     let filter = $("#searchmember_filter").val();
170                     if (!filter) return "";
171                     [% SET search_fields = Koha.Preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid' %]
172                     return [
173                         [% FOR search_field IN search_fields.split(',') %]
174                         {"me.[% search_field | html %]":{"like":"%"+filter+"%"}},
175                         [% END %]
176                         [% IF Koha.Preference('ExtendedPatronAttributes') %]
177                         {
178                             "extended_attributes.value": { "like": "%" + filter + "%" },
179                             "extended_attributes.code": extended_attribute_types
180                         }
181                         [% END %]
182                     ];
183                 },
184             };
185             [% SET default_sort_column = "name" %]
186             [% SET order_column_index = 0 %]
187             patrons_table = $("#memberresultst").kohaTable({
188                 "ajax": {
189                     [% SWITCH filter %]
190                     [% CASE 'suggestions_managers' %]
191                         "url": '/api/v1/suggestions/managers'
192                     [% CASE 'baskets_managers' %]
193                         "url": '/api/v1/acquisitions/baskets/managers'
194                     [% CASE 'funds_owners' %]
195                         "url": '/api/v1/acquisitions/funds/owners'
196                     [% CASE 'funds_users' %]
197                         "url": '/api/v1/acquisitions/funds/users'
198                     [% CASE %]
199                         "url": '/api/v1/patrons'
200                     [% END %]
201                 },
202                 embed: ['extended_attributes'],
203                 "iDeferLoading": 0,
204                 "columns": [
205                     [% FOR column IN columns %]
206                         [% IF default_sort_column == column %]
207                             [% order_column_index = loop.count - 1%]
208                         [% END %]
209                         [% SWITCH column %]
210                             [% CASE 'cardnumber' %]
211                             {
212                                 "data": "cardnumber",
213                                 "searchable": true,
214                                 "orderable": true
215                             }
216                             [% CASE 'dateofbirth' %]
217                             {
218                                 "data": "date_of_birth",
219                                 "searchable": true,
220                                 "orderable": true,
221                                 "render": function( data, type, row, meta ) {
222                                     return data ? escape_str($date(data) + " (" + _("%s years").format($get_age(data)) + ")") : "";
223                                 }
224                             }
225                             [% CASE 'address' %]
226                             {
227                                 "data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
228                                 "searchable": true,
229                                 "orderable": true,
230                                 "render": function( data, type, row, meta ) {
231                                     return escape_str($format_address(row) + " ") + escape_str(libraries_map[row.library_id].branchname);
232                                 }
233                             }
234                             [% CASE 'name' %]
235                             {
236                                 "data": "me.firstname:me.surname:me.othernames",
237                                 "searchable": true,
238                                 "orderable": true,
239                                 "render": function( data, type, row, meta ) {
240                                     let patron_id = encodeURIComponent(row.patron_id);
241                                     return "<a href=\"/cgi-bin/koha/members/moremember.pl?borrowernumber=" + patron_id + "\" class=\"patron_preview\" data-borrowernumber=\"" + patron_id + "\" style=\"white-space:nowrap\">" + $patron_to_html(row, { invert_name: 1 }) + "</a>";
242                                 }
243                             }
244                             [% CASE 'branch' %]
245                             {
246                                 "data": "library_id",
247                                 "searchable": true,
248                                 "orderable": true,
249                                 "render": function( data, type, row, meta ) {
250                                     return escape_str(libraries_map[data].branchname);
251                                 }
252                             }
253                             [% CASE 'category' %]
254                             {
255                                 "data": "category_id",
256                                 "searchable": true,
257                                 "orderable": true,
258                                 "render": function( data, type, row, meta ) {
259                                     return escape_str(categories_map[data].description);
260                                 }
261                             }
262                             [% CASE 'dateexpiry' %]
263                             {
264                                 "data": "expiry_date",
265                                 "searchable": true,
266                                 "orderable": true,
267                                 "render": function( data, type, row, meta ) {
268                                     return data ? escape_str($date(data)) : "";
269                                 }
270                             }
271                             [% CASE 'borrowernotes' %]
272                             {
273                                 "data": "staff_notes",
274                                 "searchable": true,
275                                 "orderable": true,
276                                 [%# We don't escape here, we allow html tag in staff notes %]
277                             }
278                             [% CASE 'action' %]
279                             {
280                                 "data": function( row, type, val, meta ) {
281
282                                     let patron_id = encodeURIComponent(row.patron_id);
283                                     [% IF selection_type == 'select' %]
284                                         return '<a href="#" class="btn btn-default btn-xs select_user" data-borrowernumber="' + patron_id + '">Select</a><input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '" value=\''+JSON.stringify(row)+'\' />';
285                                     [% ELSE %]
286                                         return '<a href="#" class="btn btn-default btn-xs add_user" data-borrowernumber="' + patron_id + '" data-firstname="' + encodeURIComponent(row.firstname) + '" data-surname="' + encodeURIComponent(row.surname) + '">Add</a><input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '" />';
287                                     [% END %]
288                                 },
289                                 "searchable": false,
290                                 "orderable": false
291                             }
292                         [% END %]
293                         [% UNLESS loop.last %],[% END %]
294                     [% END %]
295                 ],
296                 "order": [[ [% order_column_index | html %], "asc" ]],
297                 'bAutoWidth': false,
298                 'sPaginationType': 'full_numbers',
299                 "iDisplayLength": [% Koha.Preference('PatronsPerPage') | html %],
300             }, null, 1, additional_filters);
301
302             $("#searchform").on('submit', filter);
303             $(".filterByLetter").on("click",function(e){
304                 e.preventDefault();
305                 filterByFirstLetterSurname($(this).text());
306             });
307             $("body").on("click",".add_user",function(e){
308                 e.preventDefault();
309                 var borrowernumber = $(this).data("borrowernumber");
310                 var firstname = $(this).data("firstname");
311                 var surname = $(this).data("surname");
312                 add_user( borrowernumber, firstname + " " + surname );
313             });
314
315             $("body").on("click",".select_user",function(e){
316                 e.preventDefault();
317                 var borrowernumber = $(this).data("borrowernumber");
318                 var borrower_data = $("#borrower_data"+borrowernumber).val();
319                 select_user( borrowernumber, JSON.parse(borrower_data) );
320             });
321
322             $("body").on("click",".patron_preview", function( e ){
323                 e.preventDefault();
324                 var borrowernumber = $(this).data("borrowernumber");
325                 var page = "/cgi-bin/koha/members/moremember.pl?print=brief&borrowernumber=" + borrowernumber;
326                 $("#patronPreview .modal-body").load( page + " div.container-fluid" );
327                 $('#patronPreview').modal({show:true});
328             });
329
330             $("#patronPreview").on('hidden.bs.modal', function (e) {
331                 $("#patronPreview .modal-body").html("<img src=\"[% interface | html %]/[% theme | html %]/img/spinner-small.gif\" alt=\"\" /> Loading");
332             });
333
334         });
335
336         function filter() {
337             search = 1;
338             $("#firstletter_filter").val('');
339             $("#searchresults").show();
340
341             let table_dt = patrons_table.DataTable();
342             [% FOR c IN columns %]
343                 [% SWITCH c %]
344                 [% CASE 'branch' %]
345                     let library_id = $("#branchcode_filter").val();
346                     patrons_table.find('thead tr:eq(1) th[data-filter="libraries"] select').val(library_id);
347                     table_dt.column([% loop.count - 1 %]).search(library_id ? '^'+library_id+'$' : '');
348                 [% CASE 'category' %]
349                     let category_id = $("#categorycode_filter").val();
350                     patrons_table.find('thead tr:eq(1) th[data-filter="categories"] select').val(category_id);
351                     table_dt.column([% loop.count - 1 %]).search(category_id ? '^'+category_id+'$' : '');
352                 [% END %]
353             [% END %]
354             table_dt.search("");
355             table_dt.draw();
356             return false;
357         }
358
359         // User has clicked on a letter
360         function filterByFirstLetterSurname(letter) {
361             $("#firstletter_filter").val(letter);
362             search = 1;
363             $("#searchresults").show();
364             patrons_table.fnDraw();
365         }
366
367         // modify parent window owner element
368         [% IF selection_type == 'add' %]
369             function add_user(borrowernumber, borrowername) {
370                 var p = window.opener;
371                 // In one place (serials/routing.tt), the page is reload on every add
372                 // We have to wait for the page to be there
373                 function wait_for_opener () {
374                     if ( ! $(opener.document).find('body').size() ) {
375                         setTimeout(wait_for_opener, 500);
376                     } else {
377                         [%# Note that add_user could sent data instead of borrowername too %]
378                         $("#info").hide();
379                         $("#error").hide();
380                         if ( p.add_user(borrowernumber, borrowername) < 0 ) {
381                             $("#error").html(_("Patron '%s' is already in the list.").format(borrowername));
382                             $("#error").show();
383                         } else {
384                             $("#info").html(_("Patron '%s' added.").format(borrowername));
385                             $("#info").show();
386                         }
387                     }
388                 }
389                 wait_for_opener();
390             }
391         [% ELSIF selection_type == 'select' %]
392             function select_user(borrowernumber, data) {
393                 var p = window.opener;
394                 [%  IF callback %]
395                     p.[% callback | html %](borrowernumber, data);
396                 [%  ELSE %]
397                     p.select_user(borrowernumber, data);
398                 [%  END %]
399                 window.close();
400             }
401         [% END %]
402     </script>
403 [% END %]
404
405 [% SET popup_window = 1 %]
406 [% INCLUDE 'intranet-bottom.inc' %]