Skip to content

Commit

Permalink
Merge branch 'main' into rory/add-name-editor-2
Browse files Browse the repository at this point in the history
  • Loading branch information
RODO94 committed Jun 11, 2024
2 parents 20a0cc1 + 0d0bc43 commit 468e520
Show file tree
Hide file tree
Showing 20 changed files with 831 additions and 254 deletions.
2 changes: 2 additions & 0 deletions editor.planx.uk/src/@planx/components/List/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import InputRowLabel from "ui/shared/InputRowLabel";

import { EditorProps, ICONS, InternalNotes, MoreInformation } from "../ui";
import { List, parseContent } from "./model";
import { ProposedAdvertisements } from "./schemas/Adverts";
import { ResidentialUnitsExisting } from "./schemas/ResidentialUnits/Existing";
import { ResidentialUnitsGLANew } from "./schemas/ResidentialUnits/GLA/New";
import { ResidentialUnitsGLARebuilt } from "./schemas/ResidentialUnits/GLA/Rebuilt";
Expand Down Expand Up @@ -40,6 +41,7 @@ export const SCHEMAS = [
schema: ResidentialUnitsGLARetained,
},
{ name: "Zoo (test)", schema: Zoo },
{ name: "Proposed advertisements", schema: ProposedAdvertisements },
];

