lp1635386 Items Column & Styles for Bill Item Status
authorKyle Huckins <khuckins@catalyte.io>
Fri, 17 Nov 2017 23:54:53 +0000 (23:54 +0000)
committerDan Wells <dbw2@calvin.edu>
Thu, 28 Jun 2018 18:20:49 +0000 (14:20 -0400)
- CSS classes for red, dark red, and orange eg-grid-cells.
- New parameter for eg-grid 'rowClass' to take an object with a function
to set the class of a cell, allowing such customizations as coloring based
on item fields.
- Implementation of 'rowClass' on the Patron Bills interface to display
colors indicating current Fines Stop reason, based on XUL client.
- New parameter for eg-grid 'statusCell' to take an object with a function
to programattically add status icons to a new "Status Icon" column. Said
column requires a boolean in the object in order to display.
- Implementation of 'statusCell' on the Patron Bills interface to display
glyphicons based on if the bill is for a circ that is lost, overdue, or long
overdue.

Signed-off-by: Kyle Huckins <khuckins@catalyte.io>
 Changes to be committed:
modified:   Open-ILS/src/templates/staff/circ/patron/t_bills_list.tt2
modified:   Open-ILS/src/templates/staff/css/style.css.tt2
modified:   Open-ILS/src/templates/staff/share/t_autogrid.tt2
modified:   Open-ILS/web/js/ui/default/staff/circ/patron/bills.js
modified:   Open-ILS/web/js/ui/default/staff/services/grid.js

Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Signed-off-by: Dan Wells <dbw2@calvin.edu>
Signed-off-by: Dawn Dale <ddale@georgialibraries.org>
Open-ILS/src/templates/staff/circ/patron/t_bills_list.tt2
Open-ILS/src/templates/staff/css/style.css.tt2
Open-ILS/src/templates/staff/share/t_autogrid.tt2
Open-ILS/web/js/ui/default/staff/circ/patron/bills.js
Open-ILS/web/js/ui/default/staff/services/grid.js

index a6be0cc..ad1db19 100644 (file)
@@ -6,7 +6,9 @@
   grid-controls="gridControls"
   revision="gridRevision"
   persist-key="circ.patron.bills"
   grid-controls="gridControls"
   revision="gridRevision"
   persist-key="circ.patron.bills"
-  dateformat="{{$root.egDateAndTimeFormat}}">
+  dateformat="{{$root.egDateAndTimeFormat}}"
+  row-class="colorizeBillsList"
+  status-cell="statusIconColumn">
 
   <eg-grid-menu-item label="[% l('Bill Patron') %]" 
     handler="showBillDialog"></eg-grid-menu-item>
 
   <eg-grid-menu-item label="[% l('Bill Patron') %]" 
     handler="showBillDialog"></eg-grid-menu-item>
@@ -48,7 +50,7 @@
   <eg-grid-action label="[% l('Full Details') %]" 
     handler="showFullDetails"></eg-grid-action>
 
   <eg-grid-action label="[% l('Full Details') %]" 
     handler="showFullDetails"></eg-grid-action>
 
-  <eg-grid-field label="[% l('Balance Owed') %]" path='summary.balance_owed'></eg-grid-field>
+  <eg-grid-field label="[% l('Balance Owed') %]" path='summary.balance_owed' required></eg-grid-field>
   <eg-grid-field label="[% l('Bill #') %]" path='id'></eg-grid-field>
   <eg-grid-field label="[% l('Start') %]" path='xact_start' datatype="timestamp"></eg-grid-field>
   <eg-grid-field label="[% l('Total Billed') %]" path='summary.total_owed'></eg-grid-field>
   <eg-grid-field label="[% l('Bill #') %]" path='id'></eg-grid-field>
   <eg-grid-field label="[% l('Start') %]" path='xact_start' datatype="timestamp"></eg-grid-field>
   <eg-grid-field label="[% l('Total Billed') %]" path='summary.total_owed'></eg-grid-field>
   <eg-grid-field path='circulation.circ_lib' required hidden></eg-grid-field>
   <eg-grid-field path='circulation.duration' required hidden></eg-grid-field>
   <eg-grid-field path='circulation.due_date' dateonlyinterval="circulation.duration" datecontext="circulation.circ_lib" required hidden></eg-grid-field>
   <eg-grid-field path='circulation.circ_lib' required hidden></eg-grid-field>
   <eg-grid-field path='circulation.duration' required hidden></eg-grid-field>
   <eg-grid-field path='circulation.due_date' dateonlyinterval="circulation.duration" datecontext="circulation.circ_lib" required hidden></eg-grid-field>
+  <eg-grid-field label="[% l('Stop Fines') %]" path="circulation.stop_fines" hidden required>  </eg-grid-field>
+  <eg-grid-field path="circulation.checkin_time" hidden required></eg-grid-field>
   <eg-grid-field path='circulation.*' hidden> </eg-grid-field>
   <eg-grid-field label="[% l('Checkout / Renewal Library') %]"
     path='circulation.circ_lib.shortname' required hidden> </eg-grid-field>
   <eg-grid-field path='circulation.*' hidden> </eg-grid-field>
   <eg-grid-field label="[% l('Checkout / Renewal Library') %]"
     path='circulation.circ_lib.shortname' required hidden> </eg-grid-field>
