Skip to content

Commit 8ad9cd7

Browse files
committed
Fix handling repeating groups
1 parent 1abc594 commit 8ad9cd7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1519
-1070
lines changed

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* rendered questionnaire response item is node (one of the node stores implementing `INodeStore`)
44
* questionnaire item is template for node (`QuestionnaireItem` backing each store)
55
* nodes can have child nodes (`children` or `instances` on the store)
6-
* node can be either a display, a group, or a question (`DisplayStore`, `NonRepeatingGroupStore`/`RepeatingGroupStore`, `QuestionStore`)
6+
* node can be either a display, a group, or a question (`DisplayStore`, `NonRepeatingGroupStore`/`RepeatingGroupUmbrella`, `QuestionStore`)
77
* display node cannot have child nodes
88
* question node is answerable node
99
* display node and group node are not answerable nodes

demo/app.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ type ApplyQuestionnaireButtonProps = {
2222
onClick: () => void;
2323
};
2424

25-
function ApplyQuestionnaireButton({
26-
onClick,
27-
}: ApplyQuestionnaireButtonProps) {
25+
function ApplyQuestionnaireButton({ onClick }: ApplyQuestionnaireButtonProps) {
2826
return (
2927
<button
3028
type="button"
@@ -45,10 +43,9 @@ function DensePanel({
4543
minSize,
4644
minWidthClass,
4745
}: DensePanelProps) {
48-
const actionSlot =
49-
headerAction ?? (
50-
<span className="block h-6 w-6 flex-shrink-0" aria-hidden="true" />
51-
);
46+
const actionSlot = headerAction ?? (
47+
<span className="block h-6 w-6 flex-shrink-0" aria-hidden="true" />
48+
);
5249

5350
return (
5451
<Panel
@@ -188,9 +185,7 @@ export function App() {
188185
minWidthClass="min-w-[16rem]"
189186
headerAction={
190187
hasPendingChanges ? (
191-
<ApplyQuestionnaireButton
192-
onClick={handleApplyQuestionnaire}
193-
/>
188+
<ApplyQuestionnaireButton onClick={handleApplyQuestionnaire} />
194189
) : undefined
195190
}
196191
>

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export default tseslint.config(
2020
"react-refresh": reactRefresh,
2121
},
2222
rules: {
23+
// "@typescript-eslint/no-unnecessary-condition": "error",
2324
...reactHooks.configs.recommended.rules,
2425
"react-refresh/only-export-components": [
2526
"warn",

lib/__tests__/questionnaire-renderer.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import { describe, expect, it } from "vitest";
99

1010
describe("Renderer", () => {
11-
it("updates QuestionnaireResponse when a user answers a question", async () => {
11+
it("updates QuestionnaireResponse when a user answers a question", () => {
1212
// const questionnaire: Questionnaire = {
1313
// resourceType: "Questionnaire",
1414
// id: "test",

lib/components/common/answer-list.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { observer } from "mobx-react-lite";
44
import type {
55
AnswerType,
66
AnswerValueType,
7-
IQuestionStore,
7+
IQuestionNode,
88
} from "../../stores/types.ts";
99
import { Button } from "../controls/button.tsx";
1010
import { Answer, RowRenderProps } from "./answer.tsx";
1111

1212
export type AnswerListProps<T extends AnswerType> = {
13-
item: IQuestionStore<T>;
13+
item: IQuestionNode<T>;
1414
renderRow: (p: RowRenderProps<AnswerValueType<T>>) => ReactElement;
1515
};
1616

lib/components/common/answer.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type {
1212
AnswerType,
1313
AnswerValueType,
1414
IAnswerInstance,
15-
IQuestionStore,
15+
IQuestionNode,
1616
} from "../../stores/types.ts";
1717

1818
export type RowRenderProps<TValue> = {
@@ -26,7 +26,7 @@ export type RowRenderProps<TValue> = {
2626
};
2727

2828
export type AnswerProps<T extends AnswerType> = {
29-
item: IQuestionStore<T>;
29+
item: IQuestionNode<T>;
3030
renderRow: (p: RowRenderProps<AnswerValueType<T>>) => ReactElement;
3131
answer: IAnswerInstance<AnswerValueType<T>>;
3232
index: number;
@@ -66,9 +66,9 @@ export const Answer = observer(function Answer<T extends AnswerType>({
6666
</Button>
6767
</div>
6868
)}
69-
{!!answer.children?.length && (
69+
{!!answer.nodes?.length && (
7070
<div className="af-answer-children">
71-
<ItemsList items={answer.children} />
71+
<ItemsList items={answer.nodes} />
7272
</div>
7373
)}
7474
</div>

lib/components/common/item-errors.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
import "./item-errors.css";
22
import { observer } from "mobx-react-lite";
3-
import { INodeStore } from "../../stores/types.ts";
3+
import {
4+
IDisplayNode,
5+
INonRepeatingGroupNode,
6+
IQuestionNode,
7+
IRepeatingGroupNode,
8+
} from "../../stores/types.ts";
49
import { getItemErrorId } from "../../utils.ts";
510

611
interface ItemErrorsProps {
7-
item: INodeStore;
12+
item:
13+
| IQuestionNode
14+
| IRepeatingGroupNode
15+
| INonRepeatingGroupNode
16+
| IDisplayNode;
817
}
918

1019
export const ItemErrors = observer(function ItemErrors({

lib/components/common/item-header.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import "./item-header.css";
22
import { ItemText } from "./item-text.tsx";
3-
import { INodeStore } from "../../stores/types.ts";
3+
import { INode } from "../../stores/types.ts";
44
import { observer } from "mobx-react-lite";
55
import { getItemHelpId, getItemLabelId } from "../../utils.ts";
66

77
interface ItemHeaderProps {
8-
item: INodeStore;
8+
item: INode;
99
htmlFor?: string;
1010
className?: string;
1111
}

lib/components/common/item-list.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { observer } from "mobx-react-lite";
22
import { ItemNode } from "./item-node.tsx";
3-
import { INodeStore } from "../../stores/types.ts";
3+
import { ICoreNode } from "../../stores/types.ts";
44

55
export const ItemsList = observer(function ItemsList({
66
items,
77
}: {
8-
items: INodeStore[];
8+
items: ICoreNode[];
99
}) {
1010
return (
1111
<>
Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
import { observer } from "mobx-react-lite";
22
import { DisplayNode } from "../nodes/display-node.tsx";
3-
import { INodeStore } from "../../stores/types.ts";
3+
import { ICoreNode } from "../../stores/types.ts";
44
import { NonRepeatingGroupNode } from "../nodes/non-repeating-group-node.tsx";
5-
import { RepeatingGroupNode } from "../nodes/repeating-group-node.tsx";
5+
import { RepeatingGroupWrapper } from "../nodes/repeating-group-wrapper.tsx";
66
import { QuestionNode } from "../nodes/question-node.tsx";
7-
import {
8-
isDisplay,
9-
isNonRepeatingGroup,
10-
isRepeatingGroup,
11-
} from "../../utils.ts";
7+
import { isDisplayNode } from "../../stores/display-store.ts";
8+
import { isRepeatingGroupWrapper } from "../../stores/repeating-group-wrapper.ts";
9+
import { isNonRepeatingGroupNode } from "../../stores/non-repeating-group-store.ts";
10+
import { isQuestionNode } from "../../stores/question-store.ts";
1211

1312
export const ItemNode = observer(function ItemNode({
1413
item,
1514
}: {
16-
item: INodeStore;
15+
item: ICoreNode;
1716
}) {
18-
if (isDisplay(item)) return <DisplayNode item={item} />;
19-
if (isNonRepeatingGroup(item)) return <NonRepeatingGroupNode item={item} />;
20-
if (isRepeatingGroup(item)) return <RepeatingGroupNode item={item} />;
21-
22-
return <QuestionNode item={item} />;
17+
if (isQuestionNode(item)) return <QuestionNode item={item} />;
18+
if (isNonRepeatingGroupNode(item))
19+
return <NonRepeatingGroupNode item={item} />;
20+
if (isRepeatingGroupWrapper(item))
21+
return <RepeatingGroupWrapper item={item} />;
22+
if (isDisplayNode(item)) return <DisplayNode item={item} />;
23+
return null;
2324
});

0 commit comments

Comments
 (0)