-
Notifications
You must be signed in to change notification settings - Fork 294
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Arjun | A - 1205463333089465 | Edit complex forms in new display cont…
…rol (#741) * Sowmya | WIP - edit complex forms * add. half baked state of edit forms flow * add. bring form controls panel as popup * add. changes to save updated form * add. tweaks to handle edit and errors through modal * add. tests and refactor Edit Form * add. custom error notification for edit form * add. translations for error message * add. tests to fix coverage --------- Co-authored-by: sowmya198 <sowmya.ayilam.s@gmail.com>
- Loading branch information
Showing
17 changed files
with
1,106 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
micro-frontends/src/next-ui/Components/EditObservationForm/EditObservationForm.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import PropTypes from "prop-types"; | ||
import { getLocale } from "../i18n/utils"; | ||
import { getAllForms, getFormByFormName ,getFormDetail, getFormTranslations, setEditableObservations } from "./EditObservationFormUtils"; | ||
import { findByEncounterUuid } from '../../utils/FormDisplayControl/FormView'; | ||
import { Modal, Loading } from 'carbon-components-react'; | ||
import { FormattedMessage } from "react-intl"; | ||
import { I18nProvider } from '../i18n/I18nProvider'; | ||
import ErrorNotification from '../ErrorNotification/ErrorNotification'; | ||
|
||
import "./EditObservationForm.scss"; | ||
|
||
const EditObservationForm = (props) => { | ||
const saveButtonText = ( | ||
<FormattedMessage | ||
id={"SAVE"} | ||
defaultMessage={"SAVE"} | ||
/> | ||
); | ||
|
||
const { | ||
formName, | ||
closeEditObservationForm, | ||
isEditFormLoading, | ||
setEditFormLoading, | ||
patient, | ||
formData, | ||
encounterUuid, | ||
consultationMapper, | ||
handleEditSave, | ||
editErrorMessage | ||
} = props; | ||
|
||
const [loadedFormDetails, setLoadedFormDetails] = useState({}); | ||
const [loadedFormTranslations, setLoadedFormTranslations] = useState({}); | ||
const [updatedObservations, setUpdatedObservations] = useState(null); | ||
const [editError, setEditError] = useState(false); | ||
const [encounter, setEncounter] = useState(null); | ||
const nodeId = "form-renderer"; | ||
|
||
const handleSave = () => { | ||
const editedObservations = updatedObservations.getValue(); | ||
if(editedObservations.errors && editedObservations.errors.length > 0) { | ||
setEditError(true); | ||
return; | ||
} | ||
encounter.observations = editedObservations.observations; | ||
handleEditSave(encounter); | ||
}; | ||
|
||
useEffect(() => { | ||
const fetchFormDetails = async () => { | ||
if( formData.length > 0 && encounterUuid !== null) { | ||
const encounterTransaction = await findByEncounterUuid(encounterUuid); | ||
setEncounter(consultationMapper.map(encounterTransaction)); | ||
|
||
const formVersion = "1"; | ||
const allForms = await getAllForms(); | ||
const observationForm = getFormByFormName(allForms, formName, formVersion); | ||
const formUuid = observationForm.uuid; | ||
const locale = getLocale(); | ||
const validateForm = false; | ||
const collapse = false; | ||
|
||
if (!loadedFormDetails[formUuid]) { | ||
var formDetails = await getFormDetail(formUuid); | ||
const formDetailsAsString = formDetails.resources[0].value; | ||
formDetails = JSON.parse(formDetailsAsString); | ||
formDetails.version = formVersion; | ||
|
||
setLoadedFormDetails((prevDetails) => ({ ...prevDetails, [formUuid]: formDetails })); | ||
|
||
const formParams = { formName: formName, formVersion: formVersion, locale: locale, formUuid: formUuid }; | ||
const formTranslations = await getFormTranslations(formDetails.translationsUrl, formParams); | ||
setLoadedFormTranslations((prevTranslations) => ({ ...prevTranslations, [formUuid]: formTranslations })); | ||
|
||
var editableObservations = []; | ||
formData.forEach(function (observation) { | ||
setEditableObservations(observation, formName, formVersion, editableObservations); | ||
}); | ||
setEditFormLoading(false); | ||
setUpdatedObservations(window.renderWithControls(formDetails, editableObservations, nodeId, collapse, patient, validateForm, locale, formTranslations)); | ||
} | ||
} | ||
}; | ||
|
||
fetchFormDetails(); | ||
}, [formData, formName, loadedFormDetails, loadedFormTranslations, patient, encounterUuid]); | ||
|
||
return ( | ||
<> | ||
<I18nProvider> | ||
<Modal | ||
open | ||
passiveModal | ||
className="edit-observation-form-modal" | ||
onRequestClose={closeEditObservationForm} | ||
> | ||
{ | ||
isEditFormLoading ? (<Loading />) : | ||
<div> | ||
<div className='section-title-wrapper'> | ||
<h2 className="section-title">{formName}</h2> | ||
<button className='confirm' onClick={handleSave}>{saveButtonText}</button> | ||
</div> | ||
<section className="content-body"> | ||
<section className='section-body'> | ||
<div id={nodeId}></div> | ||
</section> | ||
</section> | ||
</div> | ||
} | ||
</Modal> | ||
{ editError && <ErrorNotification setEditError={setEditError} errorMessage={editErrorMessage}/> } | ||
</I18nProvider> | ||
</> | ||
); | ||
}; | ||
|
||
EditObservationForm.propTypes = { | ||
formName: PropTypes.string.isRequired, | ||
closeEditObservationForm: PropTypes.func.isRequired, | ||
isEditFormLoading: PropTypes.bool.isRequired, | ||
patient: PropTypes.object.isRequired, | ||
formData: PropTypes.object.isRequired, | ||
encounterUuid: PropTypes.string.isRequired, | ||
consultationMapper: PropTypes.object.isRequired, | ||
handleSave: PropTypes.func.isRequired, | ||
handleSaveError: PropTypes.func.isRequired | ||
}; | ||
|
||
export default EditObservationForm; |
68 changes: 68 additions & 0 deletions
68
micro-frontends/src/next-ui/Components/EditObservationForm/EditObservationForm.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
.edit-observation-form-modal { | ||
.bx--modal-container { | ||
background: #f0f0f0; | ||
border-radius: 5px; | ||
width: 80%; | ||
height: 84%; | ||
max-width: 1180px; | ||
} | ||
|
||
.content-body { | ||
border: 1px solid #669999; | ||
box-shadow: 0px 4px 4px 0px #0000004f; | ||
} | ||
|
||
.section-title-wrapper { | ||
background: #669999; | ||
padding-right: 10px; | ||
display: flex; | ||
justify-content: space-between; | ||
position: sticky; | ||
top: 0; | ||
z-index: 1; | ||
} | ||
|
||
.section-title { | ||
font-family: OpenSans, Arial, sans-serif; | ||
padding: 10px; | ||
margin-top: 0; | ||
margin-bottom: 0; | ||
color: #ffffff; | ||
font-size: 16px; | ||
clear: both; | ||
background: #669999; | ||
position: sticky; | ||
border-radius: 0; | ||
top: 0; | ||
} | ||
|
||
.confirm { | ||
border-radius: 3px; | ||
background: linear-gradient(to bottom, #A1D030, #88af28); | ||
background-color: #88af28; | ||
border: #88af28 1px solid; | ||
padding: 6px 20px 7px; | ||
display: inline-block; | ||
line-height: 1.2em; | ||
color: white; | ||
cursor: pointer; | ||
min-width: 0; | ||
max-width: 300px; | ||
text-decoration: none; | ||
max-width: 250px; | ||
min-width: 0; | ||
margin-right: 10px; | ||
margin-bottom: 6px; | ||
} | ||
|
||
.section-body { | ||
padding: 20px 10px; | ||
background-color: #ffffff; | ||
color: #525252; | ||
} | ||
} | ||
|
||
.bx--modal-content { | ||
padding-top: 0; | ||
} | ||
|
122 changes: 122 additions & 0 deletions
122
micro-frontends/src/next-ui/Components/EditObservationForm/EditObservationForm.spec.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import React from 'react'; | ||
import { render, screen, waitFor } from '@testing-library/react'; | ||
import EditObservationForm from './EditObservationForm'; | ||
|
||
describe('EditObservationForm', () => { | ||
const mockProps = { | ||
"isEditFormLoading": false, | ||
"formName": "Radiology Study Report", | ||
"patient": { | ||
"uuid": "3c05ad1e-573e-43c5-81d2-ac18bfe3efd2", | ||
"givenName": "new", | ||
"familyName": "patient", | ||
"name": "new patient", | ||
"age": 22, | ||
"ageText": "22 <span> years </span>", | ||
"gender": "F", | ||
"genderText": "<span>Female</span>", | ||
"address": {}, | ||
"birthdateEstimated": false, | ||
"birthtime": null, | ||
"identifier": "BAH203002", | ||
"birthdate": "2001-10-14T18:30:00.000Z", | ||
"image": "/openmrs/ws/rest/v1/patientImage?patientUuid=3c05ad1e-573e-43c5-81d2-ac18bfe3efd2", | ||
"registrationLocation": { | ||
"label": "Registration Location", | ||
"value": { | ||
"uuid": "0fbbeaf4-f3ea-11ed-a05b-0242ac123210", | ||
"display": "G Mobile Clinic", | ||
"links": [ | ||
{ | ||
"rel": "self", | ||
"uri": "http://localhost/openmrs/ws/rest/v1/location/0fbbeaf4-f3ea-11ed-a05b-0242ac123210", | ||
"resourceAlias": "location" | ||
} | ||
] | ||
}, | ||
"isDateField": false | ||
}, | ||
"confirmedPatient": { | ||
"label": "confirmedPatient", | ||
"value": true, | ||
"isDateField": false | ||
} | ||
}, | ||
"formData": { | ||
"encounterDateTime": 1697378779000, | ||
"visitStartDateTime": null, | ||
"targetObsRelation": null, | ||
"groupMembers": [], | ||
"providers": [ | ||
{ | ||
"uuid": "c1c26908-3f10-11e4-adec-0800271c1b75", | ||
"name": "Bailly RURANGIRWA", | ||
"encounterRoleUuid": "a0b03050-c99b-11e0-9572-0800200c9a66" | ||
} | ||
], | ||
"isAbnormal": null, | ||
"duration": null, | ||
"type": "Text", | ||
"encounterUuid": "847d26db-d1db-4176-b704-f906dee15fad", | ||
"obsGroupUuid": null, | ||
"creatorName": "Bailly RURANGIRWA", | ||
"conceptSortWeight": 1, | ||
"parentConceptUuid": null, | ||
"hiNormal": null, | ||
"lowNormal": null, | ||
"formNamespace": "Bahmni", | ||
"formFieldPath": "Radiology Study Report.1/15-0", | ||
"interpretation": null, | ||
"status": "FINAL", | ||
"encounterTypeName": null, | ||
"complexData": null, | ||
"abnormal": null, | ||
"unknown": false, | ||
"orderUuid": null, | ||
"observationDateTime": 1697378779000, | ||
"conceptNameToDisplay": "Study Site, Projections and Comment", | ||
"voided": false, | ||
"voidReason": null, | ||
"valueAsString": "Done", | ||
"concept": { | ||
"uuid": "38bdca1d-a351-4c64-84ae-e3390891f637", | ||
"name": "Study Site, Projections and Comment", | ||
"dataType": "Text", | ||
"shortName": "Study Site, Projections and Comment", | ||
"units": null, | ||
"conceptClass": "Misc", | ||
"hiNormal": null, | ||
"lowNormal": null, | ||
"set": false, | ||
"mappings": [] | ||
}, | ||
"uuid": "f030fecd-6b48-416e-a6f6-1192ae8c18cc", | ||
"conceptUuid": "38bdca1d-a351-4c64-84ae-e3390891f637", | ||
"comment": null, | ||
"value": "Done" | ||
}, | ||
"encounterUuid": "847d26db-d1db-4176-b704-f906dee15fad", | ||
"consultationMapper": {}, | ||
"handleEditSave": jest.fn(), | ||
"closeEditObservationForm": jest.fn(), | ||
"handleSave": jest.fn() | ||
}; | ||
|
||
it('should render the component', async () => { | ||
render(<EditObservationForm {...mockProps} />); | ||
await waitFor(() => { | ||
expect(screen.getByText('Radiology Study Report')).toBeTruthy(); | ||
}); | ||
}); | ||
|
||
it('should show Loading screen if form is loading', async () => { | ||
var updatedProps = mockProps; | ||
updatedProps.isEditFormLoading = true; | ||
|
||
render(<EditObservationForm {...updatedProps} />); | ||
await waitFor(() => { | ||
expect(screen.queryAllByText("Active loading indicator")).toHaveLength(2); | ||
}); | ||
}); | ||
|
||
}); |
Oops, something went wrong.