Skip to content

Commit

Permalink
Render lab-tests dynamically (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
IAMOTZ authored and dkayiwa committed Aug 6, 2018
1 parent 170d61b commit ddeab0a
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 24 deletions.
22 changes: 20 additions & 2 deletions app/js/components/labOrderEntry/LabEntryForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import '../../../css/grid.scss';
import './styles.scss';

import fetchLabOrders from '../../actions/labOrders/fetchLabOrders';
import { fetchLabConcepts } from '../../actions/labOrders/labConceptsAction';

export class LabEntryForm extends PureComponent {
static propTypes = {
Expand Down Expand Up @@ -51,6 +52,7 @@ export class LabEntryForm extends PureComponent {
inpatientCareSetting: PropTypes.shape({
uuid: PropTypes.string,
}),
conceptsAsTests: PropTypes.array,
session: PropTypes.shape({
currentProvider: PropTypes.shape({
person: PropTypes.shape({
Expand All @@ -77,6 +79,7 @@ export class LabEntryForm extends PureComponent {
inpatientCareSetting: {
uuid: '',
},
conceptsAsTests: [],
session: {
currentProvider: {
person: {
Expand All @@ -97,6 +100,9 @@ export class LabEntryForm extends PureComponent {

componentDidMount() {
this.props.dispatch(fetchLabOrders(null, 5, this.props.patient.uuid));
if (this.state.categoryUUID) {
this.props.dispatch(fetchLabConcepts(`${this.state.categoryUUID}?v=full`));
}
}

componentWillReceiveProps(nextProps) {
Expand All @@ -110,7 +116,7 @@ export class LabEntryForm extends PureComponent {
});
}

componentDidUpdate(prevProps) {
componentDidUpdate(prevProps, prevState) {
const {
status: { added, error },
errorMessage,
Expand All @@ -123,6 +129,9 @@ export class LabEntryForm extends PureComponent {
if (error) {
errorToast(errorMessage);
}
if (this.state.categoryUUID !== prevState.categoryUUID) {
this.props.dispatch(fetchLabConcepts(`${this.state.categoryUUID}?v=full`));
}
}

handleTestSelection = (item, type) => {
Expand Down Expand Up @@ -153,6 +162,10 @@ export class LabEntryForm extends PureComponent {
}
}

handleUrgencyChange = (order) => {
this.props.dispatch(toggleDraftLabOrdersUgency(order));
}

discardTestsInDraft = (test, action) => {
const { dispatch } = this.props;
if (action === 'single') return dispatch(removeTestFromDraft(test));
Expand All @@ -170,6 +183,7 @@ export class LabEntryForm extends PureComponent {
handleTestSelection={this.handleTestSelection}
draftLabOrders={this.props.draftLabOrders}
selectedTests={this.props.selectedTests}
tests={this.props.conceptsAsTests}
/>
</div>
);
Expand Down Expand Up @@ -247,7 +261,7 @@ export class LabEntryForm extends PureComponent {
renderLabDraftOrder = () => (
<div className="draft-lab-wrapper">
<LabDraftOrder
toggleDraftLabOrdersUgency={order => this.props.dispatch(toggleDraftLabOrdersUgency(order))}
toggleDraftLabOrdersUgency={this.handleUrgencyChange}
handleDraftDiscard={this.discardTestsInDraft}
draftLabOrders={this.props.draftLabOrders}
panelTests={this.state.selectedPanelTestIds}
Expand Down Expand Up @@ -305,6 +319,9 @@ export const mapStateToProps = ({
selectedTests,
},
dateFormatReducer: { dateFormat },
labConceptsReducer: {
conceptsAsTests,
},
openmrs: { session },
fetchLabOrderReducer: { labOrders },
patientReducer: { patient },
Expand All @@ -316,6 +333,7 @@ export const mapStateToProps = ({
}) => ({
draftLabOrders,
dateFormat,
conceptsAsTests,
selectedLabPanels,
defaultTests,
selectedTests,
Expand Down
31 changes: 17 additions & 14 deletions app/js/components/labOrderEntry/LabTestFieldSet.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import React from 'react';
import PropTypes from 'prop-types';
import { testsData } from './labData';
import '../../../css/grid.scss';

const LabTestFieldSet = ({ selectedTests, handleTestSelection }) => {
const selectedTestIds = selectedTests.map(test => test.id);
const LabTestFieldSet = ({ selectedTests, handleTestSelection, tests }) => {
const selectedTestIds = selectedTests.map(test => test.uuid);
return (
<fieldset className="fieldset">
<legend>Tests</legend>
<div className="flex-row">
{testsData.map(item => (
<button
type="button"
id="category-test-button"
key={`${item.id}`}
className={`lab-tests-btn ${selectedTestIds.includes(item.id) ? 'active' : ''}`}
onClick={() => handleTestSelection(item, 'single')}>
{item.test}
</button>
))}
<div className="tests-box">
{
tests.map(test => (
<button
type="button"
id="category-test-button"
key={`${test.uuid}`}
className={`lab-tests-btn ${(selectedTestIds.includes(test.uuid)) ? 'active' : ''}`}
onClick={() => handleTestSelection(test, 'single')}
>
{test.display.toLowerCase()}
</button>
))
}
</div>
</fieldset>
);
Expand All @@ -27,6 +29,7 @@ const LabTestFieldSet = ({ selectedTests, handleTestSelection }) => {
LabTestFieldSet.propTypes = {
selectedTests: PropTypes.array.isRequired,
handleTestSelection: PropTypes.func.isRequired,
tests: PropTypes.array.isRequired,
};

export default LabTestFieldSet;
11 changes: 10 additions & 1 deletion app/js/components/labOrderEntry/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,19 @@
margin-bottom: 10px;
}

.lab-tests-btn{
.panel-box, .tests-box{
display: flex;
flex-wrap: wrap;
}

.lab-tests-btn {
width: 145px;
font-size: 13px;
font-weight: bold;
margin-right: 10px;
margin-bottom: 10px;
flex-basis: 31.7%;
text-transform: capitalize;
}

.draft-lab-wrapper{
Expand Down
1 change: 1 addition & 0 deletions app/js/reducers/initialState.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,6 @@ export default {
error: null,
loading: false,
concepts: [],
conceptsAsTests: [],
},
};
25 changes: 23 additions & 2 deletions app/js/reducers/labOrders/labConceptsReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,36 @@ import {
} from '../../actions/actionTypes';
import initialState from '../initialState';


const removeDuplicateTests = (tests) => {
const uniqueTestIds = Array.from(new Set(tests.map(test => test.uuid)));
const uniqueTests = [];
tests.forEach((test) => {
const testIndex = uniqueTestIds.indexOf(test.uuid);
if (testIndex !== -1) {
uniqueTests.push(test);
uniqueTestIds.splice(testIndex, 1);
}
});
return uniqueTests;
};

export default (state = initialState.labConcepts, action) => {
switch (action.type) {
case FETCH_LAB_CONCEPTS_SUCCESS:
case FETCH_LAB_CONCEPTS_SUCCESS: {
const concepts = [...action.payload.data.setMembers];
const panels = concepts.filter(concept => concept.set);
const panelTests = [].concat(...panels.map(panel => panel.setMembers));
const standAloneTests = concepts.filter(concept => !concept.set);
const allTests = [...standAloneTests, ...panelTests];
return {
...state,
concepts: [...action.payload.data.setMembers],
concepts,
conceptsAsTests: removeDuplicateTests(allTests),
loading: false,
error: null,
};
}
case FETCH_LAB_CONCEPTS_LOADING:
return {
...state,
Expand Down
9 changes: 9 additions & 0 deletions tests/components/labOrderEntry/LabEntryForm.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ props = {
patient: {
uuid: 'jfgfhfgf',
},
conceptsAsTests: [],
encounterType: {
uuid: 'fhhfgfh9998',
},
Expand Down Expand Up @@ -104,6 +105,7 @@ describe('Component: LabEntryForm', () => {
dateFormatReducer: { dateFormat: 'DD-MM-YYYY HH:mm' },
patientReducer: { patient: {} },
fetchLabOrderReducer: { labOrders: [] },
labConceptsReducer: { conceptsAsTests:[] },
openmrs: { session: {} },
encounterRoleReducer: { encounterRole: {} },
encounterReducer: { encounterType: {} },
Expand Down Expand Up @@ -175,6 +177,13 @@ describe('Component: LabEntryForm', () => {
expect(dispatch).toBeCalled();
});

it('should toggle the urgency state of a test', () => {
const instance = getComponent().instance();
const dispatch = jest.spyOn(props, 'dispatch');
instance.handleUrgencyChange();
expect(dispatch).toBeCalled();
})

it(`should change the default lab form's tests category by toggling component state`, () => {
const component = getComponent();
const instance = component.instance();
Expand Down
15 changes: 12 additions & 3 deletions tests/components/labOrderEntry/LabTestFieldSet.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ let mountedComponent;
props = {
handleTestSelection: jest.fn(),
selectedTests: [
{ id: 1, test: 'Hemoglobin' },
{ id: 2, test: 'Hematocrit' },
{ id: 3, test: 'blood' },
{ uuid: 'asampleduuid1-234', display: 'sampleA' },
{ uuid: 'defmpleduuid1-566', display: 'sampleB' },
],
tests: [
{ uuid: 'asampleduuid1-234', display: 'sampleA' },
{ uuid: 'defmpleduuid1-566', display: 'sampleB' },
{ uuid: '5sampleduuid2-788', display: 'sampleC' }
]
};

const getComponent = () => {
Expand Down Expand Up @@ -37,4 +41,9 @@ describe('Component: LabTestFieldSet', () => {
expect(handleTestSelection).toBeCalled();
expect(component).toMatchSnapshot();
});

it('should add a class of `active` to the selected test', () => {
const component = getComponent();
expect(component.find('.lab-tests-btn.active').length).toEqual(2); // 2 tests are in the selectedTests array
})
});
31 changes: 29 additions & 2 deletions tests/reducers/labOrderReducers/labConceptsReducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ import {
import initialState from '../../../app/js/reducers/initialState';
import labConceptsReducer from '../../../app/js/reducers/labOrders/labConceptsReducer';

const mockConcepts = [
{ uuid: '123Abc-456', name: 'Concept A', set: false },
{
name: 'Concept B',
set: true,
setMembers: [
{ uuid: '456Abc-123', name: 'Concept D', set: false },
{ uuid: '138Abc-466', name: 'Concept E', set: false },
{ uuid: '123Def-456', name: 'Concept F', set: false },
]
},
{ uuid: '321Abc-146', name: 'Concept C', set: false },
{ uuid: '456Abc-123', name: 'Concept D', set: false },
];

describe('Lab Concepts reducer', () => {
it('should return the initial state', () => {
const expectedState = labConceptsReducer(initialState.labConcepts, {});
Expand All @@ -15,12 +30,20 @@ describe('Lab Concepts reducer', () => {
it('should handle `FETCH_LAB_CONCEPTS_SUCCESS`', () => {
const mockAction = {
type: FETCH_LAB_CONCEPTS_SUCCESS,
payload: { data: { setMembers: [{ name: 'I am not a true concept' }] } }
payload: { data: { setMembers: mockConcepts } }
}
const expectedState = {
...initialState.labConcepts,
error: null,
loading: false,
concepts: [{ name: 'I am not a true concept' }],
concepts: mockConcepts,
conceptsAsTests: [
{ uuid: '123Abc-456', name: 'Concept A', set: false },
{ uuid: '321Abc-146', name: 'Concept C', set: false },
{ uuid: '456Abc-123', name: 'Concept D', set: false },
{ uuid: '138Abc-466', name: 'Concept E', set: false },
{ uuid: '123Def-456', name: 'Concept F', set: false },
],
};
const actualState = labConceptsReducer(initialState.labConcepts, mockAction);
expect(actualState).toEqual(expectedState);
Expand All @@ -29,9 +52,11 @@ describe('Lab Concepts reducer', () => {
it('should handle `FETCH_LAB_CONCEPTS_LOADING`', () => {
const mockAction = { type: FETCH_LAB_CONCEPTS_LOADING };
const expectedState = {
...initialState.labConcepts,
error: null,
loading: true,
concepts: [],
conceptsAsTests: [],
};
const actualState = labConceptsReducer(initialState.labConcepts, mockAction);
expect(actualState).toEqual(expectedState);
Expand All @@ -44,9 +69,11 @@ describe('Lab Concepts reducer', () => {
payload: error
};
const expectedState = {
...initialState.labConcepts,
error: error,
loading: false,
concepts: [],
conceptsAsTests: [],
};
const actualState = labConceptsReducer(initialState.labConcepts, mockAction);
expect(actualState).toEqual(expectedState);
Expand Down

0 comments on commit ddeab0a

Please sign in to comment.