Skip to content

Commit

Permalink
Split out visible checklist and exclusive checklist option
Browse files Browse the repository at this point in the history
  • Loading branch information
jamdelion committed Dec 18, 2024
1 parent 7515cdd commit e2bd43c
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 216 deletions.
217 changes: 2 additions & 215 deletions editor.planx.uk/src/@planx/components/Checklist/Public/Public.tsx
Original file line number Diff line number Diff line change
@@ -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> = (props) => {
const autoAnswerableOptions = useStore(
Expand All @@ -56,186 +25,4 @@ const ChecklistComponent: React.FC<Props> = (props) => {
return <VisibleChecklist {...props} />;
};

const VisibleChecklist: React.FC<Props> = (props) => {
const {
description = "",
groupedOptions,
handleSubmit,
howMeasured,
info,
options,
policyRef,
text,
img,
previouslySubmittedData,
id,
} = props;

const formik = useFormik<{ checked: Array<string> }>({
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<Array<number>>(
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 (
<Card handleSubmit={formik.handleSubmit} isValid>
<CardHeader
title={text}
description={description}
info={info}
policyRef={policyRef}
howMeasured={howMeasured}
img={img}
/>
<FullWidthWrapper>
<ErrorWrapper error={getIn(formik.errors, "checked")} id={id}>
<Grid
container
spacing={layout === ChecklistLayout.Images ? 2 : 0}
component="fieldset"
>
<legend style={visuallyHidden}>{text}</legend>
<NonExclusiveChecklistItems
nonExclusiveOptions={nonExclusiveOptions}
layout={layout}
changeCheckbox={changeCheckbox}
formik={formik}
exclusiveOptionIsChecked={exclusiveOptionIsChecked}
/>

{exclusiveOrOption && (
<FormWrapper key={exclusiveOrOption.id}>
<Grid item xs={12} key={exclusiveOrOption.data.text}>
<Typography width={36} display="flex" justifyContent="center">
or
</Typography>

<ChecklistItem
onChange={changeCheckbox(exclusiveOrOption.id)}
label={exclusiveOrOption.data.text}
id={exclusiveOrOption.id}
checked={formik.values.checked.includes(
exclusiveOrOption.id
)}
/>
</Grid>
</FormWrapper>
)}

{groupedOptions && (
<FormWrapper>
<Grid item xs={12}>
<ExpandableList>
{groupedOptions.map((group, index) => {
const isExpanded = expandedGroups.includes(index);
return (
<ExpandableListItem
key={index}
expanded={isExpanded}
onToggle={() => {
setExpandedGroups((previous) =>
toggleInArray(index, previous)
);
}}
headingId={`group-${index}-heading`}
groupId={`group-${index}-content`}
title={group.title}
>
<Box
pt={0.5}
pb={2}
aria-labelledby={`group-${index}-heading`}
id={`group-${index}-content`}
data-testid={`group-${index}${
isExpanded ? "-expanded" : ""
}`}
>
{group.children.map((option) => (
<ChecklistItem
onChange={changeCheckbox(option.id)}
key={option.data.text}
label={option.data.text}
id={option.id}
checked={formik.values.checked.includes(
option.id
)}
/>
))}
</Box>
</ExpandableListItem>
);
})}
</ExpandableList>
</Grid>
</FormWrapper>
)}
</Grid>
</ErrorWrapper>
</FullWidthWrapper>
</Card>
);
};
export default ChecklistComponent;
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
Original file line number Diff line number Diff line change
@@ -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<string> }>;
}) => (
<FormWrapper key={exclusiveOrOption.id}>
<Grid item xs={12} key={exclusiveOrOption.data.text}>
<Typography width={36} display="flex" justifyContent="center">
or
</Typography>

<ChecklistItem
onChange={changeCheckbox(exclusiveOrOption.id)}
label={exclusiveOrOption.data.text}
id={exclusiveOrOption.id}
checked={formik.values.checked.includes(exclusiveOrOption.id)}
/>
</Grid>
</FormWrapper>
);
Loading

0 comments on commit e2bd43c

Please sign in to comment.