Skip to content

Commit 07280c4

Browse files
committed
Update FormItems type to consider edge cases with missing answer items
1 parent 97aa634 commit 07280c4

File tree

6 files changed

+477
-40
lines changed

6 files changed

+477
-40
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
## 1.0.0-beta-7
1+
## 1.0.0-beta.8
2+
3+
- Update FormItems type to consider edge cases with missing answer items
4+
5+
## 1.0.0-beta.7
26

37
- Export additional utils
48

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "sdc-qrf",
33
"license": "MIT",
4-
"version": "1.0.0-beta.7",
4+
"version": "1.0.0-beta.8",
55
"scripts": {
66
"test": "vitest --watch=false",
77
"test:watch": "vitest --watch",

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ export * from './types';
22
export {
33
mapFormToResponse,
44
mapResponseToForm,
5-
findAnswersForQuestionsRecursive,
65
removeDisabledAnswers,
76
getEnabledQuestions,
87
calcInitialContext,
98
parseFhirQueryExpression,
109
getChecker,
10+
cleanFormAnswerItems,
1111
toAnswerValue,
1212
getAnswerValues,
1313
getAnswerValueType,

src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ export interface FormAnswerItems {
109109
items?: FormItems;
110110
}
111111

112-
export type FormItems = Record<string, FormGroupItems | FormAnswerItems[] | undefined>;
112+
// Form renderers might insert undefined for missing field values even into array
113+
export type FormItems = Record<string, FormGroupItems | (FormAnswerItems | undefined)[] | undefined>;
113114

114115
export interface QuestionnaireResponseFormData {
115116
formValues: FormItems;

src/utils.ts

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ function isGroup(question: QuestionnaireItem) {
193193

194194
function isFormGroupItems(
195195
question: QuestionnaireItem,
196-
answers: FormGroupItems | FormAnswerItems[],
196+
answers: FormGroupItems | (FormAnswerItems | undefined)[],
197197
): answers is FormGroupItems {
198198
return isGroup(question) && _.isPlainObject(answers);
199199
}
@@ -249,21 +249,19 @@ function mapFormToResponseRecursive(
249249
}, acc);
250250
}
251251

252-
const qrItemAnswers = answers
253-
.filter((answer) => !isAnswerValueEmpty(answer.value))
254-
.reduce((answersAcc, answer) => {
255-
const items = hasSubAnswerItems(answer.items)
256-
? mapFormToResponseRecursive(answer.items, question.item ?? [])
257-
: [];
252+
const qrItemAnswers = cleanFormAnswerItems(answers).reduce((answersAcc, answer) => {
253+
const items = hasSubAnswerItems(answer.items)
254+
? mapFormToResponseRecursive(answer.items, question.item ?? [])
255+
: [];
258256

259-
return [
260-
...answersAcc,
261-
{
262-
...toFHIRAnswerValue(answer.value!, 'value'),
263-
...(items.length ? { item: items } : {}),
264-
},
265-
];
266-
}, [] as QuestionnaireResponseItemAnswer[]);
257+
return [
258+
...answersAcc,
259+
{
260+
...toFHIRAnswerValue(answer.value!, 'value'),
261+
...(items.length ? { item: items } : {}),
262+
},
263+
];
264+
}, [] as QuestionnaireResponseItemAnswer[]);
267265

268266
if (!qrItemAnswers.length) {
269267
return acc;
@@ -386,7 +384,7 @@ export function mapResponseToForm(resource: QuestionnaireResponse, questionnaire
386384
return mapResponseToFormRecursive(resource.item ?? [], questionnaire.item ?? []);
387385
}
388386

389-
export function findAnswersForQuestionsRecursive(linkId: string, values?: FormItems): any | null {
387+
function findAnswersForQuestionsRecursive(linkId: string, values?: FormItems): any | null {
390388
if (values && _.has(values, linkId)) {
391389
return values[linkId];
392390
}
@@ -410,7 +408,7 @@ export function findAnswersForQuestionsRecursive(linkId: string, values?: FormIt
410408
return acc2;
411409
}
412410

413-
return findAnswersForQuestionsRecursive(linkId, v2.items);
411+
return findAnswersForQuestionsRecursive(linkId, v2?.items);
414412
},
415413
null,
416414
);
@@ -434,7 +432,7 @@ export function findAnswersForQuestionsRecursive(linkId: string, values?: FormIt
434432
);
435433
}
436434

437-
function findAnswersForQuestion(linkId: string, parentPath: string[], values: FormItems): Array<FormAnswerItems> {
435+
export function findAnswersForQuestion(linkId: string, parentPath: string[], values: FormItems): FormAnswerItems[] {
438436
const p = _.cloneDeep(parentPath);
439437

440438
// Go up
@@ -447,15 +445,15 @@ function findAnswersForQuestion(linkId: string, parentPath: string[], values: Fo
447445
const parentGroup = _.get(values, [...p, part]);
448446

449447
if (typeof parentGroup === 'object' && linkId in parentGroup) {
450-
return parentGroup[linkId];
448+
return cleanFormAnswerItems(parentGroup[linkId]);
451449
}
452450
}
453451
}
454452

455453
// Go down
456454
const answers = findAnswersForQuestionsRecursive(linkId, values);
457455

458-
return answers ? answers : [];
456+
return answers ? cleanFormAnswerItems(answers) : [];
459457
}
460458

461459
export function compareValue(firstAnswerValue: AnswerValue, secondAnswerValue: AnswerValue) {
@@ -696,21 +694,19 @@ function removeDisabledAnswersRecursive(args: RemoveDisabledAnswersRecursiveArgs
696694

697695
return {
698696
...acc,
699-
[linkId!]: answers
700-
.filter((answer) => !isAnswerValueEmpty(answer.value))
701-
.reduce((answersAcc, answer, index) => {
702-
const items = hasSubAnswerItems(answer.items)
703-
? removeDisabledAnswersRecursive({
704-
questionnaireItems: questionnaireItem.item ?? [],
705-
parentPath: [...args.parentPath, linkId!, index.toString(), 'items'],
706-
answersItems: answer.items,
707-
initialValues: { ...values, [linkId!]: [...answersAcc, { ...answer, items: [] }] },
708-
context: args.context,
709-
})
710-
: {};
711-
712-
return [...answersAcc, { ...answer, items }];
713-
}, [] as any),
697+
[linkId!]: cleanFormAnswerItems(answers).reduce((answersAcc, answer, index) => {
698+
const items = hasSubAnswerItems(answer.items)
699+
? removeDisabledAnswersRecursive({
700+
questionnaireItems: questionnaireItem.item ?? [],
701+
parentPath: [...args.parentPath, linkId!, index.toString(), 'items'],
702+
answersItems: answer.items,
703+
initialValues: { ...values, [linkId!]: [...answersAcc, { ...answer, items: [] }] },
704+
context: args.context,
705+
})
706+
: {};
707+
708+
return [...answersAcc, { ...answer, items }];
709+
}, [] as any),
714710
};
715711
}, {} as any);
716712
}
@@ -871,6 +867,10 @@ export function isAnswerValueEmpty(value: AnswerValue | undefined | null) {
871867
return isValueEmpty(value) || _.every(_.mapValues(value, isValueEmpty));
872868
}
873869

870+
export function cleanFormAnswerItems(answerItems: (FormAnswerItems | undefined)[]): FormAnswerItems[] {
871+
return answerItems.filter((answer) => !!answer).filter((answer) => !isAnswerValueEmpty(answer.value));
872+
}
873+
874874
export function isValueEmpty(value: any) {
875875
if (_.isNaN(value)) {
876876
console.warn(

0 commit comments

Comments
 (0)