Skip to content

Commit

Permalink
Fix validation for single/multiple choice/reference. Closes #392
Browse files Browse the repository at this point in the history
  • Loading branch information
ruscoder committed Dec 3, 2024
1 parent 866d9c1 commit ce28c0d
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 53 deletions.
4 changes: 4 additions & 0 deletions src/components/BaseQuestionnaireResponseForm/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,13 @@ export function useFieldController(fieldName: any, questionItem: QuestionnaireIt
[repeats, field],
);

// This is a wrapper for react-select that always wrap single value into array
const onSelect = useCallback((option: any) => field.onChange([].concat(option)), [field]);

return {
...field,
onMultiChange,
onSelect,
fieldState,
disabled: readOnly || qrfContext.readOnly,
formItem,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function ReferenceRadioButtonUnsafe<R extends Resource = any, IR extends Resourc

const { optionsRD, fieldController } = useAnswerReference(props);

const { formItem, value, onChange, disabled } = fieldController;
const { formItem, value, onSelect, disabled } = fieldController;

return (
<RenderRemoteData
Expand All @@ -34,7 +34,7 @@ function ReferenceRadioButtonUnsafe<R extends Resource = any, IR extends Resourc
key={JSON.stringify(answerOption)}
checked={_.isEqual(value?.value, answerOption.value)}
disabled={disabled}
onChange={() => onChange(answerOption)}
onChange={() => onSelect(answerOption)}
data-testid={`inline-choice__${_.kebabCase(
JSON.stringify(getDisplay(answerOption.value)),
)}`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ export function QuestionChoice({ parentPath, questionItem }: QuestionItemProps)
const { linkId, answerOption, repeats, answerValueSet, choiceColumn } = questionItem;
const fieldName = [...parentPath, linkId];

const { value, formItem, onChange, placeholder = t`Select...` } = useFieldController(fieldName, questionItem);

const onSelect = useCallback((option: any) => onChange([].concat(option)), [onChange]);
const { value, formItem, onSelect, placeholder = t`Select...` } = useFieldController(fieldName, questionItem);

if (answerValueSet) {
return (
Expand Down
44 changes: 9 additions & 35 deletions src/components/BaseQuestionnaireResponseForm/widgets/reference.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,9 @@ export function useAnswerReference<R extends Resource = any, IR extends Resource
context,
overrideGetDisplay,
}: AnswerReferenceProps<R, IR>) {
const { linkId, repeats, required, answerExpression, choiceColumn, text, entryFormat, referenceResource } =
questionItem;
const { linkId, repeats, answerExpression, choiceColumn, text, entryFormat, referenceResource } = questionItem;
const rootFieldPath = [...parentPath, linkId];
const fieldPath = [...rootFieldPath, ...(repeats ? [] : ['0'])];
const fieldPath = [...rootFieldPath];
const rootFieldName = rootFieldPath.join('.');

const fieldName = fieldPath.join('.');
Expand All @@ -115,9 +114,10 @@ export function useAnswerReference<R extends Resource = any, IR extends Resource
}, [choiceColumn, context, overrideGetDisplay]);

// TODO: add support for fhirpath and application/x-fhir-query
const expression = answerExpression!.expression!;
const [resourceType, searchParams] = useMemo(() => {
return parseFhirQueryExpression(answerExpression!.expression!, context);
}, [answerExpression?.expression!, context]);
return parseFhirQueryExpression(expression, context);
}, [expression, context]);

const loadOptions = useCallback(
async (searchText: string) => {
Expand Down Expand Up @@ -157,31 +157,6 @@ export function useAnswerReference<R extends Resource = any, IR extends Resource
return await loadOptions('');
}, [JSON.stringify(searchParams)]);

const onChange = (
_value: SingleValue<QuestionnaireItemAnswerOption> | MultiValue<QuestionnaireItemAnswerOption>,
action: ActionMeta<QuestionnaireItemAnswerOption>,
) => {
if (!repeats || action.action !== 'select-option') {
return;
}
};

const validate = required
? (inputValue: any) => {
if (repeats) {
if (!inputValue || !inputValue.length) {
return 'Choose at least one option';
}
} else {
if (!inputValue) {
return 'Required';
}
}

return undefined;
}
: undefined;

const depsUrl = `${resourceType}?${buildQueryParams(searchParams as any)}`;

const deps = [linkId, depsUrl];
Expand All @@ -190,8 +165,6 @@ export function useAnswerReference<R extends Resource = any, IR extends Resource
rootFieldName,
fieldName,
debouncedLoadOptions,
onChange,
validate,
loadOptions,
optionsRD,
searchParams,
Expand All @@ -208,15 +181,16 @@ function QuestionReferenceUnsafe<R extends Resource = any, IR extends Resource =
props: AnswerReferenceProps<R, IR>,
) {
const { debouncedLoadOptions, fieldController, repeats, placeholder, optionsRD } = useAnswerReference(props);
const { formItem } = fieldController;

const { formItem, onSelect } = fieldController;

return (
<RenderRemoteData remoteData={optionsRD}>
{(options) => (
<Form.Item {...formItem}>
<AsyncSelect
onChange={fieldController.onChange}
value={repeats ? fieldController.value : [fieldController.value]}
onChange={onSelect}
value={fieldController.value}
loadOptions={debouncedLoadOptions}
defaultOptions={options}
getOptionLabel={(option) => getAnswerDisplay(option.value)}
Expand Down
14 changes: 1 addition & 13 deletions src/utils/questionnaire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,8 @@ export function questionnaireItemsToValidationSchema(questionnaireItems: Questio
schema = yup.date();
if (item.required) schema = schema.required();
schema = createSchemaArrayOfValues(yup.object({ date: schema })).required();
} else if (item.type === 'reference') {
schema = yup.object({
resourceType: yup.string().required(),
display: yup.string().nullable(),
id: yup.string().required(),
});

if (item.required) {
schema = createSchemaArrayOfValues(yup.object({ Reference: schema })).required();
} else {
schema = yup.mixed().nullable();
}
} else {
schema = item.required ? yup.mixed().required() : yup.mixed().nullable();
schema = item.required ? yup.array().of(yup.mixed()).min(1).required() : yup.mixed().nullable();
}
if (item.enableWhen) {
item.enableWhen.forEach((itemEnableWhen) => {
Expand Down

0 comments on commit ce28c0d

Please sign in to comment.