From 385b01405660729f87defdcf517240f652d3af9a Mon Sep 17 00:00:00 2001 From: Himabindu T Date: Fri, 3 May 2024 09:01:44 +0530 Subject: [PATCH] BAH-3050 | Add. Provider Based OT View And Date Picker * BAH-3050 | add provider based OT view and date picker (#591) * BAH-3050 | add provider based OT view and date picker * BAH-3050 | refactored provider toggle without config * BAH-3050 | removed unwanted span * BAH-3050 | fix test failures --------- Co-authored-by: Umair Fayaz * [Rahul] | BAH-3050 | Add. Unit Test For ProviderView --------- Co-authored-by: kavitha-sundararajan <90255023+kavitha-sundararajan@users.noreply.github.com> Co-authored-by: Umair Fayaz Co-authored-by: Rahul Ramesh --- .../ot/controller/calendarViewController.js | 19 +++ ui/app/ot/controller/otCalendarController.js | 29 ++++- ui/app/ot/views/home.html | 36 +++--- ui/app/ot/views/otCalendar.html | 9 +- ui/app/styles/ot/_ot.scss | 121 ++++++++++++++++-- ui/app/styles/ot/_otCalendar.scss | 1 + .../controller/otCalendarController.spec.js | 63 ++++++++- 7 files changed, 238 insertions(+), 40 deletions(-) diff --git a/ui/app/ot/controller/calendarViewController.js b/ui/app/ot/controller/calendarViewController.js index 92d7ff0e32..0dea6577da 100644 --- a/ui/app/ot/controller/calendarViewController.js +++ b/ui/app/ot/controller/calendarViewController.js @@ -70,6 +70,7 @@ angular.module('bahmni.ot') return newVar; }); $scope.filters.statusList = []; + $rootScope.providerToggle = appService.getAppDescriptor().getConfigValue("defaultViewAsSurgeonBased"); setAppointmentStatusList($scope.view); return locationService.getAllByTag('Operation Theater').then(function (response) { $scope.locations = response.data.results; @@ -101,6 +102,11 @@ angular.module('bahmni.ot') $state.view = $scope.view; }; + $scope.providerView = function (providerToggle) { + $rootScope.providerToggle = providerToggle; + $rootScope.$broadcast("event:providerView", providerToggle); + }; + var getBackGroundHSLColorFor = function (otCalendarColorAttribute) { var hue = otCalendarColorAttribute ? otCalendarColorAttribute.value.toString() : "0"; return "hsl(" + hue + ", 100%, 90%)"; @@ -185,6 +191,12 @@ angular.module('bahmni.ot') $scope.viewDate = Bahmni.Common.Util.DateUtil.addDays(date, 1); $state.viewDate = $scope.viewDate; }; + + $scope.goToSelectedDate = function (date) { + $scope.viewDate = date; + $state.viewDate = $scope.viewDate; + }; + $scope.goToCurrentWeek = function () { $scope.weekStartDate = Bahmni.Common.Util.DateUtil.getWeekStartDate(currentDate, $scope.startOfWeekCode); $state.weekStartDate = $scope.weekStartDate; @@ -211,6 +223,13 @@ angular.module('bahmni.ot') $state.weekEndDate = $scope.weekEndDate; }; + $scope.goToSelectedWeek = function (date) { + $scope.weekStartDate = date; + $scope.weekEndDate = Bahmni.Common.Util.DateUtil.addDays($scope.weekStartDate, 7); + $state.weekStartDate = $scope.weekStartDate; + $state.weekEndDate = $scope.weekEndDate; + }; + $scope.$on("event:surgicalAppointmentSelect", function (event, surgicalAppointment, surgicalBlock) { $scope.cancelDisabled = !(surgicalAppointment.status === Bahmni.OT.Constants.scheduled); $scope.moveButtonDisabled = !(surgicalAppointment.status === Bahmni.OT.Constants.scheduled); diff --git a/ui/app/ot/controller/otCalendarController.js b/ui/app/ot/controller/otCalendarController.js index 84076d4658..d4771d4b49 100644 --- a/ui/app/ot/controller/otCalendarController.js +++ b/ui/app/ot/controller/otCalendarController.js @@ -1,8 +1,8 @@ 'use strict'; angular.module('bahmni.ot') - .controller('otCalendarController', ['$scope', '$q', '$interval', 'spinner', 'locationService', 'surgicalAppointmentService', '$timeout', - function ($scope, $q, $interval, spinner, locationService, surgicalAppointmentService, $timeout) { + .controller('otCalendarController', ['$scope', '$rootScope', '$q', '$interval', 'spinner', 'locationService', 'surgicalAppointmentService', '$timeout', 'appService', 'surgicalAppointmentHelper', + function ($scope, $rootScope, $q, $interval, spinner, locationService, surgicalAppointmentService, $timeout, appService, surgicalAppointmentHelper) { var updateCurrentDayTimeline = function () { $scope.currentTimeLineHeight = heightPerMin * Bahmni.Common.Util.DateUtil.diffInMinutes($scope.calendarStartDatetime, new Date()); }; @@ -27,20 +27,41 @@ angular.module('bahmni.ot') updateBlocksStartDatetimeAndBlocksEndDatetime(); $scope.rows = $scope.getRowsForCalendar(); return $q.all([locationService.getAllByTag('Operation Theater'), - surgicalAppointmentService.getSurgicalBlocksInDateRange($scope.blocksStartDatetime, $scope.blocksEndDatetime, false, true)]).then(function (response) { + surgicalAppointmentService.getSurgicalBlocksInDateRange($scope.blocksStartDatetime, $scope.blocksEndDatetime, false, true), + surgicalAppointmentService.getSurgeons()]).then(function (response) { $scope.locations = response[0].data.results; $scope.weekDates = $scope.getAllWeekDates(); - $scope.surgicalBlocksByLocation = _.map($scope.locations, function (location) { + var surgicalBlocksByLocation = _.map($scope.locations, function (location) { return _.filter(response[1].data.results, function (surgicalBlock) { return surgicalBlock.location.uuid === location.uuid; }); }); + var providerNames = appService.getAppDescriptor().getConfigValue("primarySurgeonsForOT"); + $scope.surgeons = surgicalAppointmentHelper.filterProvidersByName(providerNames, response[2].data.results); + var surgicalBlocksBySurgeons = _.map($scope.surgeons, function (surgeon) { + return _.filter(response[1].data.results, function (surgicalBlock) { + return surgicalBlock.provider.uuid === surgeon.uuid; + }); + }); $scope.surgicalBlocksByDate = _.map($scope.weekDates, function (weekDate) { return _.filter(response[1].data.results, function (surgicalBlock) { return $scope.isSurgicalBlockActiveOnGivenDate(surgicalBlock, weekDate); }); }); $scope.blockedOtsOfTheWeek = getBlockedOtsOfTheWeek(); + + var setOTView = function (providerToggle) { + $scope.providerToggle = providerToggle; + if (providerToggle) { + $scope.surgicalBlocks = surgicalBlocksBySurgeons; + } else { + $scope.surgicalBlocks = surgicalBlocksByLocation; + } + }; + setOTView($rootScope.providerToggle); + $scope.$on("event:providerView", function (event, providerToggle) { + setOTView(providerToggle); + }); }); }; diff --git a/ui/app/ot/views/home.html b/ui/app/ot/views/home.html index 04cb3477d4..50f1b0cac0 100644 --- a/ui/app/ot/views/home.html +++ b/ui/app/ot/views/home.html @@ -60,41 +60,41 @@

{{'OT_APPOINTMENT_STATUS' | translate}}

aria-hidden="true"> {{::'OT_FILTER_KEY' |translate}}

-

- - - -

-

- - - -

- {{viewDate | date : 'dd MMM yyyy, EEE'}} + + +

- {{weekStartDate | date : 'dd MMM yyyy, EEE'}} to {{weekEndDate | date : 'dd MMM yyyy, EEE'}} + + + + + +

-

+ + - + - +

+ + - - + - +

diff --git a/ui/app/ot/views/otCalendar.html b/ui/app/ot/views/otCalendar.html index fc68b694bc..4651a0f369 100644 --- a/ui/app/ot/views/otCalendar.html +++ b/ui/app/ot/views/otCalendar.html @@ -1,9 +1,12 @@ -
+
-

+

{{location.name}}

+

+ {{surgeon.person.display}} +

@@ -14,7 +17,7 @@
-
+
diff --git a/ui/app/styles/ot/_ot.scss b/ui/app/styles/ot/_ot.scss index ef97eed751..3d9deefc52 100644 --- a/ui/app/styles/ot/_ot.scss +++ b/ui/app/styles/ot/_ot.scss @@ -214,19 +214,119 @@ div[ng-app="ot"] { } } .calendar-current-day { - margin: auto; - position: absolute; - left: 0; - right: 0; - top: 0; - width: 250px; + width: 60%; text-align: center; - bottom: 0; - height: 20px; font-weight: 600; + span { + position: relative; + } + button { + background: #fff; + border: 1px solid #95989a; + outline: none; + padding: 5px 10px; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); + display: inline-block; + color: #000; + } + } + .calendar-week-label { + cursor: pointer; + position: absolute; + background: #fff; + left: 16px; + padding: 5px; + text-align: center; + padding-top: 8px; + margin-top: 2px; + height: 7px; + } + .calendar-day-input { + background: #fff; + border: 1px solid #95989a; + outline: none; + width: 155px; + font-size: 14px; + padding: 5px; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); + display: inline-block; + color: #000; + margin-left: 10px; + margin-right: 10px; } .calendar-btn-container, .day-btn-container { - label { + .switch-input { + display: none; + } + + .switch-label { + color: #000; + position: relative; + display: inline; + min-width: 112px; + width: 100%; + box-sizing: border-box; + cursor: pointer; + font-weight: 500; + text-align: left; + padding: 10px 44px 10px 0; + &:before, &:after { + content: ""; + position: absolute; + margin: 0; + outline: 0; + top: 50%; + -ms-transform: translate(0, -50%); + -webkit-transform: translate(0, -50%); + transform: translate(0, -50%); + -webkit-transition: all 0.3s ease; + transition: all 0.3s ease; + } + &:before { + right: 2px; + width: 34px; + height: 14px; + background-color: #9E9E9E; + border-radius: 8px; + } + &:after { + right: 17px; + width: 20px; + height: 20px; + background-color: #FAFAFA; + border-radius: 50%; + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.14), 0 2px 2px 0 rgba(0, 0, 0, 0.098), 0 1px 5px 0 rgba(0, 0, 0, 0.084); + } + .toggle--on { + display: none; + } + .toggle--off { + display: inline-block; + } + } + + .switch-input:checked + .switch-label { + &:before { + background-color: #A5D6A7; + } + &:after { + background-color: #4CAF50; + -ms-transform: translate(80%, -50%); + -webkit-transform: translate(80%, -50%); + transform: translate(80%, -50%); + } + .toggle--on { + display: inline-block; + } + .toggle--off { + display: none; + } + } + .calendar-btn-label { -webkit-box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.3); padding: 6px 10px; @@ -241,7 +341,7 @@ div[ng-app="ot"] { opacity: 1; } } - input:checked + label { + input:checked + .calendar-btn-label { background: #d6d6d6; } input[value = "List View"]:checked + label { @@ -259,6 +359,7 @@ div[ng-app="ot"] { } .day-btn-container { float: left; + margin-left: 10px; } } diff --git a/ui/app/styles/ot/_otCalendar.scss b/ui/app/styles/ot/_otCalendar.scss index bc7f096f7f..7014f21f5e 100644 --- a/ui/app/styles/ot/_otCalendar.scss +++ b/ui/app/styles/ot/_otCalendar.scss @@ -75,6 +75,7 @@ position: relative; padding-bottom: 20px; overflow: hidden; + border-right: 0.5px solid lightgrey; .surgical-block { width: calc(100% - 10px); position: absolute; diff --git a/ui/test/unit/ot/controller/otCalendarController.spec.js b/ui/test/unit/ot/controller/otCalendarController.spec.js index 5b59f6e98b..6ebe806d50 100644 --- a/ui/test/unit/ot/controller/otCalendarController.spec.js +++ b/ui/test/unit/ot/controller/otCalendarController.spec.js @@ -4,8 +4,14 @@ describe("otCalendarController", function () { var scope, controller, q, spinner, state; var locationService = jasmine.createSpyObj('locationService', ['getAllByTag']); spinner = jasmine.createSpyObj('spinner', ['forPromise', 'then', 'catch']); - var surgicalAppointmentService = jasmine.createSpyObj('surgicalAppointmentService', ['getSurgicalBlocksInDateRange']); + var surgicalAppointmentService = jasmine.createSpyObj('surgicalAppointmentService', ['getSurgicalBlocksInDateRange', 'getSurgeons']); var ngDialog = jasmine.createSpyObj('ngDialog', ['open']); + var appService = jasmine.createSpyObj('appService', ['getAppDescriptor']); + var appDescriptor = jasmine.createSpyObj('appDescriptor', ['getConfigValue']); + appDescriptor.getConfigValue.and.returnValue({primarySurgeonsForOT: ["Doctor Strange", "Doctor Malhotra"]}); + appService.getAppDescriptor.and.returnValue(appDescriptor); + var surgicalAppointmentHelper = jasmine.createSpyObj('surgicalAppointmentHelper', ['filterProvidersByName']); + surgicalAppointmentHelper.filterProvidersByName.and.returnValue([{uuid: "providerUuid1", display: "Doctor Strange"},{uuid: "providerUuid2", display: "Doctor Malhotra"}]); var surgicalBlocks = [ { @@ -48,6 +54,21 @@ describe("otCalendarController", function () { } ]; + var surgeons = [ + { + id: 1, + person: {uuid: "personUuid1", display: "Doctor Strange"}, + attributes: [], + uuid: "providerUuid1" + }, + { + id: 2, + person: {uuid: "personUuid2", display: "Doctor Malhotra"}, + attributes: [], + uuid: "providerUuid2" + } + ]; + locationService.getAllByTag.and.callFake(function () { return {data: {results: [{uuid: "uuid1", name: "location1"}, {uuid: "uuid2", name: "location2"}]}}; }); @@ -73,7 +94,9 @@ describe("otCalendarController", function () { locationService: locationService, $q: q, spinner: spinner, - surgicalAppointmentService: surgicalAppointmentService + surgicalAppointmentService: surgicalAppointmentService, + appService: appService, + surgicalAppointmentHelper: surgicalAppointmentHelper }); scope.$apply(); @@ -84,6 +107,9 @@ describe("otCalendarController", function () { surgicalAppointmentService.getSurgicalBlocksInDateRange.and.callFake(function () { return {data: {results: surgicalBlocks}}; }); + surgicalAppointmentService.getSurgeons.and.callFake(function () { + return {data: {results: surgeons}}; + }); createController(); var intervals = scope.intervals(); @@ -94,6 +120,9 @@ describe("otCalendarController", function () { surgicalAppointmentService.getSurgicalBlocksInDateRange.and.callFake(function () { return {data: {results: surgicalBlocks}}; }); + surgicalAppointmentService.getSurgeons.and.callFake(function () { + return {data: {results: surgeons}}; + }); createController(); var rows = scope.getRowsForCalendar(); @@ -109,6 +138,9 @@ describe("otCalendarController", function () { surgicalAppointmentService.getSurgicalBlocksInDateRange.and.callFake(function () { return {data: {results: surgicalBlocks}}; }); + surgicalAppointmentService.getSurgeons.and.callFake(function () { + return {data: {results: surgeons}}; + }); createController(); expect(locationService.getAllByTag).toHaveBeenCalledWith('Operation Theater'); @@ -121,12 +153,33 @@ describe("otCalendarController", function () { surgicalAppointmentService.getSurgicalBlocksInDateRange.and.callFake(function () { return {data: {results: surgicalBlocks}}; }); + surgicalAppointmentService.getSurgeons.and.callFake(function () { + return {data: {results: surgeons}}; + }); + scope.weekOrDay = 'day'; + createController(); + expect(surgicalAppointmentService.getSurgicalBlocksInDateRange).toHaveBeenCalledWith(scope.viewDate, moment(scope.viewDate).endOf('day'), false, true); + expect(scope.surgicalBlocks.length).toEqual(2); + expect(scope.surgicalBlocks[0][0]).toEqual(surgicalBlocks[0]); + expect(scope.surgicalBlocks[1][0]).toEqual(surgicalBlocks[1]); + }); + + it('should group the surgical blocks by the provider', function () { + surgicalAppointmentService.getSurgicalBlocksInDateRange.and.callFake(function () { + return {data: {results: surgicalBlocks}}; + }); + surgicalAppointmentService.getSurgeons.and.callFake(function () { + return {data: {results: surgeons}}; + }); scope.weekOrDay = 'day'; createController(); + scope.$broadcast("event:providerView", true); expect(surgicalAppointmentService.getSurgicalBlocksInDateRange).toHaveBeenCalledWith(scope.viewDate, moment(scope.viewDate).endOf('day'), false, true); - expect(scope.surgicalBlocksByLocation.length).toEqual(2); - expect(scope.surgicalBlocksByLocation[0][0]).toEqual(surgicalBlocks[0]); - expect(scope.surgicalBlocksByLocation[1][0]).toEqual(surgicalBlocks[1]); + expect(surgicalAppointmentService.getSurgeons).toHaveBeenCalled(); + expect(surgicalAppointmentHelper.filterProvidersByName).toHaveBeenCalled(); + expect(scope.surgicalBlocks.length).toEqual(2); + expect(scope.surgicalBlocks[0][0]).toEqual(surgicalBlocks[0]); + expect(scope.surgicalBlocks[1][0]).toEqual(surgicalBlocks[1]); }); it('should set the day view split as integer', function () {