finish schedule pickup tab for the staff interface
authorGalen Charlton <gmc@equinoxinitiative.org>
Tue, 2 Jun 2020 22:36:56 +0000 (18:36 -0400)
committerGalen Charlton <gmc@equinoxinitiative.org>
Tue, 2 Jun 2020 22:36:56 +0000 (18:36 -0400)
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Open-ILS/src/templates/staff/circ/curbside/index.tt2
Open-ILS/src/templates/staff/circ/curbside/t_schedule_pickup.tt2
Open-ILS/web/js/ui/default/staff/circ/curbside/directives/schedule_pickup.js

index e17ec40..efbf980 100644 (file)
@@ -26,6 +26,12 @@ angular.module('egCoreMod').run(['egStrings', function(s) {
     s.SUCCESS_CURBSIDE_MARK_DELIVERED = "[% l('Marked curbside appointment {{slot_id}} as delivered') %]";
     s.NOTFOUND_CURBSIDE_MARK_DELIVERED = "[% l('Could not find curbside appointment {{slot_id}} to mark as delivered') %]";
     s.FAILED_CURBSIDE_MARK_DELIVERED = "[% l('Failed to mark curbside appointment {{slot_id}} as delivered: {{evt_code}}') %]";
+    s.CONFIRM_CANCEL_TITLE = "[% l('Cancel Curbside Pickup Appointment') %]";
+    s.CONFIRM_CANCEL_BODY = "[% l('Cancel curbside pickup appointment [_1]?', '{{slot_id}}') %]";
+    s.SUCCESS_CANCEL_APPOINTMENT = "[% l('Canceled curbside appointment {{slot_id}}') %]";
+    s.FAILED_CANCEL_APPOINTMENT = "[% l('Failed to cancel curbside appointment {{slot_id}} ({{evt_code}})') %]";
+    s.SUCCESS_SAVE_APPOINTMENT = "[% l('Saved curbside appointment {{slot_id}}') %]";
+    s.FAILED_SAVE_APPOINTMENT = "[% l('Failed to save changes to curbside appointment ({{evt_code}})') %]";
 }]);
 </script>
 [% END %]
index 65dae44..2425a26 100644 (file)
   <div class="row">
     [% l('Patron has [_1] ready holds at this location.', '{{readyHolds}}') %]
   </div>
+
+  <div class="row">
+    <button ng-disabled="openAppointments.length > 0" ng-click="startNewAppointment()" class="btn btn-success">[% l('Make New Appointment') %]</button>
+  </div>
+  <br>
+  <div class="row form-inline" ng-repeat="appt in openAppointments">
+    <ng-form name="forms['curbside' + appt.id]">
+      <div class="col-md-1">
+        <label for="appointment-id">[% l('Appointment') %]</label>
+        <div id="appointment-id">{{appt.id}}</div>
+      </div>
+      <div class="col-md-1">
+        <label for="appointment-day">[% l('Date') %]</label>
+        <eg-date-input id="appointment-day" hide-time-picker ng-model="appt.slot_date"
+                       required min-date="minDate">
+        </eg-date-input>
+      </div>
+      <div class="col-md-1 input-group">
+        <label for="appointment-time">[% l('Time') %]</label>
+        <select class="form-control" id="appointment-time" ng-model="appt.slot_time"
+                name="slot_time"
+                required ng-focus="refreshAvailableTimes(appt)">
+          <option ng-repeat="t in appt.available_times" value="{{t}}">{{t}}</option>
+        </select>
+      </div>
+      <div class="col-md-2 input-group">
+        <label for="appointment-actions">[% l('Actions') %]</label>
+        <div id="appointment-actions">
+          <button ng-click="updateAppointment(appt)" ng-disabled="!forms['curbside' + appt.id].$valid" class="btn btn-primary">[% l('Save') %]</button>
+          <button ng-click="cancelAppointment(appt.id)" ng-disabled="!appt.id" class="btn btn-danger">[% l('Cancel Appointment') %]</button>
+        </div>
+      </div>
+    </ng-form>
+  </div>
 </span>
index 7ec9be6..c4b9f8b 100644 (file)
@@ -16,6 +16,8 @@ function($scope , $q , egCurbsideCoreSvc , egCore , patronSvc ,
         $scope.user_id = undefined;
         $scope.args = {};
         $scope.readyHolds = 0;
+        $scope.openAppointments = [];
+        $scope.forms = [];
     }
     $scope.clear();
 
@@ -207,11 +209,150 @@ function($scope , $q , egCurbsideCoreSvc , egCore , patronSvc ,
         });
     }
 
