From f615d65da51acd08ae8458c8a29ca67bf203696a Mon Sep 17 00:00:00 2001 From: BharathKShetty Date: Thu, 13 Feb 2025 15:07:49 +0530 Subject: [PATCH] (fix) O3-4442: Duplicate Subquestion IDs in ObsGroup should trigger validation (#392) * prevent duplicate subquestion IDs in obsGroup using sibling-based check * check for duplicate in sub questions * check for duplicate in sub questions --------- Co-authored-by: Nethmi Rodrigo --- .../question/question.component.tsx | 4 +- .../modals/question/question.modal.tsx | 39 ++++++++++++------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/components/interactive-builder/modals/question/question-form/question/question.component.tsx b/src/components/interactive-builder/modals/question/question-form/question/question.component.tsx index 0115330b..46f161fe 100644 --- a/src/components/interactive-builder/modals/question/question-form/question/question.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/question/question.component.tsx @@ -27,7 +27,7 @@ const Question: React.FC = ({ checkIfQuestionIdExists }) => { setFormField({ ...formField, id: camelCasedLabel }); }; - const isQuestionIdValid = useCallback(() => { + const isQuestionIdDuplicate = useCallback(() => { return checkIfQuestionIdExists(formField.id); }, [formField.id, checkIfQuestionIdExists]); @@ -35,7 +35,7 @@ const Question: React.FC = ({ checkIfQuestionIdExists }) => { <> diff --git a/src/components/interactive-builder/modals/question/question.modal.tsx b/src/components/interactive-builder/modals/question/question.modal.tsx index b4365820..df788a46 100644 --- a/src/components/interactive-builder/modals/question/question.modal.tsx +++ b/src/components/interactive-builder/modals/question/question.modal.tsx @@ -41,23 +41,32 @@ const QuestionModalContent: React.FC = ({ const { t } = useTranslation(); const { formField, setFormField } = useFormField(); + const getAllQuestionIds = useCallback((questions?: FormField[]): string[] => { + if (!questions) return []; + return flattenDeep(questions.map((question) => [question.id, getAllQuestionIds(question.questions)])); + }, []); + const checkIfQuestionIdExists = useCallback( (idToTest: string): boolean => { - if (formFieldProp) return false; - const nestedIds = schema?.pages?.map((page) => { - return page?.sections?.map((section) => { - return section?.questions?.map((question) => { - question.questions?.map((nestedQuestion) => { - return nestedQuestion.id; - }); - return question.id; - }); - }); - }); - const questionIds: Array = flattenDeep(nestedIds); - return questionIds.includes(idToTest); + // Get all IDs from the schema + const schemaIds: string[] = + schema?.pages?.flatMap((page) => page?.sections?.flatMap((section) => getAllQuestionIds(section.questions))) || + []; + + // Get all IDs from the current formField's questions array + const formFieldIds: string[] = formField?.questions ? getAllQuestionIds(formField.questions) : []; + + // Combine both arrays, along with the parent question ID and count occurrences of the ID + const allIds = [...schemaIds, ...formFieldIds]; + if (!formFieldProp || formFieldProp.id !== formField.id) { + allIds.push(formField.id); + } + const occurrences = allIds.filter((id) => id === idToTest).length; + + // Return true if ID occurs more than once + return occurrences > 1; }, - [formFieldProp, schema], + [schema, getAllQuestionIds, formField, formFieldProp], ); const addObsGroupQuestion = useCallback(() => { @@ -180,7 +189,7 @@ const QuestionModalContent: React.FC = ({ disabled={ !formField || !formField.id || - checkIfQuestionIdExists(formField.id) || + (!formField.questions && checkIfQuestionIdExists(formField.id)) || !formField.questionOptions?.rendering } onClick={saveQuestion}