Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auto-answer one at a time, not into the future #3764

Merged
merged 34 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
30139f2
questions are working
jessicamcinchak Oct 4, 2024
3911c82
add autoAnswerableOptions store method, checklists working too
jessicamcinchak Oct 5, 2024
63db51a
filters are working
jessicamcinchak Oct 6, 2024
fddef39
automate through no result flag if no matching flag
jessicamcinchak Oct 6, 2024
0078c28
handle granular automations
jessicamcinchak Oct 6, 2024
32da380
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 9, 2024
d8ff09c
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 11, 2024
0495d9e
update upcomingCardIds tests
jessicamcinchak Oct 11, 2024
a1339c1
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 11, 2024
ccac584
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 15, 2024
89ad20b
filters work across all flagsets
jessicamcinchak Oct 15, 2024
65cfd79
fix imports
jessicamcinchak Oct 15, 2024
37b2f74
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 17, 2024
c917afd
stub out filter tests
jessicamcinchak Oct 17, 2024
95c28af
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 21, 2024
19465b1
more tests
jessicamcinchak Oct 21, 2024
59bf5d9
automate question & checklist blanks
jessicamcinchak Oct 22, 2024
9cc07d2
adjust blanks to account for previously visited options
jessicamcinchak Oct 23, 2024
fadcf03
handle _nots
jessicamcinchak Oct 23, 2024
81bd7f0
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 24, 2024
9475e74
add forceSelection toggle to Questions & Checklists
jessicamcinchak Oct 24, 2024
a77cca5
separate store methods for auto-answering options v flags, blanks work
jessicamcinchak Oct 25, 2024
348b851
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 25, 2024
738ff99
tweak parent/child granularity matching
jessicamcinchak Oct 26, 2024
65d8375
lots of tests
jessicamcinchak Oct 28, 2024
7bba548
blanks and Calculate tests
jessicamcinchak Oct 28, 2024
9b522e6
tidy up
jessicamcinchak Oct 28, 2024
efe731d
planning constraints _nots test suite
jessicamcinchak Oct 28, 2024
570cb28
autoAnswerableOptions test todos
jessicamcinchak Oct 29, 2024
91c9dfd
test suite using SetValue and forceSelection prop
jessicamcinchak Oct 29, 2024
a60b5aa
final test suite
jessicamcinchak Oct 29, 2024
d9c94cf
fix: Apply `wasVisited` class to Filter node (#3869)
DafyddLlyr Oct 29, 2024
d699da6
Merge branch 'main' of github.com:theopensystemslab/planx-new into je…
jessicamcinchak Oct 29, 2024
d96476c
first round of PR feedback
jessicamcinchak Oct 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions editor.planx.uk/src/@planx/components/Calculate/logic.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { ComponentType as TYPES } from "@opensystemslab/planx-core/types";
import { clickContinue, visitedNodes } from "pages/FlowEditor/lib/__tests__/utils";
import { Store, useStore } from "pages/FlowEditor/lib/store";

const { getState, setState } = useStore;
const { upcomingCardIds, resetPreview, record } = getState();

// Helper method
const visitedNodes = () => Object.keys(getState().breadcrumbs);
const { upcomingCardIds, resetPreview, autoAnswerableOptions } = getState();

beforeEach(() => {
resetPreview();
Expand All @@ -17,13 +15,12 @@ test("When formatOutputForAutomations is true, Calculate writes an array and fut
expect(upcomingCardIds()).toEqual(["Calculate", "Question"]);

// Step forwards through the Calculate
record("Calculate", { data: { testGroup: ["2"] }, auto: true });
upcomingCardIds();

// The Question has been auto-answered
expect(visitedNodes()).toEqual(["Calculate", "Question"]);
clickContinue("Calculate", { data: { testGroup: ["2"] }, auto: true });

expect(upcomingCardIds()).toEqual(["Group2Notice"]);
// The Question can be auto-answered
expect(visitedNodes()).toEqual(["Calculate"]);
expect(upcomingCardIds()).toEqual(["Question"])
expect(autoAnswerableOptions("Question")).toEqual(["Group2Response"]);
});

test("When formatOutputForAutomations is false, Calculate writes a number and future questions are not auto-answered", () => {
Expand All @@ -32,13 +29,12 @@ test("When formatOutputForAutomations is false, Calculate writes a number and fu
expect(upcomingCardIds()).toEqual(["Calculate", "Question"]);

// Step forwards through the Calculate
record("Calculate", { data: { testGroup: 2 }, auto: true });
upcomingCardIds();
clickContinue("Calculate", { data: { testGroup: 2 }, auto: true });

// The Question has NOT been auto-answered
// The Question cannot be auto-answered
expect(visitedNodes()).toEqual(["Calculate"]);

expect(upcomingCardIds()).toEqual(["Question"]);
expect(autoAnswerableOptions("Question")).toBeUndefined();
});

const flowWithAutomation: Store.Flow = {
Expand Down
18 changes: 18 additions & 0 deletions editor.planx.uk/src/@planx/components/Checklist/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface ChecklistProps extends Checklist {
node?: {
data?: {
allRequired?: boolean;
forceSelection?: boolean;
categories?: Array<Category>;
description?: string;
fn?: string;
Expand Down Expand Up @@ -285,6 +286,7 @@ export const ChecklistComponent: React.FC<ChecklistProps> = (props) => {
const formik = useFormik<Checklist>({
initialValues: {
allRequired: props.node?.data?.allRequired || false,
forceSelection: props.node?.data?.forceSelection || false,
description: props.node?.data?.description || "",
fn: props.node?.data?.fn || "",
groupedOptions: props.groupedOptions,
Expand Down Expand Up @@ -422,6 +424,22 @@ export const ChecklistComponent: React.FC<ChecklistProps> = (props) => {
label="All required"
/>
</InputRow>
<InputRow>
<FormControlLabel
control={
<Switch
checked={formik.values.forceSelection}
onChange={() =>
formik.setFieldValue(
"forceSelection",
!formik.values.forceSelection,
)
}
/>
}
label="Always put to user (forgo automation)"
/>
</InputRow>
jessicamcinchak marked this conversation as resolved.
Show resolved Hide resolved
</InputGroup>
</ModalSectionContent>

Expand Down
38 changes: 37 additions & 1 deletion editor.planx.uk/src/@planx/components/Checklist/Public.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import ImageButton from "@planx/components/shared/Buttons/ImageButton";
import Card from "@planx/components/shared/Preview/Card";
import CardHeader from "@planx/components/shared/Preview/CardHeader";
import { getIn, useFormik } from "formik";
import React, { useState } from "react";
import { useStore } from "pages/FlowEditor/lib/store";
import React, { useEffect, useState } from "react";
import { ExpandableList, ExpandableListItem } from "ui/public/ExpandableList";
import FormWrapper from "ui/public/FormWrapper";
import FullWidthWrapper from "ui/public/FullWidthWrapper";
Expand All @@ -38,6 +39,41 @@ function toggleInArray<T>(value: T, arr: Array<T>): Array<T> {
}

const ChecklistComponent: React.FC<Props> = (props) => {
if (props.forceSelection) {
return <VisibleChecklist {...props} />;
}

const autoAnswerableOptions = useStore(
(state) => state.autoAnswerableOptions,
);

let idsThatCanBeAutoAnswered: string[] | undefined;
if (props.id) idsThatCanBeAutoAnswered = autoAnswerableOptions(props.id);

if (idsThatCanBeAutoAnswered && idsThatCanBeAutoAnswered.length > 0) {
jessicamcinchak marked this conversation as resolved.
Show resolved Hide resolved
return (
<AutoAnsweredChecklist {...props} answerIds={idsThatCanBeAutoAnswered} />
);
} else {
return <VisibleChecklist {...props} />;
}
jessicamcinchak marked this conversation as resolved.
Show resolved Hide resolved
};

// An auto-answered Checklist won't be seen by the user, but still leaves a breadcrumb
const AutoAnsweredChecklist: React.FC<Props & { answerIds: string[] }> = (
props,
) => {
useEffect(() => {
props.handleSubmit?.({
answers: props.answerIds,
auto: true,
});
}, []);

return null;
};

const VisibleChecklist: React.FC<Props> = (props) => {
jessicamcinchak marked this conversation as resolved.
Show resolved Hide resolved
const {
description = "",
groupedOptions,
Expand Down
1 change: 1 addition & 0 deletions editor.planx.uk/src/@planx/components/Checklist/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface Checklist extends BaseNodeData {
img?: string;
allRequired?: boolean;
categories?: Array<Category>;
forceSelection?: boolean;
jessicamcinchak marked this conversation as resolved.
Show resolved Hide resolved
}

interface ChecklistExpandableProps {
Expand Down
3 changes: 1 addition & 2 deletions editor.planx.uk/src/@planx/components/Filter/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,12 @@ const Filter: React.FC<Props> = (props) => {
through the left-most matching flag option only.
</Typography>
</ModalSectionContent>
<ModalSectionContent title="Pick a flagset category (coming soon)">
<ModalSectionContent title="Pick a flagset category">
<select
data-testid="flagset-category-select"
name="category"
value={formik.values.category}
onChange={formik.handleChange}
disabled
>
{Array.from(categories).map((category) => (
<option key={category} value={category}>
Expand Down
26 changes: 26 additions & 0 deletions editor.planx.uk/src/@planx/components/Filter/Public.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { PublicProps } from "@planx/components/ui";
import { useStore } from "pages/FlowEditor/lib/store";
import { useEffect } from "react";

import type { Props as Filter } from "./Editor";

export type Props = PublicProps<Filter>;

// Filters are always auto-answered and never seen by a user, but should still leave a breadcrumb
export default function Component(props: Props) {
const autoAnswerableFlag = useStore(
(state) => state.autoAnswerableFlag,
);

let idThatCanBeAutoAnswered: string | undefined;
if (props.id) idThatCanBeAutoAnswered = autoAnswerableFlag(props.id);

useEffect(() => {
props.handleSubmit?.({
answers: [idThatCanBeAutoAnswered],
auto: true,
});
}, []);

return null;
}
24 changes: 20 additions & 4 deletions editor.planx.uk/src/@planx/components/Question/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";
import { ComponentType as TYPES } from "@opensystemslab/planx-core/types";
import { useFormik } from "formik";
import React, { useEffect, useRef } from "react";
Expand All @@ -24,6 +26,7 @@ interface Props {
img?: string;
text: string;
type?: string;
forceSelection?: boolean;
} & BaseNodeData;
};
options?: Option[];
Expand Down Expand Up @@ -131,6 +134,7 @@ export const Question: React.FC<Props> = (props) => {
img: props.node?.data?.img || "",
options: props.options || [],
text: props.node?.data?.text || "",
forceSelection: props.node?.data?.forceSelection || false,
...parseBaseNodeData(props.node?.data),
},
onSubmit: ({ options, ...values }) => {
Expand Down Expand Up @@ -175,15 +179,13 @@ export const Question: React.FC<Props> = (props) => {
onChange={formik.handleChange}
inputRef={focusRef}
/>

<ImgInput
img={formik.values.img}
onChange={(newUrl) => {
formik.setFieldValue("img", newUrl);
}}
/>
</InputRow>

<InputRow>
<RichTextInput
name="description"
Expand All @@ -192,7 +194,6 @@ export const Question: React.FC<Props> = (props) => {
onChange={formik.handleChange}
/>
</InputRow>

<InputRow>
<Input
// required
Expand All @@ -203,6 +204,22 @@ export const Question: React.FC<Props> = (props) => {
onChange={formik.handleChange}
/>
</InputRow>
<InputRow>
<FormControlLabel
control={
<Switch
checked={formik.values.forceSelection}
onChange={() =>
formik.setFieldValue(
"forceSelection",
!formik.values.forceSelection,
)
}
/>
}
label="Always put to user (forgo automation)"
/>
</InputRow>
</InputGroup>
</ModalSectionContent>

Expand All @@ -227,7 +244,6 @@ export const Question: React.FC<Props> = (props) => {
/>
</ModalSectionContent>
</ModalSection>

<MoreInformation
changeField={formik.handleChange}
definitionImg={formik.values.definitionImg}
Expand Down
46 changes: 44 additions & 2 deletions editor.planx.uk/src/@planx/components/Question/Public.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,50 @@
import { waitFor } from "@testing-library/react";
import { act, waitFor } from "@testing-library/react";
import React from "react";
import { setup } from "testUtils";
import { vi } from "vitest";
import { axe } from "vitest-axe";

import { Store, useStore } from "pages/FlowEditor/lib/store";
import type { Question } from "./model";
import QuestionComponent, { QuestionLayout } from "./Public";

const { setState } = useStore;

// Setup a basic single component flow so that we're testing the "VisibleQuestion" throughout (eg wrapper checks `flow[props.id].edges`)
const flow: Store.Flow = {
"_root": {
"edges": [
"qustion_id"
]
},
"celery_id": {
"data": {
"text": "celery"
},
"type": 200
},
"pizza_id": {
"data": {
"text": "pizza"
},
"type": 200
},
"question_id": {
"data": {
"text": "Best food",
},
"type": 100,
"edges": [
"pizza_id",
"celery_id",
]
},
};

beforeEach(() => {
act(() => setState({ flow }));
});

const responses: { [key in QuestionLayout]: Question["responses"] } = {
[QuestionLayout.Basic]: [
{
Expand Down Expand Up @@ -58,9 +96,10 @@ describe("Question component", () => {
describe(`${QuestionLayout[type]} layout`, () => {
it(`renders the layout correctly`, async () => {
const handleSubmit = vi.fn();

const { user, getByTestId, getByRole, getByText } = setup(
<QuestionComponent
id="question_id"
text="Best food"
responses={responses[type]}
handleSubmit={handleSubmit}
Expand All @@ -84,6 +123,7 @@ describe("Question component", () => {
const handleSubmit = vi.fn();
const { user, getByRole, getByTestId } = setup(
<QuestionComponent
id="question_id"
text="Best food"
responses={responses[type]}
previouslySubmittedData={{
Expand Down Expand Up @@ -114,6 +154,7 @@ describe("Question component", () => {
const handleSubmit = vi.fn();
const { container } = setup(
<QuestionComponent
id="question_id"
text="Best food"
responses={responses[type]}
handleSubmit={handleSubmit}
Expand All @@ -129,6 +170,7 @@ describe("Question component", () => {

const { user, getByTestId, getByText, queryByText } = setup(
<QuestionComponent
id="question_id"
text="Best food"
responses={responses[type]}
handleSubmit={handleSubmit}
Expand Down
Loading
Loading