diff --git a/editor.planx.uk/src/@planx/components/DateInput/model.test.ts b/editor.planx.uk/src/@planx/components/DateInput/model.test.ts index 03d7b20439..7d73193590 100644 --- a/editor.planx.uk/src/@planx/components/DateInput/model.test.ts +++ b/editor.planx.uk/src/@planx/components/DateInput/model.test.ts @@ -47,7 +47,10 @@ describe("dateSchema", () => { expect(await dateSchema().isValid("2021-23-03")).toBe(false); }); - const validate = async (date?: string) => await dateSchema().validate(date).catch((err) => err.errors); + const validate = async (date?: string) => + await dateSchema() + .validate(date) + .catch((err) => err.errors); it("throws an error for an undefined value (empty form)", async () => { const errors = await validate(undefined); @@ -58,12 +61,12 @@ describe("dateSchema", () => { const errors = await validate("ab-cd-efgh"); expect(errors[0]).toMatch(/Date must include a day/); }); - + it("throws an error for a missing day", async () => { const errors = await validate("2024-12-"); expect(errors[0]).toMatch(/Date must include a day/); }); - + it("throws an error for a missing month", async () => { const errors = await validate("2024--25"); expect(errors[0]).toMatch(/Date must include a month/); @@ -112,7 +115,7 @@ describe("dateRangeSchema", () => { "1980-06-15", ), ).toBe(false); - }) + }); }); test("padding on input", () => { @@ -145,4 +148,4 @@ test("padding on blur", () => { // Leaves single 0 alone expect(paddedDate("2021-0-2", "blur")).toBe("2021-0-02"); expect(paddedDate("2021-10-0", "blur")).toBe("2021-10-0"); -}); \ No newline at end of file +}); diff --git a/editor.planx.uk/src/@planx/components/DateInput/model.ts b/editor.planx.uk/src/@planx/components/DateInput/model.ts index 4b6ee7b2b5..f661f803e3 100644 --- a/editor.planx.uk/src/@planx/components/DateInput/model.ts +++ b/editor.planx.uk/src/@planx/components/DateInput/model.ts @@ -60,47 +60,33 @@ const displayDate = (date: string): string | undefined => { }; export const parseDate = (date?: string) => { - const [year, month, day] = date?.split("-").map((val) => parseInt(val) || undefined) || []; + const [year, month, day] = + date?.split("-").map((val) => parseInt(val) || undefined) || []; return { year, month, day }; -} +}; export const dateSchema = () => { return string() - .test( - "missing day", - "Date must include a day", - (date?: string) => { - const { day } = parseDate(date); - return day !== undefined; - }) - .test( - "missing month", - "Date must include a month", - (date?: string) => { - const { month } = parseDate(date); - return month !== undefined; - }) - .test( - "missing year", - "Date must include a year", - (date?: string) => { - const { year } = parseDate(date); - return year !== undefined; - }) - .test( - "invalid day", - "Day must be valid", - (date?: string) => { - const { day } = parseDate(date); - return Boolean(day && day <= 31) - }) - .test( - "invalid month", - "Month must be valid", - (date?: string) => { - const { month } = parseDate(date); - return Boolean(month && month <= 12); - }) + .test("missing day", "Date must include a day", (date?: string) => { + const { day } = parseDate(date); + return day !== undefined; + }) + .test("missing month", "Date must include a month", (date?: string) => { + const { month } = parseDate(date); + return month !== undefined; + }) + .test("missing year", "Date must include a year", (date?: string) => { + const { year } = parseDate(date); + return year !== undefined; + }) + .test("invalid day", "Day must be valid", (date?: string) => { + const { day } = parseDate(date); + return Boolean(day && day <= 31); + }) + .test("invalid month", "Month must be valid", (date?: string) => { + const { month } = parseDate(date); + return Boolean(month && month <= 12); + }) .test( "valid", "Enter a valid date in DD.MM.YYYY format", @@ -115,24 +101,26 @@ export const dateRangeSchema: (params: { min?: string; max?: string; }) => SchemaOf = (params) => - dateSchema() - .required("Enter a valid date in DD.MM.YYYY format") - .test({ - name: "too soon", - message: `Enter a date later than ${params.min && displayDate(params.min) - }`, - test: (date: string | undefined) => { - return Boolean(date && !(params.min && date < params.min)); - }, - }) - .test({ - name: "too late", - message: `Enter a date earlier than ${params.max && displayDate(params.max) - }`, - test: (date: string | undefined) => { - return Boolean(date && !(params.max && date > params.max)); - }, - }); + dateSchema() + .required("Enter a valid date in DD.MM.YYYY format") + .test({ + name: "too soon", + message: `Enter a date later than ${ + params.min && displayDate(params.min) + }`, + test: (date: string | undefined) => { + return Boolean(date && !(params.min && date < params.min)); + }, + }) + .test({ + name: "too late", + message: `Enter a date earlier than ${ + params.max && displayDate(params.max) + }`, + test: (date: string | undefined) => { + return Boolean(date && !(params.max && date > params.max)); + }, + }); export const parseDateInput = ( data: Record | undefined, diff --git a/editor.planx.uk/src/@planx/components/List/Editor.tsx b/editor.planx.uk/src/@planx/components/List/Editor.tsx index b62e8daa30..6b85d49b87 100644 --- a/editor.planx.uk/src/@planx/components/List/Editor.tsx +++ b/editor.planx.uk/src/@planx/components/List/Editor.tsx @@ -14,6 +14,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 { NonResidentialFloorspace } from "./schemas/Floorspace"; import { BuildingDetailsGLA } from "./schemas/GLA/BuildingDetails"; import { CommunalSpaceGLA } from "./schemas/GLA/CommunalSpace"; import { ExistingAndProposedUsesGLA } from "./schemas/GLA/ExistingAndProposedUses"; @@ -24,7 +25,6 @@ import { ResidentialUnitsExisting } from "./schemas/ResidentialUnits/Existing"; import { ResidentialUnitsGLAGained } from "./schemas/ResidentialUnits/GLA/Gained"; import { ResidentialUnitsGLALost } from "./schemas/ResidentialUnits/GLA/Lost"; import { ResidentialUnitsProposed } from "./schemas/ResidentialUnits/Proposed"; -import { NonResidentialFloorspace } from "./schemas/Floorspace"; type Props = EditorProps; diff --git a/editor.planx.uk/src/@planx/components/List/Public/Context.tsx b/editor.planx.uk/src/@planx/components/List/Public/Context.tsx index 99af3801fb..e9c22cee1a 100644 --- a/editor.planx.uk/src/@planx/components/List/Public/Context.tsx +++ b/editor.planx.uk/src/@planx/components/List/Public/Context.tsx @@ -63,7 +63,9 @@ export const ListProvider: React.FC = (props) => { props.previouslySubmittedData ? -1 : 0, ); - const [activeItemInitialState, setActiveItemInitialState] = useState(undefined); + const [activeItemInitialState, setActiveItemInitialState] = useState< + UserResponse | undefined + >(undefined); const [addItemError, setAddItemError] = useState(false); const [unsavedItemError, setUnsavedItemError] = useState(false); @@ -132,16 +134,16 @@ export const ListProvider: React.FC = (props) => { activeItemInitialState ? resetItemToPreviousState() : removeItem(activeIndex); - + setActiveItemInitialState(undefined); exitEditMode(); - } + }; const editItem = (index: number) => { setActiveItemInitialState(formik.values.userData[index]); setActiveIndex(index); - } + }; const getInitialValues = () => { const previousValues = getPreviouslySubmittedData(props); @@ -151,12 +153,9 @@ export const ListProvider: React.FC = (props) => { }; const exitEditMode = () => setActiveIndex(-1); - - const resetItemToPreviousState = () => - formik.setFieldValue( - `userData[${activeIndex}]`, - activeItemInitialState - ) + + const resetItemToPreviousState = () => + formik.setFieldValue(`userData[${activeIndex}]`, activeItemInitialState); const isPageComponent = schema.max === 1; diff --git a/editor.planx.uk/src/@planx/components/List/Public/index.test.tsx b/editor.planx.uk/src/@planx/components/List/Public/index.test.tsx index 1f25e0eb34..aa47784682 100644 --- a/editor.planx.uk/src/@planx/components/List/Public/index.test.tsx +++ b/editor.planx.uk/src/@planx/components/List/Public/index.test.tsx @@ -348,7 +348,7 @@ describe("Building a list", () => { expect(cards).toHaveLength(1); const cancelButton = getByText(/Cancel/, { selector: "button" }); - await user.click(cancelButton) + await user.click(cancelButton); cards = queryAllByTestId(/list-card/); expect(cards).toHaveLength(0); @@ -376,7 +376,7 @@ describe("Building a list", () => { expect(getByText("richard.parker@pi.com")).toBeInTheDocument(); }); }); - + describe("Form validation and error handling", () => { test.todo("form validation is triggered when saving an item"); test.todo("text fields use existing validation schemas"); diff --git a/editor.planx.uk/src/@planx/components/List/Public/index.tsx b/editor.planx.uk/src/@planx/components/List/Public/index.tsx index 1afd2c3ecd..44117493dc 100644 --- a/editor.planx.uk/src/@planx/components/List/Public/index.tsx +++ b/editor.planx.uk/src/@planx/components/List/Public/index.tsx @@ -65,7 +65,8 @@ const InputField: React.FC = (props) => { const ActiveListCard: React.FC<{ index: number; }> = ({ index: i }) => { - const { schema, saveItem, cancelEditItem, errors, isPageComponent } = useListContext(); + const { schema, saveItem, cancelEditItem, errors, isPageComponent } = + useListContext(); return ( = ({ index: i }) => { - const { schema, formik, removeItem, editItem, isPageComponent } = useListContext(); + const { schema, formik, removeItem, editItem, isPageComponent } = + useListContext(); return ( diff --git a/editor.planx.uk/src/@planx/components/List/schemas/Floorspace.ts b/editor.planx.uk/src/@planx/components/List/schemas/Floorspace.ts index e0329432c3..f8476d0e3f 100644 --- a/editor.planx.uk/src/@planx/components/List/schemas/Floorspace.ts +++ b/editor.planx.uk/src/@planx/components/List/schemas/Floorspace.ts @@ -28,15 +28,24 @@ export const NonResidentialFloorspace: Schema = { }, { id: "eAShops", - data: { text: "E(a) - Retail (other than hot food): Shops", val: "eAShops" }, + data: { + text: "E(a) - Retail (other than hot food): Shops", + val: "eAShops", + }, }, { id: "eANetTradeableArea", - data: { text: "E(a) - Retail (other than hot food): Net tradeable area", val: "eANetTradeableArea" }, + data: { + text: "E(a) - Retail (other than hot food): Net tradeable area", + val: "eANetTradeableArea", + }, }, { id: "eB", - data: { text: "E(b) - Sale of food and drink (mostly consumed on the premises)", val: "eB" }, + data: { + text: "E(b) - Sale of food and drink (mostly consumed on the premises)", + val: "eB", + }, }, { id: "eCI", @@ -44,7 +53,10 @@ export const NonResidentialFloorspace: Schema = { }, { id: "eCII", - data: { text: "E(c)(ii) - Professional services (other than health or medical)", val: "eCII" }, + data: { + text: "E(c)(ii) - Professional services (other than health or medical)", + val: "eCII", + }, }, { id: "eCIII", @@ -52,7 +64,10 @@ export const NonResidentialFloorspace: Schema = { }, { id: "eD", - data: { text: "E(d) - Indoor sports, recreation or fitness", val: "eD" }, + data: { + text: "E(d) - Indoor sports, recreation or fitness", + val: "eD", + }, }, { id: "eF", @@ -60,15 +75,24 @@ export const NonResidentialFloorspace: Schema = { }, { id: "eGI", - data: { text: "E(g)(i) - Office (to carry out operational or administrative functions)", val: "eGI" }, + data: { + text: "E(g)(i) - Office (to carry out operational or administrative functions)", + val: "eGI", + }, }, { id: "eGII", - data: { text: "E(g)(ii) - Research and development of products or processes", val: "eGII" }, + data: { + text: "E(g)(ii) - Research and development of products or processes", + val: "eGII", + }, }, { id: "eGIII", - data: { text: "E(g)(iii) - Any industrial process (can be carried out within a residential area)", val: "eGIII" }, + data: { + text: "E(g)(iii) - Any industrial process (can be carried out within a residential area)", + val: "eGIII", + }, }, { id: "fOneA", @@ -121,11 +145,17 @@ export const NonResidentialFloorspace: Schema = { }, { id: "fTwoA", - data: { text: "F2(a) - Shop selling essential goods (not over 280sqm and no other such facility in 1000m radius)", val: "fTwoA" }, + data: { + text: "F2(a) - Shop selling essential goods (not over 280sqm and no other such facility in 1000m radius)", + val: "fTwoA", + }, }, { id: "fTwoB", - data: { text: "F2(b) - Hall or meeting place for local community (principal use)", val: "fTwoB" }, + data: { + text: "F2(b) - Hall or meeting place for local community (principal use)", + val: "fTwoB", + }, }, { id: "fTwoC", @@ -133,7 +163,10 @@ export const NonResidentialFloorspace: Schema = { }, { id: "fTwoD", - data: { text: "F2(d) - Indoor or outdoor swimming pool or skating rink", val: "fTwoD" }, + data: { + text: "F2(d) - Indoor or outdoor swimming pool or skating rink", + val: "fTwoD", + }, }, { id: "other", data: { text: "Other", val: "other" } }, ], @@ -151,7 +184,8 @@ export const NonResidentialFloorspace: Schema = { { type: "number", data: { - title: "What is the gross internal floor area to be lost by change of use or demolition?", + title: + "What is the gross internal floor area to be lost by change of use or demolition?", units: "m²", fn: "area.loss", allowNegatives: false, @@ -160,7 +194,8 @@ export const NonResidentialFloorspace: Schema = { { type: "number", data: { - title: "What is the total gross internal floor area proposed (including change of use)?", + title: + "What is the total gross internal floor area proposed (including change of use)?", units: "m²", fn: "area.proposed", allowNegatives: false, diff --git a/editor.planx.uk/src/@planx/components/List/schemas/ResidentialUnits/Proposed.ts b/editor.planx.uk/src/@planx/components/List/schemas/ResidentialUnits/Proposed.ts index 77b533791d..ea99c599b0 100644 --- a/editor.planx.uk/src/@planx/components/List/schemas/ResidentialUnits/Proposed.ts +++ b/editor.planx.uk/src/@planx/components/List/schemas/ResidentialUnits/Proposed.ts @@ -10,8 +10,17 @@ export const ResidentialUnitsProposed: Schema = { 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" } }, + { + 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" }, + }, ], }, }, diff --git a/editor.planx.uk/src/@planx/components/NumberInput/Public.test.tsx b/editor.planx.uk/src/@planx/components/NumberInput/Public.test.tsx index 016150cc80..9756edf100 100644 --- a/editor.planx.uk/src/@planx/components/NumberInput/Public.test.tsx +++ b/editor.planx.uk/src/@planx/components/NumberInput/Public.test.tsx @@ -39,12 +39,21 @@ test("requires a positive number to be input by default", async () => { const handleSubmit = jest.fn(); const { user } = setup( - , + , ); - expect(screen.getByRole("heading")).toHaveTextContent("How many doors are you adding?"); + expect(screen.getByRole("heading")).toHaveTextContent( + "How many doors are you adding?", + ); - await user.type(screen.getByLabelText("How many doors are you adding?"), "-1"); + await user.type( + screen.getByLabelText("How many doors are you adding?"), + "-1", + ); await user.click(screen.getByTestId("continue-button")); expect(screen.getByText("Enter a positive number")).toBeInTheDocument(); @@ -55,10 +64,17 @@ test("allows negative numbers to be input when toggled on by editor", async () = const handleSubmit = jest.fn(); const { user } = setup( - , + , ); - expect(screen.getByRole("heading")).toHaveTextContent("What's the temperature?"); + expect(screen.getByRole("heading")).toHaveTextContent( + "What's the temperature?", + ); await user.type(screen.getByLabelText("What's the temperature?"), "-10"); await user.click(screen.getByTestId("continue-button")); diff --git a/editor.planx.uk/src/@planx/components/SetValue/utils.test.ts b/editor.planx.uk/src/@planx/components/SetValue/utils.test.ts index c556459134..9fb490626d 100644 --- a/editor.planx.uk/src/@planx/components/SetValue/utils.test.ts +++ b/editor.planx.uk/src/@planx/components/SetValue/utils.test.ts @@ -1,7 +1,7 @@ -import { SetValue } from "./model"; -import { handleSetValue } from "./utils"; import { Store } from "pages/FlowEditor/lib/store"; +import { SetValue } from "./model"; +import { handleSetValue } from "./utils"; describe("calculateNewValues() helper function", () => { describe('"replace" operation', () => { @@ -12,26 +12,29 @@ describe("calculateNewValues() helper function", () => { { previous: ["lion"], expected: ["lion"] }, { previous: ["bear", "dog", "monkey"], expected: ["lion"] }, { previous: ["bear", "dog", "lion"], expected: ["lion"] }, - ])('input of $previous sets passport value to be $expected', ({ previous, expected }) => { - const mockKey = "myAnimals"; - const mockSetValue: SetValue = { - operation: "replace", - fn: mockKey, - val: "lion", - }; - const mockPassport: Store.passport = { - data: { mockNode: mockSetValue, [mockKey]: previous }, - }; + ])( + "input of $previous sets passport value to be $expected", + ({ previous, expected }) => { + const mockKey = "myAnimals"; + const mockSetValue: SetValue = { + operation: "replace", + fn: mockKey, + val: "lion", + }; + const mockPassport: Store.passport = { + data: { mockNode: mockSetValue, [mockKey]: previous }, + }; - const updatedPassport = handleSetValue({ - nodeData: mockSetValue, - previousValues: previous, - passport: mockPassport, - }); + const updatedPassport = handleSetValue({ + nodeData: mockSetValue, + previousValues: previous, + passport: mockPassport, + }); - const actual = updatedPassport.data?.[mockKey]; - expect(actual).toEqual(expected); - }); + const actual = updatedPassport.data?.[mockKey]; + expect(actual).toEqual(expected); + }, + ); }); describe('"append" operation', () => { @@ -45,26 +48,29 @@ describe("calculateNewValues() helper function", () => { expected: ["bear", "dog", "monkey", "lion"], }, { previous: ["bear", "dog", "lion"], expected: ["bear", "dog", "lion"] }, - ])('input of $previous sets passport value to be $expected', ({ previous, expected }) => { - const mockKey = "myAnimals"; - const mockSetValue: SetValue = { - operation: "append", - fn: mockKey, - val: "lion", - }; - const mockPassport: Store.passport = { - data: { mockNode: mockSetValue, [mockKey]: previous }, - }; + ])( + "input of $previous sets passport value to be $expected", + ({ previous, expected }) => { + const mockKey = "myAnimals"; + const mockSetValue: SetValue = { + operation: "append", + fn: mockKey, + val: "lion", + }; + const mockPassport: Store.passport = { + data: { mockNode: mockSetValue, [mockKey]: previous }, + }; - const updatedPassport = handleSetValue({ - nodeData: mockSetValue, - previousValues: previous, - passport: mockPassport, - }); + const updatedPassport = handleSetValue({ + nodeData: mockSetValue, + previousValues: previous, + passport: mockPassport, + }); - const actual = updatedPassport.data?.[mockKey]; - expect(actual).toEqual(expected); - }); + const actual = updatedPassport.data?.[mockKey]; + expect(actual).toEqual(expected); + }, + ); }); describe('"removeOne" operation', () => { @@ -78,26 +84,29 @@ describe("calculateNewValues() helper function", () => { expected: ["bear", "dog", "monkey"], }, { previous: ["bear", "dog", "lion"], expected: ["bear", "dog"] }, - ])('input of $previous sets passport value to be $expected', ({ previous, expected }) => { - const mockKey = "myAnimals"; - const mockSetValue: SetValue = { - operation: "removeOne", - fn: mockKey, - val: "lion", - }; - const mockPassport: Store.passport = { - data: { mockNode: mockSetValue, [mockKey]: previous }, - }; + ])( + "input of $previous sets passport value to be $expected", + ({ previous, expected }) => { + const mockKey = "myAnimals"; + const mockSetValue: SetValue = { + operation: "removeOne", + fn: mockKey, + val: "lion", + }; + const mockPassport: Store.passport = { + data: { mockNode: mockSetValue, [mockKey]: previous }, + }; - const updatedPassport = handleSetValue({ - nodeData: mockSetValue, - previousValues: previous, - passport: mockPassport, - }); + const updatedPassport = handleSetValue({ + nodeData: mockSetValue, + previousValues: previous, + passport: mockPassport, + }); - const actual = updatedPassport.data?.[mockKey]; - expect(actual).toEqual(expected); - }); + const actual = updatedPassport.data?.[mockKey]; + expect(actual).toEqual(expected); + }, + ); }); describe('"removeAll" operation', () => { @@ -111,25 +120,28 @@ describe("calculateNewValues() helper function", () => { expected: undefined, }, { previous: ["bear", "dog", "lion"], expected: undefined }, - ])('input of $previous sets passport value to be $expected', ({ previous, expected }) => { - const mockKey = "myAnimals"; - const mockSetValue: SetValue = { - operation: "removeAll", - fn: mockKey, - val: "lion", - }; - const mockPassport: Store.passport = { - data: { mockNode: mockSetValue, [mockKey]: previous }, - }; + ])( + "input of $previous sets passport value to be $expected", + ({ previous, expected }) => { + const mockKey = "myAnimals"; + const mockSetValue: SetValue = { + operation: "removeAll", + fn: mockKey, + val: "lion", + }; + const mockPassport: Store.passport = { + data: { mockNode: mockSetValue, [mockKey]: previous }, + }; - const updatedPassport = handleSetValue({ - nodeData: mockSetValue, - previousValues: previous, - passport: mockPassport, - }); + const updatedPassport = handleSetValue({ + nodeData: mockSetValue, + previousValues: previous, + passport: mockPassport, + }); - const actual = updatedPassport.data?.[mockKey]; - expect(actual).toEqual(expected); - }); + const actual = updatedPassport.data?.[mockKey]; + expect(actual).toEqual(expected); + }, + ); }); }); diff --git a/editor.planx.uk/src/@planx/components/SetValue/utils.ts b/editor.planx.uk/src/@planx/components/SetValue/utils.ts index be6756dff3..46df9c9431 100644 --- a/editor.planx.uk/src/@planx/components/SetValue/utils.ts +++ b/editor.planx.uk/src/@planx/components/SetValue/utils.ts @@ -1,4 +1,5 @@ import { Store } from "pages/FlowEditor/lib/store"; + import { SetValue } from "./model"; type PreviousValues = string | string[] | undefined; diff --git a/editor.planx.uk/src/@planx/components/shared/Buttons/Tag.tsx b/editor.planx.uk/src/@planx/components/shared/Buttons/Tag.tsx index effbd45a40..c1740b7783 100644 --- a/editor.planx.uk/src/@planx/components/shared/Buttons/Tag.tsx +++ b/editor.planx.uk/src/@planx/components/shared/Buttons/Tag.tsx @@ -67,7 +67,9 @@ export default function Tag(props: Props): FCReturn { id={id} tagType={tagType} > - The status of this section of the application is: + + The status of this section of the application is: + {children} ); diff --git a/editor.planx.uk/src/@planx/components/shared/Radio/BasicRadio.tsx b/editor.planx.uk/src/@planx/components/shared/Radio/BasicRadio.tsx index da3e7e2aa2..55a9a7606b 100644 --- a/editor.planx.uk/src/@planx/components/shared/Radio/BasicRadio.tsx +++ b/editor.planx.uk/src/@planx/components/shared/Radio/BasicRadio.tsx @@ -12,7 +12,12 @@ export interface Props { value?: string; } -const BasicRadio: React.FC = ({ id, onChange, title, variant = "default" }) => ( +const BasicRadio: React.FC = ({ + id, + onChange, + title, + variant = "default", +}) => ( { diff --git a/editor.planx.uk/src/components/Feedback/FeedbackForm.stories.tsx b/editor.planx.uk/src/components/Feedback/FeedbackForm.stories.tsx index 2d60bd235e..4582ce7235 100644 --- a/editor.planx.uk/src/components/Feedback/FeedbackForm.stories.tsx +++ b/editor.planx.uk/src/components/Feedback/FeedbackForm.stories.tsx @@ -59,4 +59,4 @@ export const MissingInputForm: Story = { const submitButton = canvas.getByRole("button", { name: "Send feedback" }); await userEvent.click(submitButton); }, -}; \ No newline at end of file +}; diff --git a/editor.planx.uk/src/lib/feedback.ts b/editor.planx.uk/src/lib/feedback.ts index f3b8b3f7a0..fec8766746 100644 --- a/editor.planx.uk/src/lib/feedback.ts +++ b/editor.planx.uk/src/lib/feedback.ts @@ -41,7 +41,7 @@ export async function getInternalFeedbackMetadata(): Promise { nodeType: node?.type ? TYPES[node.type] : null, device: Bowser.parse(window.navigator.userAgent), userData: userData, - nodeData: node?.data + nodeData: node?.data, }; return metadata; diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/ButtonForm.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/ButtonForm.tsx index e4f4adc681..bab3a5c61a 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/ButtonForm.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/ButtonForm.tsx @@ -11,8 +11,8 @@ import InputDescription from "ui/editor/InputDescription"; import InputRow from "ui/shared/InputRow"; import InputRowItem from "ui/shared/InputRowItem"; -import { DesignPreview, FormProps } from "."; import { SettingsForm } from "../shared/SettingsForm"; +import { DesignPreview, FormProps } from "."; export const ButtonForm: React.FC = ({ formikConfig, diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/FaviconForm.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/FaviconForm.tsx index 3a7fa0f608..14a5386a88 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/FaviconForm.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/FaviconForm.tsx @@ -10,8 +10,8 @@ import InputRow from "ui/shared/InputRow"; import InputRowItem from "ui/shared/InputRowItem"; import InputRowLabel from "ui/shared/InputRowLabel"; -import { FormProps } from "."; import { SettingsForm } from "../shared/SettingsForm"; +import { FormProps } from "."; export const FaviconForm: React.FC = ({ formikConfig, diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/TextLinkForm.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/TextLinkForm.tsx index 98c0fea0e6..4b341a74b4 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/TextLinkForm.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/TextLinkForm.tsx @@ -9,8 +9,8 @@ import InputDescription from "ui/editor/InputDescription"; import InputRow from "ui/shared/InputRow"; import InputRowItem from "ui/shared/InputRowItem"; -import { DesignPreview, FormProps } from "."; import { SettingsForm } from "../shared/SettingsForm"; +import { DesignPreview, FormProps } from "."; export const TextLinkForm: React.FC = ({ formikConfig, diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/ThemeAndLogoForm.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/ThemeAndLogoForm.tsx index afc872074f..af5c9e8da4 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/ThemeAndLogoForm.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DesignSettings/ThemeAndLogoForm.tsx @@ -12,8 +12,8 @@ import InputRow from "ui/shared/InputRow"; import InputRowItem from "ui/shared/InputRowItem"; import InputRowLabel from "ui/shared/InputRowLabel"; -import { DesignPreview, FormProps } from "."; import { SettingsForm } from "../shared/SettingsForm"; +import { DesignPreview, FormProps } from "."; export const ThemeAndLogoForm: React.FC = ({ formikConfig, diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/EditHistory.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/EditHistory.tsx index b174681364..c92b60b6b6 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/EditHistory.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/EditHistory.tsx @@ -18,9 +18,9 @@ import { OT } from "@planx/graph/types"; import DelayedLoadingIndicator from "components/DelayedLoadingIndicator"; import React, { useState } from "react"; import { FONT_WEIGHT_SEMI_BOLD } from "theme"; +import { Operation } from "types"; import { useStore } from "../../lib/store"; -import { Operation } from "types"; import { formatLastEditDate } from "../../utils"; const TooltipWrap = styled(({ className, ...props }: TooltipProps) => ( diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/PublishDialog.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/PublishDialog.tsx index da3cd924cb..cb33d3ba3c 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/PublishDialog.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/PublishDialog.tsx @@ -12,11 +12,11 @@ import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemText from "@mui/material/ListItemText"; import Typography from "@mui/material/Typography"; import { ComponentType as TYPES } from "@opensystemslab/planx-core/types"; +import { formatLastPublishMessage } from "pages/FlowEditor/utils"; import React, { useState } from "react"; import { useAsync } from "react-use"; import Caret from "ui/icons/Caret"; -import { formatLastPublishMessage } from "pages/FlowEditor/utils"; import { useStore } from "../../lib/store"; export interface AlteredNode { @@ -68,7 +68,9 @@ const AlteredNestedFlowListItem = (props: Portal) => { const _nestedFlowLastPublishedRequest = useAsync(async () => { const user = await lastPublisher(flowId); - setNestedFlowLastPublishedTitle(formatLastPublishMessage(publishedAt, user)); + setNestedFlowLastPublishedTitle( + formatLastPublishMessage(publishedAt, user), + ); }); return ( @@ -148,17 +150,23 @@ export const AlteredNodesSummaryContent = (props: { {`Changes`} {changeSummary["title"] && ( - - {changeSummary["title"]} - + {changeSummary["title"]} )} {(changeSummary["updated"] > 0 || changeSummary["deleted"] > 0) && ( - + {`${changeSummary["updated"]} nodes have been updated or added`} - + {`${changeSummary["deleted"]} nodes have been deleted`} @@ -228,14 +236,14 @@ export interface ValidationCheck { } export const ValidationChecks = (props: { - validationChecks: ValidationCheck[] + validationChecks: ValidationCheck[]; }) => { const { validationChecks } = props; const Icon: Record = { - "Pass": , - "Fail": , - "Not applicable": + Pass: , + Fail: , + "Not applicable": , }; return ( @@ -250,8 +258,27 @@ export const ValidationChecks = (props: { {Icon[check.status]} {check.title}} - secondary={{check.message}} + primary={ + + {check.title} + + } + secondary={ + + {check.message} + + } /> ))} @@ -259,4 +286,4 @@ export const ValidationChecks = (props: { ); -} +}; diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx index 346ce7146e..1b42dd65b0 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx @@ -13,21 +13,26 @@ import DialogActions from "@mui/material/DialogActions"; import DialogContent from "@mui/material/DialogContent"; import DialogTitle from "@mui/material/DialogTitle"; import Link from "@mui/material/Link"; +import { styled } from "@mui/material/styles"; import Tab, { tabClasses } from "@mui/material/Tab"; import Tabs from "@mui/material/Tabs"; import Tooltip from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; -import { styled } from "@mui/material/styles"; import { AxiosError } from "axios"; +import { formatLastPublishMessage } from "pages/FlowEditor/utils"; import React, { useState } from "react"; import { useAsync } from "react-use"; import Input from "ui/shared/Input"; -import { formatLastPublishMessage } from "pages/FlowEditor/utils"; import Questions from "../../../Preview/Questions"; import { useStore } from "../../lib/store"; import EditHistory from "./EditHistory"; -import { AlteredNode, AlteredNodesSummaryContent, ValidationCheck, ValidationChecks } from "./PublishDialog"; +import { + AlteredNode, + AlteredNodesSummaryContent, + ValidationCheck, + ValidationChecks, +} from "./PublishDialog"; type SidebarTabs = "PreviewBrowser" | "History"; @@ -174,7 +179,9 @@ const Sidebar: React.FC<{ const [lastPublishedTitle, setLastPublishedTitle] = useState( "This flow is not published yet", ); - const [validationChecks, setValidationChecks] = useState([]); + const [validationChecks, setValidationChecks] = useState( + [], + ); const [alteredNodes, setAlteredNodes] = useState(); const [dialogOpen, setDialogOpen] = useState(false); const [summary, setSummary] = useState(); @@ -189,9 +196,7 @@ const Sidebar: React.FC<{ setLastPublishedTitle("Checking for changes..."); const alteredFlow = await validateAndDiffFlow(flowId); setAlteredNodes( - alteredFlow?.data.alteredNodes - ? alteredFlow.data.alteredNodes - : [], + alteredFlow?.data.alteredNodes ? alteredFlow.data.alteredNodes : [], ); setLastPublishedTitle( alteredFlow?.data.alteredNodes @@ -201,9 +206,7 @@ const Sidebar: React.FC<{ setValidationChecks(alteredFlow?.data?.validationChecks); setDialogOpen(true); } catch (error) { - setLastPublishedTitle( - "Error checking for changes to publish", - ); + setLastPublishedTitle("Error checking for changes to publish"); if (error instanceof AxiosError) { alert(error.response?.data?.error); @@ -219,10 +222,7 @@ const Sidebar: React.FC<{ try { setDialogOpen(false); setLastPublishedTitle("Publishing changes..."); - const { alteredNodes, message } = await publishFlow( - flowId, - summary, - ); + const { alteredNodes, message } = await publishFlow(flowId, summary); setLastPublishedTitle( alteredNodes ? `Successfully published changes to ${alteredNodes.length} nodes` @@ -379,13 +379,17 @@ const Sidebar: React.FC<{ {alteredNodes?.length ? ( <> {`Preview these content changes in-service before publishing `} - + {`here (opens in a new tab).`} @@ -413,7 +417,12 @@ const Sidebar: React.FC<{ color="primary" variant="contained" onClick={handlePublish} - disabled={!alteredNodes || alteredNodes.length === 0 || validationChecks.filter((v) => v.status === "Fail").length > 0} + disabled={ + !alteredNodes || + alteredNodes.length === 0 || + validationChecks.filter((v) => v.status === "Fail").length > + 0 + } > PUBLISH diff --git a/editor.planx.uk/src/pages/FlowEditor/lib/store/preview.ts b/editor.planx.uk/src/pages/FlowEditor/lib/store/preview.ts index 97f437e533..be77eeeb9b 100644 --- a/editor.planx.uk/src/pages/FlowEditor/lib/store/preview.ts +++ b/editor.planx.uk/src/pages/FlowEditor/lib/store/preview.ts @@ -11,6 +11,7 @@ import { import { ComponentType as TYPES } from "@opensystemslab/planx-core/types"; import { FileList } from "@planx/components/FileUploadAndLabel/model"; import { SetValue } from "@planx/components/SetValue/model"; +import { handleSetValue } from "@planx/components/SetValue/utils"; import { sortIdsDepthFirst } from "@planx/graph"; import { logger } from "airbrake"; import { objectWithoutNullishValues } from "lib/objectHelpers"; @@ -29,7 +30,6 @@ import { ApplicationPath } from "./../../../../types"; import type { Store } from "."; import { NavigationStore } from "./navigation"; import type { SharedStore } from "./shared"; -import { handleSetValue } from "@planx/components/SetValue/utils"; const SUPPORTED_DECISION_TYPES = [TYPES.Checklist, TYPES.Question]; let memoizedPreviousCardId: string | undefined = undefined; @@ -902,4 +902,4 @@ export const removeNodesDependentOnPassport = ( return acc; }, [] as string[]); return { removedNodeIds, breadcrumbsWithoutPassportData: newBreadcrumbs }; -}; \ No newline at end of file +}; diff --git a/editor.planx.uk/src/pages/FlowEditor/utils.ts b/editor.planx.uk/src/pages/FlowEditor/utils.ts index ed3c5d0688..a9f28b54ee 100644 --- a/editor.planx.uk/src/pages/FlowEditor/utils.ts +++ b/editor.planx.uk/src/pages/FlowEditor/utils.ts @@ -9,7 +9,7 @@ export const formatLastEditDate = (date: string): string => { export const formatLastEditMessage = ( date: string, - actor?: { firstName: string; lastName: string } + actor?: { firstName: string; lastName: string }, ): string => { if (!actor) { return `Last edited ${formatLastEditDate(date)}`; diff --git a/editor.planx.uk/src/pages/PlatformAdminPanel.tsx b/editor.planx.uk/src/pages/PlatformAdminPanel.tsx index 30fcd5456b..540fc44abe 100644 --- a/editor.planx.uk/src/pages/PlatformAdminPanel.tsx +++ b/editor.planx.uk/src/pages/PlatformAdminPanel.tsx @@ -58,7 +58,7 @@ const TeamData: React.FC = ({ data }) => { const a4Endpoint = `${process.env.REACT_APP_API_URL}/gis/${data.slug}/article4-schema`; const fetcher = (url: string) => fetch(url).then((r) => r.json()); const { data: a4Check, isValidating } = useSWR( - () => data.slug ? a4Endpoint : null, + () => (data.slug ? a4Endpoint : null), fetcher, ); @@ -123,7 +123,13 @@ const TeamData: React.FC = ({ data }) => { <> {"Article 4s (API)"} - {!isValidating && a4Check?.status ? : } + + {!isValidating && a4Check?.status ? ( + + ) : ( + + )} + <> {"Reference code"} diff --git a/editor.planx.uk/src/pages/layout/PublicLayout.tsx b/editor.planx.uk/src/pages/layout/PublicLayout.tsx index bb854c417e..e3c63cd5fb 100644 --- a/editor.planx.uk/src/pages/layout/PublicLayout.tsx +++ b/editor.planx.uk/src/pages/layout/PublicLayout.tsx @@ -52,10 +52,10 @@ const PublicFooter: React.FC = () => { const globalFooterItems = globalSettings?.footerContent ? Object.entries(globalSettings?.footerContent).map(([slug, item]) => ({ - title: item.heading, - content: item.content, - href: makeHref(slug), - })) + title: item.heading, + content: item.content, + href: makeHref(slug), + })) : []; const footerItems = [...flowSettingsContent, ...globalFooterItems].filter( diff --git a/editor.planx.uk/src/themeOverrides.d.ts b/editor.planx.uk/src/themeOverrides.d.ts index 39704669b5..37b3bbbea0 100644 --- a/editor.planx.uk/src/themeOverrides.d.ts +++ b/editor.planx.uk/src/themeOverrides.d.ts @@ -1,8 +1,8 @@ import "@mui/material/Chip"; // eslint-disable-next-line no-restricted-imports import "@mui/material/styles/createPalette"; -import { RadioProps } from "@mui/material/Radio"; +import { RadioProps } from "@mui/material/Radio"; declare module "@mui/material/Chip" { interface ChipPropsVariantOverrides { diff --git a/editor.planx.uk/src/ui/shared/Checkbox.tsx b/editor.planx.uk/src/ui/shared/Checkbox.tsx index 297c1115d9..c3ba044fb5 100644 --- a/editor.planx.uk/src/ui/shared/Checkbox.tsx +++ b/editor.planx.uk/src/ui/shared/Checkbox.tsx @@ -47,10 +47,15 @@ export interface Props { id?: string; checked: boolean; onChange?: (event?: React.MouseEvent) => void; - inputProps?: React.InputHTMLAttributes + inputProps?: React.InputHTMLAttributes; } -export default function Checkbox({ id, checked, onChange, inputProps }: Props): FCReturn { +export default function Checkbox({ + id, + checked, + onChange, + inputProps, +}: Props): FCReturn { return ( onChange && onChange()}>