diff --git a/packages/smart-forms-renderer/src/components/FormComponents/RepeatGroup/RepeatGroup.tsx b/packages/smart-forms-renderer/src/components/FormComponents/RepeatGroup/RepeatGroup.tsx index 8f9c6358..51e248c2 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/RepeatGroup/RepeatGroup.tsx +++ b/packages/smart-forms-renderer/src/components/FormComponents/RepeatGroup/RepeatGroup.tsx @@ -24,11 +24,11 @@ import type { } from '../../../interfaces/renderProps.interface'; import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; import useInitialiseRepeatGroups from '../../../hooks/useInitialiseRepeatGroups'; -import { nanoid } from 'nanoid'; import cloneDeep from 'lodash.clonedeep'; import { useQuestionnaireStore } from '../../../stores'; import useRepeatGroups from '../../../hooks/useRepeatGroups'; import RepeatGroupView from './RepeatGroupView'; +import { generateNewRepeatId } from '../../../utils/repeatId'; interface RepeatGroupProps extends PropsWithQrRepeatGroupChangeHandler, @@ -104,7 +104,7 @@ function RepeatGroup(props: RepeatGroupProps) { setRepeatGroups([ ...repeatGroups, { - nanoId: nanoid(), + nanoId: generateNewRepeatId(qItem.linkId), qrItem: null } ]); diff --git a/packages/smart-forms-renderer/src/components/FormComponents/RepeatItem/RepeatItem.tsx b/packages/smart-forms-renderer/src/components/FormComponents/RepeatItem/RepeatItem.tsx index 2ac434c6..d822ada8 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/RepeatItem/RepeatItem.tsx +++ b/packages/smart-forms-renderer/src/components/FormComponents/RepeatItem/RepeatItem.tsx @@ -22,7 +22,6 @@ import type { PropsWithShowMinimalViewAttribute } from '../../../interfaces/renderProps.interface'; import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { nanoid } from 'nanoid'; import { createEmptyQrItem } from '../../../utils/qrItem'; import { FullWidthFormComponentBox } from '../../Box.styles'; import AddItemButton from './AddItemButton'; @@ -33,6 +32,7 @@ import useInitialiseRepeatAnswers from '../../../hooks/useInitialiseRepeatAnswer import ItemFieldGrid from '../ItemParts/ItemFieldGrid'; import useReadOnly from '../../../hooks/useReadOnly'; import { useQuestionnaireStore } from '../../../stores'; +import { generateExistingRepeatId, generateNewRepeatId } from '../../../utils/repeatId'; interface RepeatItemProps extends PropsWithQrItemChangeHandler, @@ -56,7 +56,7 @@ function RepeatItem(props: RepeatItemProps) { const readOnly = useReadOnly(qItem, parentIsReadOnly); - const repeatAnswers = useInitialiseRepeatAnswers(qrItem); + const repeatAnswers = useInitialiseRepeatAnswers(qItem.linkId, qrItem); // Event Handlers function handleAnswerChange(newQrItem: QuestionnaireResponseItem, index: number) { @@ -81,7 +81,7 @@ function RepeatItem(props: RepeatItemProps) { } function handleAddItem() { - const updatedRepeatAnswers = [...repeatAnswers, { id: nanoid() }]; + const updatedRepeatAnswers = [...repeatAnswers, { id: generateNewRepeatId(qItem.linkId) }]; onQrItemChange({ ...createEmptyQrItem(qItem, undefined), @@ -100,7 +100,7 @@ function RepeatItem(props: RepeatItemProps) { return ( + ( diff --git a/packages/smart-forms-renderer/src/hooks/useInitialiseGroupTable.ts b/packages/smart-forms-renderer/src/hooks/useInitialiseGroupTable.ts index 05a61cc7..3936ecd6 100644 --- a/packages/smart-forms-renderer/src/hooks/useInitialiseGroupTable.ts +++ b/packages/smart-forms-renderer/src/hooks/useInitialiseGroupTable.ts @@ -16,21 +16,24 @@ */ import type { QuestionnaireResponseItem } from 'fhir/r4'; -import { nanoid } from 'nanoid'; import type { GroupTableRowModel } from '../interfaces/groupTable.interface'; +import { generateExistingRepeatId, generateNewRepeatId } from '../utils/repeatId'; -function useInitialiseGroupTable(qrItems: QuestionnaireResponseItem[]): GroupTableRowModel[] { +function useInitialiseGroupTable( + linkId: string, + qrItems: QuestionnaireResponseItem[] +): GroupTableRowModel[] { let initialGroupTableRows: GroupTableRowModel[] = [ { - nanoId: nanoid(), + nanoId: generateNewRepeatId(linkId), qrItem: null } ]; if (qrItems.length > 0) { - initialGroupTableRows = qrItems.map((qrItem) => { + initialGroupTableRows = qrItems.map((qrItem, index) => { return { - nanoId: nanoid(), + nanoId: generateExistingRepeatId(linkId, index), qrItem }; }); diff --git a/packages/smart-forms-renderer/src/hooks/useInitialiseRepeatAnswers.ts b/packages/smart-forms-renderer/src/hooks/useInitialiseRepeatAnswers.ts index 37cdcbdb..933a335d 100644 --- a/packages/smart-forms-renderer/src/hooks/useInitialiseRepeatAnswers.ts +++ b/packages/smart-forms-renderer/src/hooks/useInitialiseRepeatAnswers.ts @@ -16,26 +16,23 @@ */ import type { QuestionnaireResponseItem, QuestionnaireResponseItemAnswer } from 'fhir/r4'; -import { nanoid } from 'nanoid'; import { useMemo } from 'react'; +import { generateExistingRepeatId, generateNewRepeatId } from '../utils/repeatId'; function useInitialiseRepeatAnswers( + linkId: string, qrItem: QuestionnaireResponseItem | null ): (QuestionnaireResponseItemAnswer | null)[] { return useMemo(() => { - let initialRepeatAnswers: (QuestionnaireResponseItemAnswer | null)[] = [{ id: nanoid() }]; - - if (qrItem?.answer) { - initialRepeatAnswers = qrItem.answer.map((answer) => { - if (!answer.id) { - answer.id = nanoid(); - } - return answer; - }); + if (!qrItem?.answer) { + return [{ id: generateNewRepeatId(linkId) }]; } - return initialRepeatAnswers; - }, [qrItem]); + return qrItem.answer.map((answer, index) => ({ + ...answer, + id: answer.id ?? generateExistingRepeatId(linkId, index) + })); + }, [linkId, qrItem]); } export default useInitialiseRepeatAnswers; diff --git a/packages/smart-forms-renderer/src/hooks/useInitialiseRepeatGroups.ts b/packages/smart-forms-renderer/src/hooks/useInitialiseRepeatGroups.ts index 0aa3d457..dec11307 100644 --- a/packages/smart-forms-renderer/src/hooks/useInitialiseRepeatGroups.ts +++ b/packages/smart-forms-renderer/src/hooks/useInitialiseRepeatGroups.ts @@ -16,9 +16,9 @@ */ import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { nanoid } from 'nanoid'; import type { RepeatGroupSingle } from '../interfaces/repeatGroup.interface'; import { useMemo } from 'react'; +import { generateExistingRepeatId, generateNewRepeatId } from '../utils/repeatId'; function useInitialiseRepeatGroups( qItem: QuestionnaireItem, @@ -28,15 +28,15 @@ function useInitialiseRepeatGroups( () => { let initialRepeatGroupAnswers: RepeatGroupSingle[] = [ { - nanoId: nanoid(), + nanoId: generateNewRepeatId(qItem.linkId), qrItem: null } ]; if (qrItems.length > 0) { - initialRepeatGroupAnswers = qrItems.map((qrItem) => { + initialRepeatGroupAnswers = qrItems.map((qrItem, index) => { return { - nanoId: nanoid(), + nanoId: generateExistingRepeatId(qItem.linkId, index), qrItem }; }); diff --git a/packages/smart-forms-renderer/src/utils/manageForm.ts b/packages/smart-forms-renderer/src/utils/manageForm.ts index 52ee8b44..9a4d26b8 100644 --- a/packages/smart-forms-renderer/src/utils/manageForm.ts +++ b/packages/smart-forms-renderer/src/utils/manageForm.ts @@ -9,6 +9,7 @@ import { initialiseQuestionnaireResponse } from './initialise'; import { removeEmptyAnswers } from './removeEmptyAnswers'; import { readEncounter, readPatient, readUser } from '../api/smartClient'; import type Client from 'fhirclient/lib/Client'; +import cloneDeep from 'lodash.clonedeep'; /** * Build the form with an initial Questionnaire and an optional filled QuestionnaireResponse. @@ -95,7 +96,7 @@ export async function initialiseFhirClient(fhirClient: Client): Promise { * @author Sean Fong */ export function getResponse(): QuestionnaireResponse { - return questionnaireResponseStore.getState().updatableResponse; + return cloneDeep(questionnaireResponseStore.getState().updatableResponse); } /** diff --git a/packages/smart-forms-renderer/src/utils/repeatId.ts b/packages/smart-forms-renderer/src/utils/repeatId.ts new file mode 100644 index 00000000..ff9e7c4b --- /dev/null +++ b/packages/smart-forms-renderer/src/utils/repeatId.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { nanoid } from 'nanoid'; + +export function generateNewRepeatId(linkId: string): string { + return `${linkId}-${nanoid()}`; +} + +export function generateExistingRepeatId(linkId: string, index: number): string { + const paddedIndex = index.toString().padStart(6, '0'); + return `${linkId}-${paddedIndex}`; +}