Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bindu, Umair | BAH-3025, BAH-3054 | Enable Search by Patient Name or ID in the Ward Nurse Dashboard page #636

Merged
merged 13 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions ui/app/adt/controllers/wardListController.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ angular.module('bahmni.adt')
$.extend(options, {patientUuid: patientUuid, visitUuid: visitUuid || null});
$window.location = appService.getAppDescriptor().formatUrl(Bahmni.ADT.Constants.ipdDashboard, options, true);
};
$scope.searchText = '';
$scope.searchTextFilter = function (row) {
rahu1ramesh marked this conversation as resolved.
Show resolved Hide resolved
var searchText = $scope.searchText;
if (!searchText) {
return true;
}
searchText = searchText.toLowerCase();
const excludedKeys = ["hiddenAttributes", "$$hashKey", "Diagnosis"];
const attributes = Object.keys(row).filter(key => !excludedKeys.includes(key));

return attributes.some(function (attribute) {
const rowValue = row[attribute].toString();
return rowValue && rowValue.toLowerCase().includes(searchText);
});
};

var getTableDetails = function () {
var params = {
Expand Down
12 changes: 10 additions & 2 deletions ui/app/adt/models/wardDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Bahmni.ADT.WardDetails = {};

Bahmni.ADT.WardDetails.create = function (details, diagnosisStatus) {
var detailsMap = {};
var attributesToCopy = ["Bed", "Name", "Id", "Name", "Age", "District", "Village", "Admission By", "Admission Time", "Disposition By", "Disposition Time", "ADT Notes"];
var attributesToCopy = ["Bed", "Ward", "Id", "Name", "Age", "Gender", "District", "Village", "Admission By", "Admission Time", "Disposition By", "Disposition Time", "ADT Notes"];
var diagnosisProperties = ["Diagnosis", "Diagnosis Certainty", "Diagnosis Order", "Diagnosis Status", "Diagnosis Provider", "Diagnosis Datetime"];
var hiddenAttributesToCopy = ["Patient Uuid", "Visit Uuid"];

Expand All @@ -15,6 +15,14 @@ Bahmni.ADT.WardDetails.create = function (details, diagnosisStatus) {
return newObject;
};

var filterHeadingsFromResponse = function (newObject, oldObject, properties) {
var keys = Object.keys(oldObject);
var identicalItems = properties.filter(function (item) {
return keys.includes(item);
});
return copyProperties({}, oldObject, identicalItems);
};

var removeDuplicateRuledOutDiagnosis = function (rows) {
rows.forEach(function (row) {
var ruledOutDiagnoses = _.map(_.filter(row.Diagnosis, {'ruledOut': true}), 'Diagnosis');
Expand All @@ -26,7 +34,7 @@ Bahmni.ADT.WardDetails.create = function (details, diagnosisStatus) {
};

details.forEach(function (detail) {
detailsMap[detail.Id] = detailsMap[detail.Id] || copyProperties({}, detail, attributesToCopy);
detailsMap[detail.Id] = detailsMap[detail.Id] || filterHeadingsFromResponse({}, detail, attributesToCopy);
detailsMap[detail.Id].Diagnosis = detailsMap[detail.Id].Diagnosis || [];
if (detail.Diagnosis !== undefined) {
var diagnosis = copyProperties({}, detail, diagnosisProperties);
Expand Down
7 changes: 4 additions & 3 deletions ui/app/adt/views/wardList.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
<div class="ward-details-container">
<input type="text" ng-model="searchText" placeholder="{{'IPD_WARD_LIST_SEARCH_KEY'| translate }}"/>
<span ng-if="tableDetails.length == 0" class="no-data-info">
{{ 'EMPTY_WARD_MESSAGE'|translate }}
</span>
<table class="table ward-details-content" ng-if="tableDetails.length > 0">
<thead>
<tr>
<th ng-repeat="heading in tableHeadings" ng-if="heading != 'hiddenAttributes'" ng-class="{'bed-detail-column' : $index == 0}">{{heading}}</th>
<th ng-repeat="heading in tableHeadings" ng-if="heading != 'hiddenAttributes'" ng-class="{'bed-detail-column' : $index == 0}">{{heading | titleTranslate}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in tableDetails">
<tr ng-repeat="row in tableDetails | filter:searchTextFilter">
<td ng-repeat="heading in tableHeadings" ng-if="heading != 'hiddenAttributes'">
<span ng-if="heading != 'Diagnosis' && heading != 'Id'">{{row[heading]}}</span>
<a ng-if="heading =='Id'" ng-click="gotoPatientDashboard(row['hiddenAttributes'].patientUuid, row['hiddenAttributes'].visitUuid)">
Expand All @@ -27,4 +28,4 @@
</tr>
</tbody>
</table>
</div>
</div>
4 changes: 3 additions & 1 deletion ui/app/i18n/adt/locale_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,7 @@
"EMPTY_WARD_MESSAGE": "There are no patients in this ward.",
"BEDMANAGEMENT_DISPOSITION_ADMIT_PATIENT": "Admit Patient",
"BEDMANAGEMENT_DISPOSITION_DISCHARGE_PATIENT": "Discharge Patient",
"BEDMANAGEMENT_DISPOSITION_TRANSFER_PATIENT": "Transfer Patient"
"BEDMANAGEMENT_DISPOSITION_TRANSFER_PATIENT": "Transfer Patient",
"Id": "Identifier",
parvathy00 marked this conversation as resolved.
Show resolved Hide resolved
"IPD_WARD_LIST_SEARCH_KEY": "Search..."
}
12 changes: 11 additions & 1 deletion ui/app/styles/adt/_adt.scss
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,19 @@ div[ng-app="adt"] {
max-width: $max-page-width;
overflow-x: auto;

input {
rahu1ramesh marked this conversation as resolved.
Show resolved Hide resolved
float: left;
min-width: 300px;
margin: 10px 10px;
padding: 2px 10px;
&:focus {
outline: 2px solid #007fff;
}
border: 1px solid #DDD;
}

table {
font-size: 14px;

thead tr th {
border: 1px solid #bebebe;
color: $black;
Expand Down
64 changes: 48 additions & 16 deletions ui/test/unit/adt/controllers/wardListController.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,80 @@

describe('WardListController', function () {

var controller;
var rootScope;
var scope;
var queryService, appService, window;

var controller, rootScope, scope, queryService, appService, window;

beforeEach(function () {
module('bahmni.adt');

module(function ($provide) {
appService = jasmine.createSpyObj('appService', ['getAppDescriptor']);
appService.getAppDescriptor.and.returnValue(new Bahmni.Common.AppFramework.AppDescriptor());

$provide.value('appService', {});
queryService = jasmine.createSpyObj('queryService', ['getResponseFromQuery']);
queryService.getResponseFromQuery.and.returnValue(specUtil.createServicePromise('queryService'));
$provide.value('queryService', queryService);
$provide.value('$stateParams', {});
});
});

beforeEach(function () {
inject(function ($controller, $rootScope, $window) {
controller = $controller;
rootScope = $rootScope;
scope = $rootScope.$new();
window = $window;
});
});

it('Should go to patient dashboard', function () {
scope.ward = {ward: {name: 'ward1'}};

controller('WardListController', {
$scope: scope,
queryService: queryService,
appService: appService
});
});

describe('gotoPatientDashboard', function () {
it('should go to patient dashboard', function () {
scope.ward = {ward: {name: 'ward1'}};
controller('WardListController', {
$scope: scope,
queryService: queryService,
appService: appService
});
scope.gotoPatientDashboard('patient1', 'visit2');
expect(window.location.toString().indexOf("/context.html#/patient/patient1/visit/visit2/")).not.toEqual(-1);
});
});

describe('searchTextFilter', function () {
it('should return true when search text is empty', function () {
expect(scope.searchTextFilter({})).toBe(true);
});

it('should return true for row matching exact search text (case-insensitive)', function () {
scope.searchText = 'test';
expect(scope.searchTextFilter({ name: 'TEST' })).toBe(true);
expect(scope.searchTextFilter({ description: 'testValue' })).toBe(true);
});

it('should return true for row containing search text (case-insensitive)', function () {
scope.searchText = 'Value';
expect(scope.searchTextFilter({ name: 'Any Value' })).toBe(true);
expect(scope.searchTextFilter({ details: 'This has some Value' })).toBe(true);
});

it('should return false for row with no matching text', function () {
scope.searchText = 'other';
expect(scope.searchTextFilter({ name: 'Test Name' })).toBe(false);
expect(scope.searchTextFilter({ details: 'No Match Here' })).toBe(false);
});

scope.gotoPatientDashboard('patient1', 'visit2');
it('should exclude specified keys from search', function () {
scope.searchText = 'hidden';
expect(scope.searchTextFilter({ hiddenAttributes: 'hidden data' })).toBe(false);
expect(scope.searchTextFilter({ $$hashKey: 'hash' })).toBe(false);
});

expect(window.location.toString().indexOf("/context.html#/patient/patient1/visit/visit2/")).not.toEqual(-1);
it('should search on all non-excluded keys', function () {
scope.searchText = 'giardiasis';
expect(scope.searchTextFilter({ name: 'John Doe', primaryDiagnoses: 'Giardiasis', secondaryDiagnoses: 'Hay Fever' })).toBe(true);
});
});
});

});