From e2bd43caec029760d7a1f63f04973fd0bee78fbb Mon Sep 17 00:00:00 2001 From: Jo Humphrey <31373245+jamdelion@users.noreply.github.com> Date: Wed, 18 Dec 2024 12:36:56 +0000 Subject: [PATCH] Split out visible checklist and exclusive checklist option --- .../components/Checklist/Public/Public.tsx | 217 +----------------- .../Public/components/ChecklistItems.tsx | 2 +- .../components/ExclusiveChecklistItem.tsx | 33 +++ .../Public/components/VisibleChecklist.tsx | 206 +++++++++++++++++ 4 files changed, 242 insertions(+), 216 deletions(-) create mode 100644 editor.planx.uk/src/@planx/components/Checklist/Public/components/ExclusiveChecklistItem.tsx create mode 100644 editor.planx.uk/src/@planx/components/Checklist/Public/components/VisibleChecklist.tsx diff --git a/editor.planx.uk/src/@planx/components/Checklist/Public/Public.tsx b/editor.planx.uk/src/@planx/components/Checklist/Public/Public.tsx index c0e786806e..fa60443d44 100644 --- a/editor.planx.uk/src/@planx/components/Checklist/Public/Public.tsx +++ b/editor.planx.uk/src/@planx/components/Checklist/Public/Public.tsx @@ -1,40 +1,9 @@ -import Box from "@mui/material/Box"; -import Grid from "@mui/material/Grid"; -import Typography from "@mui/material/Typography"; -import { visuallyHidden } from "@mui/utils"; -import { - checklistValidationSchema, - getFlatOptions, - getLayout, -} from "@planx/components/Checklist/model"; -import Card from "@planx/components/shared/Preview/Card"; -import { CardHeader } from "@planx/components/shared/Preview/CardHeader/CardHeader"; -import { getIn, useFormik } from "formik"; -import { partition } from "lodash"; import { useStore } from "pages/FlowEditor/lib/store"; -import React, { useState } from "react"; -import { ExpandableList, ExpandableListItem } from "ui/public/ExpandableList"; -import FormWrapper from "ui/public/FormWrapper"; -import FullWidthWrapper from "ui/public/FullWidthWrapper"; -import ChecklistItem from "ui/shared/ChecklistItem/ChecklistItem"; -import ErrorWrapper from "ui/shared/ErrorWrapper"; -import { object } from "yup"; +import React from "react"; -import { Option } from "../../shared"; import { Props } from "../types"; import { AutoAnsweredChecklist } from "./components/AutoAnsweredChecklist"; -import { NonExclusiveChecklistItems } from "./components/ChecklistItems"; -import { - getInitialExpandedGroups, - toggleInArray, - toggleNonExclusiveCheckbox, -} from "./helpers"; - -export enum ChecklistLayout { - Basic, - Grouped, - Images, -} +import { VisibleChecklist } from "./components/VisibleChecklist"; const ChecklistComponent: React.FC = (props) => { const autoAnswerableOptions = useStore( @@ -56,186 +25,4 @@ const ChecklistComponent: React.FC = (props) => { return ; }; -const VisibleChecklist: React.FC = (props) => { - const { - description = "", - groupedOptions, - handleSubmit, - howMeasured, - info, - options, - policyRef, - text, - img, - previouslySubmittedData, - id, - } = props; - - const formik = useFormik<{ checked: Array }>({ - initialValues: { - checked: previouslySubmittedData?.answers || [], - }, - onSubmit: (values) => { - handleSubmit?.({ answers: values.checked }); - }, - validateOnBlur: false, - validateOnChange: false, - validationSchema: object({ - checked: checklistValidationSchema(props), - }), - }); - - const setCheckedFieldValue = (optionIds: string[]) => { - const sortedCheckedIds = sortCheckedIds(optionIds); - formik.setFieldValue("checked", sortedCheckedIds); - }; - - const initialExpandedGroups = getInitialExpandedGroups( - groupedOptions, - previouslySubmittedData - ); - - const [expandedGroups, setExpandedGroups] = useState>( - initialExpandedGroups - ); - - const layout = getLayout({ options, groupedOptions }); - const flatOptions = getFlatOptions({ options, groupedOptions }); - - const sortCheckedIds = (ids: string[]): string[] => { - const originalIds = flatOptions.map((cb) => cb.id); - return ids.sort((a, b) => originalIds.indexOf(a) - originalIds.indexOf(b)); - }; - - const [exclusiveOptions, nonExclusiveOptions]: Option[][] = partition( - options, - (option) => option.data.exclusive - ); - - const exclusiveOrOption = exclusiveOptions[0]; - - const exclusiveOptionIsChecked = - exclusiveOrOption && formik.values.checked.includes(exclusiveOrOption.id); - - const toggleExclusiveCheckbox = (checkboxId: string) => { - return exclusiveOptionIsChecked ? [] : [checkboxId]; - }; - - const changeCheckbox = (id: string) => () => { - const currentCheckedIds = formik.values.checked; - - const currentCheckboxIsExclusiveOption = - exclusiveOrOption && id === exclusiveOrOption.id; - - if (currentCheckboxIsExclusiveOption) { - const newCheckedIds = toggleExclusiveCheckbox(id); - setCheckedFieldValue(newCheckedIds); - return; - } - const newCheckedIds = toggleNonExclusiveCheckbox( - id, - currentCheckedIds, - exclusiveOrOption - ); - setCheckedFieldValue(newCheckedIds); - }; - - return ( - - - - - - {text} - - - {exclusiveOrOption && ( - - - - or - - - - - - )} - - {groupedOptions && ( - - - - {groupedOptions.map((group, index) => { - const isExpanded = expandedGroups.includes(index); - return ( - { - setExpandedGroups((previous) => - toggleInArray(index, previous) - ); - }} - headingId={`group-${index}-heading`} - groupId={`group-${index}-content`} - title={group.title} - > - - {group.children.map((option) => ( - - ))} - - - ); - })} - - - - )} - - - - - ); -}; export default ChecklistComponent; diff --git a/editor.planx.uk/src/@planx/components/Checklist/Public/components/ChecklistItems.tsx b/editor.planx.uk/src/@planx/components/Checklist/Public/components/ChecklistItems.tsx index 146edbd5f8..c1cfceba88 100644 --- a/editor.planx.uk/src/@planx/components/Checklist/Public/components/ChecklistItems.tsx +++ b/editor.planx.uk/src/@planx/components/Checklist/Public/components/ChecklistItems.tsx @@ -6,7 +6,7 @@ import React from "react"; import FormWrapper from "ui/public/FormWrapper"; import ChecklistItem from "ui/shared/ChecklistItem/ChecklistItem"; -import { ChecklistLayout } from "./../Public"; +import { ChecklistLayout } from "./VisibleChecklist"; interface NonExclusiveChecklistItemsProps { nonExclusiveOptions: Option[]; diff --git a/editor.planx.uk/src/@planx/components/Checklist/Public/components/ExclusiveChecklistItem.tsx b/editor.planx.uk/src/@planx/components/Checklist/Public/components/ExclusiveChecklistItem.tsx new file mode 100644 index 0000000000..8a12291e51 --- /dev/null +++ b/editor.planx.uk/src/@planx/components/Checklist/Public/components/ExclusiveChecklistItem.tsx @@ -0,0 +1,33 @@ +import Grid from "@mui/material/Grid"; +import Typography from "@mui/material/Typography"; +import { FormikProps } from "formik"; +import React from "react"; +import FormWrapper from "ui/public/FormWrapper"; +import ChecklistItem from "ui/shared/ChecklistItem/ChecklistItem"; + +import { Option } from "../../../shared"; + +export const ExclusiveChecklistItem = ({ + exclusiveOrOption, + changeCheckbox, + formik, +}: { + exclusiveOrOption: Option; + changeCheckbox: (id: string) => () => void; + formik: FormikProps<{ checked: Array }>; +}) => ( + + + + or + + + + + +); diff --git a/editor.planx.uk/src/@planx/components/Checklist/Public/components/VisibleChecklist.tsx b/editor.planx.uk/src/@planx/components/Checklist/Public/components/VisibleChecklist.tsx new file mode 100644 index 0000000000..8f404967b8 --- /dev/null +++ b/editor.planx.uk/src/@planx/components/Checklist/Public/components/VisibleChecklist.tsx @@ -0,0 +1,206 @@ +import Box from "@mui/material/Box"; +import Grid from "@mui/material/Grid"; +import { visuallyHidden } from "@mui/utils"; +import { + checklistValidationSchema, + getFlatOptions, + getLayout, +} from "@planx/components/Checklist/model"; +import Card from "@planx/components/shared/Preview/Card"; +import { CardHeader } from "@planx/components/shared/Preview/CardHeader/CardHeader"; +import { getIn, useFormik } from "formik"; +import { partition } from "lodash"; +import React, { useState } from "react"; +import { ExpandableList, ExpandableListItem } from "ui/public/ExpandableList"; +import FormWrapper from "ui/public/FormWrapper"; +import FullWidthWrapper from "ui/public/FullWidthWrapper"; +import ChecklistItem from "ui/shared/ChecklistItem/ChecklistItem"; +import ErrorWrapper from "ui/shared/ErrorWrapper"; +import { object } from "yup"; + +import { Option } from "../../../shared"; +import { Props } from "../../types"; +import { NonExclusiveChecklistItems } from "./../components/ChecklistItems"; +import { ExclusiveChecklistItem } from "./../components/ExclusiveChecklistItem"; +import { + getInitialExpandedGroups, + toggleInArray, + toggleNonExclusiveCheckbox, +} from "./../helpers"; + +export enum ChecklistLayout { + Basic, + Grouped, + Images, +} + +export const VisibleChecklist: React.FC = (props) => { + const { + description = "", + groupedOptions, + handleSubmit, + howMeasured, + info, + options, + policyRef, + text, + img, + previouslySubmittedData, + id, + } = props; + + const formik = useFormik<{ checked: Array }>({ + initialValues: { + checked: previouslySubmittedData?.answers || [], + }, + onSubmit: (values) => { + handleSubmit?.({ answers: values.checked }); + }, + validateOnBlur: false, + validateOnChange: false, + validationSchema: object({ + checked: checklistValidationSchema(props), + }), + }); + + const setCheckedFieldValue = (optionIds: string[]) => { + const sortedCheckedIds = sortCheckedIds(optionIds); + formik.setFieldValue("checked", sortedCheckedIds); + }; + + const initialExpandedGroups = getInitialExpandedGroups( + groupedOptions, + previouslySubmittedData + ); + + const [expandedGroups, setExpandedGroups] = useState>( + initialExpandedGroups + ); + + const layout = getLayout({ options, groupedOptions }); + const flatOptions = getFlatOptions({ options, groupedOptions }); + + const sortCheckedIds = (ids: string[]): string[] => { + const originalIds = flatOptions.map((cb) => cb.id); + return ids.sort((a, b) => originalIds.indexOf(a) - originalIds.indexOf(b)); + }; + + const [exclusiveOptions, nonExclusiveOptions]: Option[][] = partition( + options, + (option) => option.data.exclusive + ); + + const exclusiveOrOption = exclusiveOptions[0]; + + const exclusiveOptionIsChecked = + exclusiveOrOption && formik.values.checked.includes(exclusiveOrOption.id); + + const toggleExclusiveCheckbox = (checkboxId: string) => { + return exclusiveOptionIsChecked ? [] : [checkboxId]; + }; + + const changeCheckbox = (id: string) => () => { + const currentCheckedIds = formik.values.checked; + + const currentCheckboxIsExclusiveOption = + exclusiveOrOption && id === exclusiveOrOption.id; + + if (currentCheckboxIsExclusiveOption) { + const newCheckedIds = toggleExclusiveCheckbox(id); + setCheckedFieldValue(newCheckedIds); + return; + } + const newCheckedIds = toggleNonExclusiveCheckbox( + id, + currentCheckedIds, + exclusiveOrOption + ); + setCheckedFieldValue(newCheckedIds); + }; + + return ( + + + + + + {text} + + {exclusiveOrOption && ( + + )} + + {groupedOptions && ( + + + + {groupedOptions.map((group, index) => { + const isExpanded = expandedGroups.includes(index); + return ( + { + setExpandedGroups((previous) => + toggleInArray(index, previous) + ); + }} + headingId={`group-${index}-heading`} + groupId={`group-${index}-content`} + title={group.title} + > + + {group.children.map((option) => ( + + ))} + + + ); + })} + + + + )} + + + + + ); +};