function ListComponent(props: Props) {
Expand Down
24 changes: 17 additions & 7 deletions editor.planx.uk/src/@planx/components/List/Public/Context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ import {
Schema,
UserData,
} from "../model";
import { flatten } from "../utils";
import {
flatten,
sumIdenticalUnits,
sumIdenticalUnitsByDevelopmentType,
} from "../utils";

interface ListContextValue {
schema: Schema;
Expand Down Expand Up @@ -132,7 +136,7 @@ export const ListProvider: React.FC<ListProviderProps> = (props) => {
userData: getInitialValues(),
},
onSubmit: (values) => {
// defaultPassportData is used when coming "back"
// defaultPassportData (array) is used when coming "back"
const defaultPassportData = makeData(props, values.userData)?.["data"];

// flattenedPassportData makes individual list items compatible with Calculate components
Expand All @@ -141,16 +145,22 @@ export const ListProvider: React.FC<ListProviderProps> = (props) => {
// basic example of general summary stats we can add onSubmit:
// 1. count of items/responses
// 2. if the schema includes a field that sets fn = "identicalUnits", sum of total units
let sumIdenticalUnits = 0;
defaultPassportData[`${props.fn}`].map(
(item) => (sumIdenticalUnits += parseInt(item?.identicalUnits)),
// 3. if the schema includes a field that sets fn = "development" & fn = "identicalUnits", sum of total units by development "val"
const totalUnits = sumIdenticalUnits(props.fn, defaultPassportData);
const totalUnitsByDevelopmentType = sumIdenticalUnitsByDevelopmentType(
props.fn,
defaultPassportData,
);

const summaries = {
[`${props.fn}.total.listItems`]:
defaultPassportData[`${props.fn}`].length,
...(sumIdenticalUnits > 0 && {
[`${props.fn}.total.units`]: sumIdenticalUnits,
...(totalUnits > 0 && {
[`${props.fn}.total.units`]: totalUnits,
}),
...(totalUnits > 0 &&
Object.keys(totalUnitsByDevelopmentType).length > 0 &&
totalUnitsByDevelopmentType),
};

handleSubmit?.({
Expand Down
10 changes: 6 additions & 4 deletions editor.planx.uk/src/@planx/components/List/Public/Fields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export const RadioFieldInput: React.FC<Props<QuestionField>> = (props) => {
{data.options.map(({ id, data }) => (
<BasicRadio
key={id}
id={data.text}
id={data.val || data.text}
title={data.text}
onChange={formik.handleChange}
/>
Expand All @@ -159,9 +159,11 @@ export const SelectFieldInput: React.FC<Props<QuestionField>> = (props) => {

const existingValues = formik.values.userData
.map((response) => response[data.fn])
.filter((value) => value === option.data.text);
.filter(
(value) => value === option.data.val || value === option.data.text,
);

return existingValues.includes(option.data.text);
return existingValues.includes(option.data.val || option.data.text);
};

return (
Expand All @@ -185,7 +187,7 @@ export const SelectFieldInput: React.FC<Props<QuestionField>> = (props) => {
{data.options.map((option) => (
<MenuItem
key={option.id}
value={option.data.text}
value={option.data.val || option.data.text}
disabled={isDisabled(option)}
>
{option.data.text}
Expand Down
95 changes: 94 additions & 1 deletion editor.planx.uk/src/@planx/components/List/Public/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ import { cloneDeep, merge } from "lodash";
import React from "react";
import { axe, setup } from "testUtils";

import { UserResponse } from "../model";
import ListComponent, { Props } from "../Public";
import { GenericUnitsTest } from "../schemas/GenericUnitsTest";
import { Zoo } from "../schemas/Zoo";
import {
flatten,
sumIdenticalUnits,
sumIdenticalUnitsByDevelopmentType,
} from "../utils";

const mockProps: Props = {
fn: "mockFn",
Expand Down Expand Up @@ -47,6 +54,48 @@ const mockPayload = {
},
};

const mockPropsUnits: Props = {
fn: "proposal.units.residential",
schema: GenericUnitsTest,
schemaName: "Generic residential units",
title: "Describe residential units",
};

const mockPayloadUnits = {
data: {
"proposal.units.residential": [
{
development: "newBuild",
garden: "Yes",
identicalUnits: 1,
},
{
development: "newBuild",
garden: "No",
identicalUnits: 2,
},
{
development: "changeOfUseTo",
garden: "No",
identicalUnits: 2,
},
],
"proposal.units.residential.one.development": "newBuild",
"proposal.units.residential.one.garden": "Yes",
"proposal.units.residential.one.identicalUnits": 1,
"proposal.units.residential.two.development": "newBuild",
"proposal.units.residential.two.garden": "No",
"proposal.units.residential.two.identicalUnits": 2,
"proposal.units.residential.three.development": "changeOfUseTo",
"proposal.units.residential.three.garden": "No",
"proposal.units.residential.three.identicalUnits": 2,
"proposal.units.residential.total.listItems": 3,
"proposal.units.residential.total.units": 5,
"proposal.units.residential.total.units.newBuid": 3,
"proposal.units.residential.total.units.changeOfUseTo": 2,
},
};

jest.setTimeout(20_000);

describe("Basic UI", () => {
Expand Down Expand Up @@ -378,7 +427,7 @@ describe("Form validation and error handling", () => {
});

describe("Payload generation", () => {
it("generates a valid payload on submission", async () => {
it("generates a valid payload on submission (Zoo)", async () => {
const handleSubmit = jest.fn();
const { getByTestId, user } = setup(
<ListComponent {...mockProps} handleSubmit={handleSubmit} />,
Expand All @@ -395,6 +444,50 @@ describe("Payload generation", () => {
expect(handleSubmit).toHaveBeenCalled();
expect(handleSubmit.mock.calls[0][0]).toMatchObject(mockPayload);
});

it.skip("generates a valid payload with summary stats on submission (Units)", async () => {
const handleSubmit = jest.fn();
const { getByTestId, user } = setup(
<ListComponent {...mockPropsUnits} handleSubmit={handleSubmit} />,
);

const saveButton = screen.getByRole("button", { name: /Save/ });
const addItemButton = getByTestId("list-add-button");
const developmentSelect = screen.getByRole("combobox");
const gardenYesRadio = screen.getAllByRole("radio")[0];
const gardenNoRadio = screen.getAllByRole("radio")[1];
const unitsNumberInput = screen.getByLabelText(/identical units/);

// Response 1
await user.click(developmentSelect);
await user.click(screen.getByRole("option", { name: /New build/ }));
await user.click(gardenYesRadio);
await user.type(unitsNumberInput, "1");
await user.click(saveButton);

// Response 2
await user.click(addItemButton);
await user.click(developmentSelect);
await user.click(screen.getByRole("option", { name: /New build/ }));
await user.click(gardenNoRadio);
await user.type(unitsNumberInput, "2");
await user.click(saveButton);

// Response 3
await user.click(addItemButton);
await user.click(developmentSelect);
await user.click(
screen.getByRole("option", { name: /Change of use to a home/ }),
);
await user.click(gardenNoRadio);
await user.type(unitsNumberInput, "2");
await user.click(saveButton);

await user.click(screen.getByTestId("continue-button"));

expect(handleSubmit).toHaveBeenCalled();
expect(handleSubmit.mock.calls[0][0]).toMatchObject(mockPayloadUnits);
});
});

describe("Navigating back", () => {
Expand Down
8 changes: 7 additions & 1 deletion editor.planx.uk/src/@planx/components/List/Public/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import InputRow from "ui/shared/InputRow";
import Card from "../../shared/Preview/Card";
import CardHeader from "../../shared/Preview/CardHeader";
import type { Field, List } from "../model";
import { formatSchemaDisplayValue } from "../utils";
import { ListProvider, useListContext } from "./Context";
import {
NumberFieldInput,
Expand Down Expand Up @@ -111,7 +112,12 @@ const InactiveListCard: React.FC<{
<TableCell sx={{ fontWeight: FONT_WEIGHT_SEMI_BOLD }}>
{field.data.title}
</TableCell>
<TableCell>{formik.values.userData[i][field.data.fn]}</TableCell>
<TableCell>
{formatSchemaDisplayValue(
formik.values.userData[i][field.data.fn],
schema,
)}
</TableCell>
</TableRow>
))}
</TableBody>
Expand Down
4 changes: 2 additions & 2 deletions editor.planx.uk/src/@planx/components/List/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface QuestionInput {
*/
const questionInputValidationSchema = (data: QuestionInput) =>
string()
.oneOf(data.options.map((option) => option.data.text))
.oneOf(data.options.map((option) => option.data.val || option.data.text))
.required("Select your answer before continuing");

// TODO: Add summary fields for inactive view?
Expand Down Expand Up @@ -62,7 +62,7 @@ export interface Schema {
max?: number;
}

type UserResponse = Record<Field["data"]["fn"], string>;
export type UserResponse = Record<Field["data"]["fn"], string>;

export type UserData = { userData: UserResponse[] };

Expand Down
41 changes: 41 additions & 0 deletions editor.planx.uk/src/@planx/components/List/schemas/Adverts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Schema } from "@planx/components/List/model";

export const ProposedAdvertisements: Schema = {
type: "Proposed advertisements",
fields: [
{
type: "number",
data: {
title: "How many fascia signs are you applying for?",
fn: "fascia",
allowNegatives: false,
},
},
{
type: "number",
data: {
title: "How many projecting or hanging signs are you applying for?",
fn: "projecting",
allowNegatives: false,
},
},
{
type: "number",
data: {
title: "How many hoardings are you applying for?",
fn: "hoarding",
allowNegatives: false,
},
},
{
type: "number",
data: {
title: "How many other advertisements are you applying for?",
fn: "other",
allowNegatives: false,
},
},
],
min: 1,
max: 1,
} as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Schema } from "@planx/components/List/model";

export const GenericUnitsTest: Schema = {
type: "Unit",
fields: [
// fn = "development" triggers summary stat and options set "val"
{
type: "question",
data: {
title: "What development does this unit result from?",
fn: "development",
options: [
{ id: "newBuild", data: { text: "New build", val: "newBuild" } },
{
id: "changeOfUseFrom",
data: {
text: "Change of use of existing single home",
val: "changeOfUseFrom",
},
},
{
id: "changeOfUseTo",
data: { text: "Change of use to a home", val: "changeOfUseTo" },
},
],
},
},
// options set "text" only
{
type: "question",
data: {
title: "Is this unit built on garden land?",
fn: "garden",
options: [
{ id: "true", data: { text: "Yes" } },
{ id: "false", data: { text: "No" } },
],
},
},
// fn = "identicalUnits" triggers summary stat
{
type: "number",
data: {
title: "How many identical units does the description above apply to?",
fn: "identicalUnits",
allowNegatives: false,
},
},
],
min: 1,
} as const;
Loading

0 comments on commit 468e520

Please sign in to comment.