%]
[% BLOCK APP_JS %]
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/list.js"></script><!-- remove me -->
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/app.js"></script>
+
+<!-- load on demand? -->
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/checkout.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/items_out.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/holds.js"></script>
<!-- TODO: APP_JS should really be called APP_ADDONS or some such.
It just means "load these things, too, and load them last" -->
<!-- patron holds list -->
-<div class="row pad-vert">
- <div class="col-md-12 text-right">
- [% INCLUDE 'staff/circ/patron/t_holds_actions.tt2' %]
- </div>
-</div>
+<eg-grid
+ id-field="id"
+ features="-display,-sort,-multisort"
+ main-label="[% l('Items On Hold') %]"
+ items-provider="gridDataProvider"
+ persist-key="eg.staff.circ.patron.holds">
+ <eg-grid-field label="[% ('Hold ID') %]" path='hold.id' visible></eg-grid-field>
+ <eg-grid-field label="[% ('Current Copy') %]" path='hold.current_copy.barcode' visible></eg-grid-field>
+ <eg-grid-field label="[% l('Request Date') %]" path='hold.request_time' visible></eg-grid-field>
+ <eg-grid-field label="[% l('Capture Date') %]" path='hold.capture_time' visible></eg-grid-field>
+ <eg-grid-field label="[% l('Available Date') %]" path='hold.shelf_time' visible></eg-grid-field>
+ <eg-grid-field label="[% l('Hold Type') %]" path='hold.hold_type' visible></eg-grid-field>
+ <eg-grid-field label="[% l('Pickup Library') %]" path='hold.pickup_lib.shortname' visible></eg-grid-field>
+ <eg-grid-field label="[% l('Title') %]" path='mvr.title' visible></eg-grid-field>
+ <eg-grid-field label="[% l('Author') %]" path='mvr.author' visible></eg-grid-field>
+</eg-grid>
-[% INCLUDE 'staff/circ/patron/t_holds_table.tt2' %]
+++ /dev/null
-<div class="btn-group text-left" ng-show="holds.count()">
-
- <!-- PAGING -->
-
- <!--
- <button type="button" class="btn btn-default"
- ng-class="{disabled : holds.onFirstPage()}"
- ng-click="holds.offset = 0;draw()">[% l('Start') %]</button>
-
- <button type="button" class="btn btn-default"
- ng-class="{disabled : holds.onFirstPage()}"
- ng-click="holds.decrementPage();draw()">«</button>
-
- <button type="button" class="btn btn-default"
- ng-class="{disabled : !holds.hasNextPage()}"
- ng-click="holds.incrementPage();draw()">»</button>
- -->
-
- <div class="btn-group">
- <button type="button" class="btn btn-default dropdown-toggle"
- ng-class="{disabled : !holds.count()}" data-toggle="dropdown">
- [% l('Actions') %] <span class="caret"></span>
- </button>
- <ul class="dropdown-menu pull-right">
- <li class="disabled" xxxng-class="{disabled : !holds.count()}">
- <a href="" ng-click="">
- [% l('Cancel Hold(s)') %]</a>
- </li>
- </ul>
- </div>
-
- [% INCLUDE 'staff/parts/column_picker.tt2' listname='holds' %]
-</div>
-
+++ /dev/null
-[%
-COLUMNS = [
-{label => l('Hold ID'), name => 'hold.id', display => 1},
-{label => l('Current Copy'), name => 'hold.current_copy.barcode' display => 1},
-{label => l('Request Date'), name => 'hold.request_time' display => 1},
-{label => l('Capture Date'), name => 'hold.capture_time' display => 1},
-{label => l('Available Date'), name => 'hold.shelf_time' display => 1},
-{label => l('Type'), name => 'hold.hold_type' display => 1},
-{label => l('Pickup Library'), name => 'hold.pickup_lib.shortname' display => 1},
-{label => l('Title'), name => 'mvr.title', display => 1},
-{label => l('Author'), name => 'mvr.author', display => 1}
-]
-%]
-
-<!-- tell JS about our columns so they can be dynamically managed -->
-<div ng-init="
-holds.setColumns([
-[%- FOR col IN COLUMNS %]
-{label:'[% col.label %]',name:'[% col.name %]'[% IF col.display %],display:true[% END %]}[% IF !loop.last; ','; END -%]
-[% END %]
-]);
-holds.addColumnsForClass('ahr', 'hold');
-">
-</div>
-
-
-<div class="row" ng-show="!loading && !holds.count()">
- <div class="col-md-10 col-md-offset-1">
- <div class="alert alert-info">[% l('No Holds To Display') %]</div>
- </div>
-</div>
-
-<div class="row" ng-show="holds.count()">
- <div class="col-md-12">
- <table class="list table table-hover table-condensed">
- <thead>
- <tr>
- <th>#</th>
- <th><a href='' ng-click="holds.toggleSelectAll()">✓</a></th>
- <th ng-repeat="col in holds.allColumns"
- ng-show="holds.displayColumns[col.name]">
- {{col.label}}
- </th>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="hold_data in holds.items | reverse track by $index"
- ng-click="onRowClick($event, hold_data)"
- ng-class="{selected : holds.selected[hold_data.id]}">
- <td>{{$index + 1}}</td>
- <td><span ng-if="holds.selected[hold_data.id]">✓</span>
- <td ng-repeat="col in holds.allColumns"
- ng-show="holds.displayColumns[col.name]">
- {{holds.fieldValue(hold_data, col.name)}}
- </td>
- </tr>
- </tbody>
- </table>
- </div>
-</div>
*/
angular.module('egPatronApp', ['ngRoute', 'ui.bootstrap',
- 'egCoreMod', 'egUiMod', 'egGridMod', 'egListMod', 'egUserMod'])
+ 'egCoreMod', 'egUiMod', 'egGridMod', 'egUserMod'])
.config(function($routeProvider, $locationProvider, $compileProvider) {
$locationProvider.html5Mode(true);
* Patron service
*/
.factory('patronSvc',
- ['$q','$timeout','egList','egNet','egAuth','egUser','egEnv','egOrg','egList',
-function($q , $timeout , egList, egNet, egAuth, egUser, egEnv, egOrg, egList) {
+ ['$q','$timeout','egNet','egAuth','egUser','egEnv','egOrg',
+function($q , $timeout , egNet, egAuth, egUser, egEnv, egOrg) {
var service = {
// currently selected patron object
service.checkouts = [];
service.items_out = []
service.items_out_ids = [];
- /*
- service.holds.reset();
- service.bills.reset();
- service.messages.reset();
- */
+ service.holds = [];
+ service.hold_ids = [];
service.checkout_overrides = {};
}
service.resetPatronLists(); // initialize
*/
.controller('PatronSearchCtrl',
['$scope','$q','$routeParams','$timeout','$window','$location','egEnv',
- '$filter','egIDL','egNet','egAuth','egEvent','egList','egUser',
+ '$filter','egIDL','egNet','egAuth','egEvent','egUser',
'patronSvc','egGridDataProvider','egPrintStore',
function($scope, $q, $routeParams, $timeout, $window, $location, egEnv,
- $filter, egIDL, egNet, egAuth, egEvent, egList, egUser,
+ $filter, egIDL, egNet, egAuth, egEvent, egUser,
patronSvc , egGridDataProvider , egPrintStore) {
$scope.initTab('search');
// from the parent scope. Nothing to do here.
}])
-
-/**
- * Manages holds
- */
-.controller('PatronHoldsCtrl',
- ['$scope','$q','$routeParams','egNet','egAuth','egUser','patronSvc','egOrg',
-function($scope, $q, $routeParams, egNet, egAuth, egUser, patronSvc, egOrg) {
- $scope.initTab('holds', $routeParams.id);
-
- $scope.holds = patronSvc.holds;
-
- $scope.onRowClick = function($event, hold) {
- $scope.lastSelected = hold;
- if ($event.ctrlKey || $event.metaKey) {
- $scope.holds.toggleOneSelection(hold.id);
- } else {
- $scope.holds.selectOne(hold.id);
- }
- }
-
- function fetchPatronHolds() {
- $scope.loading = true;
-
- egNet.request(
- 'open-ils.circ',
- 'open-ils.circ.holds.id_list.retrieve.authoritative',
- egAuth.token(), $scope.patron_id
-
- ).then(function(hold_ids) {
-
- if (!hold_ids.length) {
- $scope.loading = false;
- return;
- }
-
- angular.forEach(hold_ids, function(id) {
-
- egNet.request(
- 'open-ils.circ',
- 'open-ils.circ.hold.details.retrieve.authoritative',
- egAuth.token(), id
-
- ).then(function(hold_data) {
- $scope.loading = false;
- var hold = hold_data.hold;
- hold_data.id = hold.id();
-
- // flesh
- hold.pickup_lib(egOrg.get(hold.pickup_lib()));
-
- angular.forEach(hold_ids, function(id, idx) {
- if (id == hold.id()) // maintain order
- patronSvc.holds.items[idx] = hold_data;
- });
- });
- })
- })
- }
-
- fetchPatronHolds(); // TODO: only when necessary
-
-}])
-
/**
- * Manages bills
+ * Manages edit
*/
.controller('PatronBillsCtrl',
['$scope','$q','$routeParams','egNet','egAuth','egUser','patronSvc',
$scope.initTab('bills', $routeParams.id);
}])
+
/**
* Manages messages
*/
--- /dev/null
+/**
+ * List of patron holds
+ */
+
+angular.module('egPatronApp').controller('PatronHoldsCtrl',
+
+ ['$scope','$q','$routeParams','egNet','egAuth','egUser','patronSvc','egOrg','egGridDataProvider',
+function($scope, $q, $routeParams, egNet, egAuth, egUser, patronSvc, egOrg , egGridDataProvider) {
+ $scope.initTab('holds', $routeParams.id);
+
+ var provider = egGridDataProvider.instance({});
+ provider.itemFieldValue = provider.nestedItemFieldValue;
+ $scope.gridDataProvider = provider;
+
+ function fetchHolds(offset, count) {
+
+ var ids = patronSvc.hold_ids.slice(offset, offset + count);
+
+ return egNet.request(
+ 'open-ils.circ',
+ 'open-ils.circ.hold.details.batch.retrieve.authoritative',
+ egAuth.token(), ids
+
+ ).then(null, null, function(hold_data) {
+ $scope.loading = false;
+ var hold = hold_data.hold;
+ hold_data.id = hold.id();
+ hold.pickup_lib(egOrg.get(hold.pickup_lib())); // flesh
+ patronSvc.holds.push(hold_data);
+ return hold_data;
+ });
+ }
+
+ provider.get = function(offset, count) {
+
+ // see if we have the requested range cached
+ if (patronSvc.holds[offset]) {
+ return patronSvc.arrayNotifier(
+ patronSvc.holds.slice(offset, offset + count)
+ );
+ }
+
+ // see if we have the holds IDs for this range already loaded
+ if (patronSvc.hold_ids[offset]) {
+ return fetchHolds(offset, count);
+ }
+
+ var deferred = $q.defer();
+ patronSvc.hold_ids = [];
+
+ egNet.request(
+ 'open-ils.circ',
+ 'open-ils.circ.holds.id_list.retrieve.authoritative',
+ egAuth.token(), $scope.patron_id
+
+ ).then(function(hold_ids) {
+ console.log('fetched hold ids ' + hold_ids);
+
+ if (!hold_ids.length) { deferred.resolve(); return; }
+
+ patronSvc.hold_ids = hold_ids;
+ fetchHolds(offset, count).then(null, null, deferred.notify);
+ });
+
+ return deferred.promise;
+ }
+}])
+
+