-
Notifications
You must be signed in to change notification settings - Fork 72
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
(feat) O3-3712: add a concept answer to a concept in the form builder #351
base: main
Are you sure you want to change the base?
(feat) O3-3712: add a concept answer to a concept in the form builder #351
Conversation
Can you please add these changes to the |
Okay doing that |
Hello @NethmiRodrigo , I added the changes to edit-modal component as requested |
@Willie-theBeastMutua can you please update your fork and fix the changes, some of the code has gotten reverted, maybe due to a bad rebase |
d96574f
to
d761d9b
Compare
Hello ** @NethmiRodrigo** the code has been updated and fixed kindly check |
The merge you conducted reverted some of the changes in the main but i have fixed them i hope its now okay |
Hey @Willie-theBeastMutua thank you for the progress. One minor detail, I see that we can't remove the answers once added. Can you add support to remove an added answer, and also add a check that you can't add the same concept multiple times as an answer? |
@NethmiRodrigo support for deletion and checks for duplicate concept answers has been added kindly check |
@Willie-theBeastMutua could you add like a small |
@NethmiRodrigo the changes have been made and it saves successfully |
@NethmiRodrigo did you have a look |
Sorry I couldn't re-review it, will do asap. Thanks for pinging me. Meanwhile, can you resolve the conflicts and update your branch? |
@NethmiRodrigo branch has been updated |
@NethmiRodrigo can we restart the test as it times out and when i test the same test from my end it should work. Or advice on what is failing.... |
@Willie-theBeastMutua I re-ran the tests but it failed again due to a metadata issue (unrelated to your changes). |
@NethmiRodrigo to get you right.. i added the check for duplicates to only save one instance. You want the same check to be available in the UI? |
@Willie-theBeastMutua yep, exactly! |
@NethmiRodrigo the checks have been added. Kindly check |
Could you please update your branch @Willie-theBeastMutua? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Willie-theBeastMutua, some very minor suggestions
closeModal(); | ||
}; | ||
|
||
const createQuestion = () => { | ||
const createQuestion = useCallback(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for clarification purposes, any particular reason as to why we changed this to a useCallback?
useEffect(() => { | ||
if (isCreatingQuestion) { | ||
createQuestion(); | ||
setIsCreatingQuestion(false); | ||
} | ||
}, [isCreatingQuestion, createQuestion]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just call the handleCreateQuestion
function, instead of having a useEffect to do it? See - https://react.dev/learn/you-might-not-need-an-effect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use effect is used due to react's state management when combining the added answers and the selected answers. Saving without checking when the state is changed only saves the selected answers and not the update. I tried not using it but react's state management did not allow me. The call back is used to execute also the use effect. They are both part of the same solution
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I see. So instead of having a useEffect and useCallback we could change the handleSaveMoreAnswers
to return the answers list, like so:
const handleSaveMoreAnswers = () => {
const newAnswers = addedAnswers.filter(
(newAnswer) => !selectedAnswers.some((prevAnswer) => prevAnswer.id === newAnswer.id),
);
const updatedAnswers = [...selectedAnswers, ...newAnswers];
setSelectedAnswers(updatedAnswers);
setaddedAnswers([]);
return updatedAnswers;
};
And then in the handleCreateQuestion
, we pass in the list to the createQuestion
function, like so:
const handleCreateQuestion = () => {
const updatedAnswers = handleSaveMoreAnswers();
createQuestion(updatedAnswers);
closeModal();
};
And accept change the createQuestion
function to accept a parameter and then use that param for the object:
const createQuestion = (conceptAnswers) => {
try {
const questionIndex = schema.pages[pageIndex]?.sections?.[sectionIndex]?.questions?.length ?? 0;
const computedQuestionId = `question${questionIndex + 1}Section${sectionIndex + 1}Page-${pageIndex + 1}`;
const newQuestion = {
label: questionLabel,
......,
...(conceptAnswers.length && {
answers: conceptAnswers.map((answer) => ({
concept: answer.id,
label: answer.text,
})),
}),
};
}
};
This way we could avoid the useCallback with a massive dependency list
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me try that
Co-authored-by: Nethmi Rodrigo <[email protected]>
Okay let me do that |
@NethmiRodrigo I was able to remove the callback and useEffect according to your suggestion and it worked perfectly. Thank you so much |
@NethmiRodrigo the change has been made |
)} | ||
) : null} | ||
|
||
{(selectedConcept || questionToEdit) && questionToEdit?.questionOptions.answers?.length ? ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of the condition questionToEdit?.questionOptions.answers?.length
, if a user when creating a question doesn't select any answer, they wouldn't be able to add any answers when editing either, and that shouldn't be the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NethmiRodrigo sorry for replying late. This is what is used even in the add-question.modal. I have used it to ensure that the concept that was selected has a coded datatype. In the add-question modal if the API returns a concept without answers even if its datatype is coded then the select answers field will not be displayed.
That was my thinking based on what has been implemented. Unless you have another idea as to how we can implement it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the add-question-modal, this condition makes sense. In the edit version, if the user has not selected any answer during creation, they should still be able to add answers. What I meant was that we should just remove this condition and show the Add more answers
if the concept is of the datatype coded
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NethmiRodrigo how do we check if the datatype is coded? Because even in add question, the check is done to see if the concept has answers there is no check for the datatype
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in the add-question-modal
, the reason that there is no check for the datatype is because as soon as you search for a concept from the API and select a concept, if the concept has answers, it got added to a state, so the check for the datatype coded
wasn't necessary (hacky way to do it) -
openmrs-esm-form-builder/src/components/interactive-builder/add-question.modal.tsx
Lines 160 to 170 in 5154c46
const handleConceptSelect = (concept: Concept) => { | |
const updatedDatePickerType = getDatePickerType(concept); | |
if (updatedDatePickerType) setDatePickerType(updatedDatePickerType); | |
setConceptToLookup(''); | |
setSelectedConcept(concept); | |
setAnswers( | |
concept?.answers?.map((answer) => ({ | |
concept: answer?.uuid, | |
label: answer?.display, | |
})), | |
); |
@NethmiRodrigo I found a way to do it kindly check and advise |
@@ -875,7 +876,14 @@ const EditQuestionModal: React.FC<EditQuestionModalProps> = ({ | |||
</div> | |||
) : null} | |||
|
|||
{(selectedConcept || questionToEdit) && questionToEdit?.questionOptions.answers?.length ? ( | |||
{!hasConceptChanged && editConceptInfo?.datatype?.uuid == '8d4a48b6-c2cc-11de-8d13-0010c6dffd0f' ? ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have a hard-coded UUID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Willie-theBeastMutua please check my comment, just removing the conditional logic is sufficient, and we'll merge this in. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have a hard-coded UUID?
The UUID id for the coded datatype that is the check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Willie-theBeastMutua please check my comment, just removing the conditional logic is sufficient, and we'll merge this in. Thanks!
If I remove the logic, the more answers will display even when the concept is not of a coded datatype so I added a hook that collects data on the concept and I check for the UUID for the coded datatype. I can use the word "Coded" to check but my fear was what would happen if the language changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore my suggestion about simply removing the condition, I see why the hook is needed.
@ibacher if we do a datatype.display === "Coded", would that be language sensitive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Willie-theBeastMutua for now lets assume it wont change with the language
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NethmiRodrigo Yes, but if you used datatype.name
is shouldn't be, except in some edge-cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general display
is the (possibly) localized metadata, but name
is the "raw" value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NethmiRodrigo this is done
Requirements
Summary
Users are now be able to manually add specific concepts as answers to a concept of type Coded after searching of them (similar to how we add a backing concept)
Screenshots
Related Issue
https://openmrs.atlassian.net/browse/O3-3712
Other