index b70887b..ebeab4a 100644 (file)
@@ -301,12 +301,22 @@ table.list tr.selected td { /* deprecated? */
   text-align: center;
 }
 
   text-align: center;
 }
 
-/* the conf header must be twice the stock flex */
+.eg-grid-cell-stock-status {
+  width: 4.4em;
+  text-align: center;
+}
+
+/* the conf header must be ~four times the stock flex */
 .eg-grid-cell-conf-header {
   width: 4.4em;
   font-weight: bold;
 }
 
 .eg-grid-cell-conf-header {
   width: 4.4em;
   font-weight: bold;
 }
 
+.eg-grid-cell-conf-header-status {
+  width: 8.8em;
+  font-weight: bold;
+}
+
 .eg-grid-row-selected {
   color: #000;
   background-color: rgb(201, 221, 225);
 .eg-grid-row-selected {
   color: #000;
   background-color: rgb(201, 221, 225);
@@ -333,6 +343,30 @@ table.list tr.selected td { /* deprecated? */
   background: rgb(201, 221, 225);
   border-bottom: 1px solid #888;
 }
   background: rgb(201, 221, 225);
   border-bottom: 1px solid #888;
 }
+
+/* patron bill row-highlighting */
+.red-row-highlight {
+  color: #FFF;
+  background-color: #FF0000;
+}
+.orange-row-highlight {
+  color: #FFF;
+  background-color: #FFA500 ;
+}
+.dark-red-row-highlight {
+  color: #FFF;
+  background-color: #800000;
+}
+.eg-grid-row-selected .red-row-highlight {
+  background-color: #CF0000;
+}
+.eg-grid-row-selected .orange-row-highlight {
+  background-color: #DE9000;
+}
+.eg-grid-row-selected .dark-red-row-highlight {
+  background-color: #5C0000;
+}
+
 .eg-grid-cell-content::selection {
   color: #000;
   background: rgb(201, 221, 225);
 .eg-grid-cell-content::selection {
   color: #000;
   background: rgb(201, 221, 225);
index 0519012..21d602b 100644 (file)
           type='checkbox' ng-model="selectAll"/> 
       </div>
     </div>
           type='checkbox' ng-model="selectAll"/> 
       </div>
     </div>
+    <div class="eg-grid-cell eg-grid-cell-stock-status" ng-show="statusCell.isEnabled">
+      <div title="[% l('Status Icon Column') %]">[% l('Status') %]</div>
+    </div>
     <div class="eg-grid-cell"
         eg-grid-column-drag-dest
         ng-class="{'eg-grid-column-last-mod' : isLastModifiedColumn(col)}"
     <div class="eg-grid-cell"
         eg-grid-column-drag-dest
         ng-class="{'eg-grid-column-last-mod' : isLastModifiedColumn(col)}"
 
   <!-- Inline grid configuration row -->
   <div class="eg-grid-row eg-grid-conf-row" ng-show="showGridConf">
 
   <!-- Inline grid configuration row -->
   <div class="eg-grid-row eg-grid-conf-row" ng-show="showGridConf">
-    <div class="eg-grid-cell eg-grid-cell-conf-header">
+    <div class="eg-grid-cell"
+      ng-class="statusicon.isEnabled ? 'eg-grid-cell-conf-header-status' : 'eg-grid-cell-conf-header'">
       <div class="eg-grid-conf-cell-entry">[% l('Expand') %]</div>
       <div class="eg-grid-conf-cell-entry">[% l('Shrink') %]</div>
     </div>
       <div class="eg-grid-conf-cell-entry">[% l('Expand') %]</div>
       <div class="eg-grid-conf-cell-entry">[% l('Shrink') %]</div>
     </div>
         ng-show="items.length > 0"
         ng-class="{'eg-grid-row-selected' : selected[indexValue(item)]}">
       <div class="eg-grid-cell eg-grid-cell-stock" ng-show="showIndex"
         ng-show="items.length > 0"
         ng-class="{'eg-grid-row-selected' : selected[indexValue(item)]}">
       <div class="eg-grid-cell eg-grid-cell-stock" ng-show="showIndex"
-        ng-click="handleRowClick($event, item)" title="[% l('Row Index') %]">
+        ng-click="handleRowClick($event, item)" title="[% l('Row Index') %]"
+          ng-class="rowClass.rowClass(item)">
         <a href ng-show="gridControls.activateItem" 
           ng-click="gridControls.activateItem(item)" style="font-weight:bold">
           {{$index + offset() + 1}}
         </a>
         <div ng-hide="gridControls.activateItem">{{$index + offset() + 1}}</div>
       </div>
         <a href ng-show="gridControls.activateItem" 
           ng-click="gridControls.activateItem(item)" style="font-weight:bold">
           {{$index + offset() + 1}}
         </a>
         <div ng-hide="gridControls.activateItem">{{$index + offset() + 1}}</div>
       </div>
-      <div class="eg-grid-cell eg-grid-cell-stock" ng-show="canMultiSelect">
+      <div class="eg-grid-cell eg-grid-cell-stock" ng-show="canMultiSelect"
+          ng-class="rowClass.rowClass(item)">
         <!-- ng-click=handleRowClick here has unintended 
              consequences and is unnecessary, avoid it -->
         <div>
         <!-- ng-click=handleRowClick here has unintended 
              consequences and is unnecessary, avoid it -->
         <div>
             ng-model="selected[indexValue(item)]"/>
         </div>
       </div>
             ng-model="selected[indexValue(item)]"/>
         </div>
       </div>
+      <div class="eg-grid-cell eg-grid-cell-stock-status" ng-show="statusCell.isEnabled"
+          ng-class="rowClass.rowClass(item)">
+          <span ng-bind-html="statusCell.template(item)"></span>
+      </div>
       <div class="eg-grid-cell eg-grid-cell-content"
           ng-click="handleRowClick($event, item)"
           ng-dblclick="gridControls.activateItem(item)"
           ng-repeat="col in columns"
           style="text-align:{{col.align}}; flex:{{col.flex}}"
       <div class="eg-grid-cell eg-grid-cell-content"
           ng-click="handleRowClick($event, item)"
           ng-dblclick="gridControls.activateItem(item)"
           ng-repeat="col in columns"
           style="text-align:{{col.align}}; flex:{{col.flex}}"
-          ng-show="col.visible">
+          ng-show="col.visible"
+          ng-class="rowClass.rowClass(item)">
 
           <!-- if the cell comes with its own template,
                translate that content into HTML and insert it here -->
 
           <!-- if the cell comes with its own template,
                translate that content into HTML and insert it here -->
index 89110aa..a84ab2c 100644 (file)
@@ -219,6 +219,52 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
             return ['xact_start']; 
         }
     }
             return ['xact_start']; 
         }
     }
