From 6ae1fda64b9d56d877e88242ee70cfac1bd5a480 Mon Sep 17 00:00:00 2001 From: Jose Francisco <94977371+icrc-jofrancisco@users.noreply.github.com> Date: Mon, 2 Sep 2024 11:39:32 +0100 Subject: [PATCH] Feat: Add ability to disable and set default values for answers in specificQuestions (#84) (feat) Add ability to disable and set default values for answers in specificQuestions Co-authored-by: Jose Francisco --- .../SessionDetailsForm.tsx | 2 +- .../ConfigurableQuestionsSection.tsx | 4 ++ src/hooks/index.ts | 4 +- src/hooks/useForm.ts | 56 --------------- src/hooks/useSpecificQuestions.ts | 68 +++++++++++++++++++ src/types.ts | 4 ++ 6 files changed, 79 insertions(+), 59 deletions(-) delete mode 100644 src/hooks/useForm.ts create mode 100644 src/hooks/useSpecificQuestions.ts diff --git a/src/group-form-entry-workflow/SessionDetailsForm.tsx b/src/group-form-entry-workflow/SessionDetailsForm.tsx index 808ad86..82ca0ee 100644 --- a/src/group-form-entry-workflow/SessionDetailsForm.tsx +++ b/src/group-form-entry-workflow/SessionDetailsForm.tsx @@ -9,7 +9,7 @@ import { AttendanceTable } from './attendance-table'; import GroupFormWorkflowContext from '../context/GroupFormWorkflowContext'; import useGetPatients from '../hooks/useGetPatients'; import ConfigurableQuestionsSection from './configurable-questions/ConfigurableQuestionsSection'; -import useSpecificQuestions from '../hooks/useForm'; +import useSpecificQuestions from '../hooks/useSpecificQuestions'; interface ParamTypes { formUuid?: string; diff --git a/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx b/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx index 76f0b28..1daf748 100644 --- a/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +++ b/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx @@ -18,6 +18,8 @@ const ConfigurableQuestionsSection: React.FC {...register(specificQuestion.question.id, { required: false })} id={specificQuestion.question.id} labelText={specificQuestion.question.display} + readOnly={!!specificQuestion.question.disabled} + defaultValue={specificQuestion.question.defaultAnswer} > {specificQuestion.answers.map((answer) => ( @@ -30,6 +32,8 @@ const ConfigurableQuestionsSection: React.FC {...register(specificQuestion.question.id, { required: false })} type="text" labelText={specificQuestion.question.display} + readOnly={!!specificQuestion.question.disabled} + defaultValue={specificQuestion.question.defaultAnswer} /> )} diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 834fe03..7f68379 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -2,7 +2,7 @@ import useGetAllForms from './useGetAllForms'; import useGetPatient from './useGetPatient'; import useFormState from './useFormState'; import useGetEncounter from './useGetEncounter'; -import useForm from './useForm'; +import useSpecificQuestions from './useSpecificQuestions'; -export { useGetAllForms, useGetPatient, useFormState, useGetEncounter, useForm }; +export { useGetAllForms, useGetPatient, useFormState, useGetEncounter, useSpecificQuestions }; export * from './usePostEndpoint'; diff --git a/src/hooks/useForm.ts b/src/hooks/useForm.ts deleted file mode 100644 index 8709edd..0000000 --- a/src/hooks/useForm.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework'; -import useSWR from 'swr'; -import { type SpecificQuestion, type SpecificQuestionConfig } from '../types'; -import { useMemo } from 'react'; - -const formUrl = `${restBaseUrl}/o3/forms`; - -export const useSpecificQuestions = (formUuid: string, specificQuestionConfig: Array) => { - const specificQuestionsToLoad = useMemo( - () => getQuestionIdsByFormId(formUuid, specificQuestionConfig), - [formUuid, specificQuestionConfig], - ); - - const { data, error } = useSWR( - specificQuestionsToLoad ? `${formUrl}/${formUuid}` : null, - openmrsFetch, - ); - - const specificQuestions = getQuestionsByIds(specificQuestionsToLoad, data?.data); - - return { - questions: specificQuestions || null, - isError: error, - isLoading: !data && !error, - }; -}; - -function getQuestionIdsByFormId(formUuid: string, specificQuestionConfig: Array) { - const matchingQuestions = specificQuestionConfig.filter((question) => question.forms.includes(formUuid)); - return matchingQuestions.map((question) => question.questionId); -} - -function getQuestionsByIds(questionIds, formSchema): Array { - if (!formSchema || questionIds.lenght <= 0) { - return []; - } - const conceptLabels = formSchema.conceptReferences; - return formSchema.pages.flatMap((page) => - page.sections.flatMap((section) => - section.questions - .filter((question) => questionIds.includes(question.id)) - .map((question) => ({ - question: { - display: question.label ?? conceptLabels[question.questionOptions.concept]?.display, - id: question.id, - }, - answers: (question.questionOptions.answers ?? []).map((answer) => ({ - value: answer.concept, - display: answer.label ?? conceptLabels[answer.concept]?.display, - })), - })), - ), - ); -} - -export default useSpecificQuestions; diff --git a/src/hooks/useSpecificQuestions.ts b/src/hooks/useSpecificQuestions.ts new file mode 100644 index 0000000..7d71f80 --- /dev/null +++ b/src/hooks/useSpecificQuestions.ts @@ -0,0 +1,68 @@ +import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework'; +import useSWR from 'swr'; +import { type SpecificQuestion, type SpecificQuestionConfig } from '../types'; +import { useMemo } from 'react'; + +const formUrl = `${restBaseUrl}/o3/forms`; + +export const useSpecificQuestions = (formUuid: string, specificQuestionConfig: Array) => { + const specificQuestionsToLoad = useMemo( + () => getQuestionByFormId(formUuid, specificQuestionConfig), + [formUuid, specificQuestionConfig], + ); + + const { data, error } = useSWR( + specificQuestionsToLoad ? `${formUrl}/${formUuid}` : null, + openmrsFetch, + ); + + const specificQuestions = getQuestions(specificQuestionsToLoad, data?.data); + + return { + questions: specificQuestions || null, + isError: error, + isLoading: !data && !error, + }; +}; + +function getQuestionByFormId(formUuid: string, specificQuestionConfig: Array) { + return specificQuestionConfig.filter((question) => question.forms.includes(formUuid)); +} + +function getQuestions(specificQuestions: Array, formSchema): Array { + if (!formSchema || specificQuestions.length <= 0) { + return []; + } + + const specificQuestionsMap = new Map( + specificQuestions.map((sq) => [sq.questionId, sq]), + ); + + const questionIds = new Set(specificQuestionsMap.keys()); + const conceptLabels = formSchema.conceptReferences; + + return formSchema.pages.flatMap((page) => + page.sections.flatMap((section) => + section.questions + .filter((question) => questionIds.has(question.id)) + .map((question) => { + const specificQuestion = specificQuestionsMap.get(question.id) || {}; + + return { + question: { + display: question.label ?? conceptLabels[question.questionOptions.concept]?.display, + id: question.id, + disabled: (specificQuestion as SpecificQuestionConfig).disabled, + defaultAnswer: (specificQuestion as SpecificQuestionConfig).defaultAnswer, + }, + answers: (question.questionOptions.answers ?? []).map((answer) => ({ + value: answer.concept, + display: answer.label ?? conceptLabels[answer.concept]?.display, + })), + }; + }), + ), + ); +} + +export default useSpecificQuestions; diff --git a/src/types.ts b/src/types.ts index 1f0f08a..9213a90 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,6 +7,8 @@ export interface SpecificQuestion { question: { id: string; display: string; + defaultAnswer?: string; + disabled?: boolean; }; answers: Array<{ value: string; @@ -17,4 +19,6 @@ export interface SpecificQuestion { export interface SpecificQuestionConfig { forms: Array; questionId: string; + defaultAnswer?: string; + disabled?: boolean; }