+    function fetchOpenAppointments(user_id) {
+        return egCore.net.request(
+            'open-ils.curbside',
+            'open-ils.curbside.open_user_appointments_at_lib.atomic',
+            egCore.auth.token(),
+            user_id
+        ).then(function(resp) {
+            if (evt = egCore.evt.parse(resp)) {
+                return 0;
+            } else {
+                return resp;
+            }
+        });
+    }
+
+    function mungeOneAppointment(c, isNew) {
+        var hash = egCore.idl.toHash(c);
+        if (hash.slot === null) {
+            // coerce to today for the purpose of the
+            // form if no slot time has been set yet
+            hash.slot = new Date().toISOString();
+            hash.slot_time = null;
+        } else {
+            if (!isNew) {
+                hash.slot_time = hash.slot.substring(11, 19);
+            }
+        }
+        hash.slot_date = new Date(hash.slot);
+        hash.available_times = [];
+        egCore.net.request (
+            'open-ils.curbside',
+            'open-ils.curbside.times_for_date.atomic',
+            egCore.auth.token(),
+            hash.slot.substring(0, 10),
+        ).then(function(times) {
+            hash.available_times = times.map(function(t) { return t[0]; });
+        });
+        return hash;
+    }
+
+    function mungeAppointmentList(list) {
+        $scope.openAppointments = list.map(function(c) {
+            var hash = mungeOneAppointment(c);
+            return hash;
+        });
+    }
+
     function loadPatron(user_id) {
         $scope.user_id = user_id;
         patronSvc.getPrimary(user_id);
         countReadyHolds(user_id).then(function(ct) { $scope.readyHolds = ct });        
+        fetchOpenAppointments(user_id).then(function(list) {
+            mungeAppointmentList(list);
+        });
+    }
+
+
+    $scope.minDate = new Date();
+    $scope.refreshAvailableTimes = function(hash) {
+        var dateStr = (new Date(hash.slot_date)).toISOString().substring(0, 10);
+        egCore.net.request (
+            'open-ils.curbside',
+            'open-ils.curbside.times_for_date.atomic',
+            egCore.auth.token(),
+            dateStr,
+        ).then(function(times) {
+            hash.available_times = times.map(function(t) { return t[0]; });
+        });
     }
+
+    $scope.startNewAppointment = function() {
+        var slot = new egCore.idl.acsp();
+        slot.slot = new Date().toISOString();
+        slot.patron = $scope.user_id;
+        slot.org = egCore.auth.user().ws_ou();
+        $scope.openAppointments = [ mungeOneAppointment(slot, true) ];
+    }
+
+    $scope.updateAppointment = function(appt) {
+        var op = angular.isDefined(appt.id) ? 'update' : 'create';
+        egCore.net.request(
+            'open-ils.curbside',
+            'open-ils.curbside.' + op + '_appointment',
+            egCore.auth.token(),
+            $scope.user_id,
+            (new Date(appt.slot_date)).toISOString().substring(0, 10),
+            appt.slot_time
+        ).then(function(resp) {
+            if (evt = egCore.evt.parse(resp)) {
+                ngToast.danger(egCore.strings.$replace(
+                    egCore.strings.FAILED_SAVE_APPOINTMENT,
+                    { evt_code : evt.code }
+                ));
+            } else {
+                ngToast.success(egCore.strings.$replace(
+                    egCore.strings.SUCCESS_SAVE_APPOINTMENT,
+                    { slot_id : resp.id() }
+                ));
+            }
+            fetchOpenAppointments($scope.user_id).then(function(list) {
+                mungeAppointmentList(list);
+            });
+        });
+    }
+
+    function doCancel(id) {
+        egCore.net.request (
+            'open-ils.curbside',
+            'open-ils.curbside.delete_appointment',
+            egCore.auth.token(),
+            id
+        ).then(function(resp) {
+            if (!angular.isDefined(resp)) {
+                ngToast.danger(egCore.strings.$replace(
+                    egCore.strings.FAILED_CANCEL_APPOINTMENT,
+                    { slot_id : id, evt_code : 'NO_SUCH_APPOINTMENT' }
+                ));
+            } else if (evt = egCore.evt.parse(resp)) {
+                ngToast.danger(egCore.strings.$replace(
+                    egCore.strings.FAILED_CANCEL_APPOINTMENT,
+                    { slot_id : id, evt_code : evt.code }
+                ));
+            } else {
+                ngToast.success(egCore.strings.$replace(
+                    egCore.strings.SUCCESS_CANCEL_APPOINTMENT,
+                    { slot_id : id }
+                ));
+            }
+            fetchOpenAppointments($scope.user_id).then(function(list) {
+                mungeAppointmentList(list);
+            });
+        });
+    }
+    $scope.cancelAppointment = function(id) {
+        egConfirmDialog.open(
+            egCore.strings.CONFIRM_CANCEL_TITLE,
+            egCore.strings.CONFIRM_CANCEL_BODY,
+            {   slot_id : id,
+                ok : function() { doCancel(id) },
+                cancel : function() {}
+            }
+        );
+    }
+
     $scope.patron = function() {
         return patronSvc.current;
     }