+    // -------------
+    // Apply coloring to rows based on fines stop reason
+    $scope.colorizeBillsList = {
+        rowClass: function(item) {
+            if (!item['circulation.checkin_time']) {
+                if (item['circulation.stop_fines'] == 'LOST') {
+                    return 'dark-red-row-highlight';
+                } else if (item['circulation.stop_fines'] == 'LONGOVERDUE') {
+                    return 'red-row-highlight';
+                } else if (item['circulation.due_date'] &&  // Still checked out - need feedback on this approach, feel like there's a better way
+                          !item['circulation.stop_fines']) {
+                    return 'orange-row-highlight';
+                }
+            }
+        }
+    }
+
+    // Status Icon Column definition
+    $scope.statusIconColumn = {
+        isEnabled: true,
+        template: function(item) {
+            var template = "";
+            var icons = [];
+            var now = new Date();
+
+            if (item['circulation.due_date'] &&
+                !item['circulation.checkin_time']) {
+                var due_date = new Date(item['circulation.due_date']);
+
+                if (item['circulation.stop_fines'] &&
+                    item['circulation.stop_fines'] == "LOST") {
+                    icons.push('glyphicon-question-sign');
+                } else if (item['circulation.stop_fines'] &&
+                    item['circulation.stop_fines'] == "LONGOVERDUE") {
+                    icons.push('glyphicon-exclamation-sign');
+                } else if (now >= due_date) {
+                    icons.push('glyphicon-time');
+                }
+            }
+
+            angular.forEach(icons, function(icon) {
+                template = template + "<i class='glyphicon " + icon + "'></i>"
+            });
+            return template;
+        }
+    }
 
     billSvc.fetchSummary().then(function(s) {$scope.summary = s});
 
 
     billSvc.fetchSummary().then(function(s) {$scope.summary = s});
 
index 15d61f2..71e271c 100644 (file)
@@ -54,6 +54,14 @@ angular.module('egGridMod',
             //                 column
             features : '@',
 
             //                 column
             features : '@',
 
+            // optional: object containing function to conditionally apply
+            //    class to each row.
+            rowClass : '=',
+
+            // optional: object that enables status icon field and contains
+            //    function to handle what status icons should exist and why.
+            statusCell : '=',
+
             // optional primary grid label
             mainLabel : '@',
 
             // optional primary grid label
             mainLabel : '@',
 
@@ -110,6 +118,9 @@ angular.module('egGridMod',
             scope.handleAutoFields();
             scope.collect();
 
             scope.handleAutoFields();
             scope.collect();
 
+            var statusCell = scope.statusCell;
+            var rowClass = scope.rowClass;
+
             scope.grid_element = element;
             $(element)
                 .find('.eg-grid-content-body')
             scope.grid_element = element;
             $(element)
                 .find('.eg-grid-content-body')