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

chore: optimise planning constraints requests #3740

Merged
merged 3 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import classifiedRoadsNegativeResponseMock from "./mocks/classifiedRoadsNegative
import classifiedRoadsResponseMock from "./mocks/classifiedRoadsResponseMock";
import digitalLandNegativeResponseMock from "./mocks/digitalLandNegativeResponseMock";
import digitalLandResponseMock from "./mocks/digitalLandResponseMock";
import Public, {
PlanningConstraintsContent,
PlanningConstraintsContentProps,
} from "./Public";
import { Presentational, PresentationalProps } from "./Presentational";
import Public from "./Public";

/**
* PlanningConstraints fetches data about constraints from DLUHC's planning.data.gov.uk & data about classified roads from the Ordnance Survey Features API.
Expand All @@ -27,7 +25,7 @@ export default {
component: Public,
} satisfies Meta<typeof Public>;

const propsWithIntersections: PlanningConstraintsContentProps = {
const propsWithIntersections: PresentationalProps = {
title: "Planning constraints",
description:
"Planning constraints might limit how you can develop or use the property",
Expand All @@ -48,7 +46,7 @@ const propsWithIntersections: PlanningConstraintsContentProps = {
setInaccurateConstraints: () => {},
};

const propsWithoutIntersections: PlanningConstraintsContentProps = {
const propsWithoutIntersections: PresentationalProps = {
title: "Planning constraints",
description:
"Planning constraints might limit how you can develop or use the property",
Expand All @@ -70,11 +68,11 @@ const propsWithoutIntersections: PlanningConstraintsContentProps = {
};

export const WithIntersections = {
render: () => <PlanningConstraintsContent {...propsWithIntersections} />,
render: () => <Presentational {...propsWithIntersections} />,
};

export const WithoutIntersections = {
render: () => <PlanningConstraintsContent {...propsWithoutIntersections} />,
render: () => <Presentational {...propsWithoutIntersections} />,
};

export const WithEditor = () => <Wrapper Editor={Editor} Public={Public} />;
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import ErrorOutline from "@mui/icons-material/ErrorOutline";
import Typography from "@mui/material/Typography";
import type { Constraint, GISResponse } from "@opensystemslab/planx-core/types";
import Card from "@planx/components/shared/Preview/Card";
import CardHeader from "@planx/components/shared/Preview/CardHeader";
import capitalize from "lodash/capitalize";
import { HandleSubmit } from "pages/Preview/Node";
import React from "react";
import ReactMarkdownOrHtml from "ui/shared/ReactMarkdownOrHtml";

import { ErrorSummaryContainer } from "../shared/Preview/ErrorSummaryContainer";
import SimpleExpand from "../shared/Preview/SimpleExpand";
import { WarningContainer } from "../shared/Preview/WarningContainer";
import ConstraintsList from "./List";
import { DEFAULT_PLANNING_CONDITIONS_DISCLAIMER } from "./model";
import { InaccurateConstraints } from "./Public";

export type PresentationalProps = {
title: string;
description: string;
fn: string;
disclaimer: string;
constraints: GISResponse["constraints"];
metadata: GISResponse["metadata"];
handleSubmit: () => void;
refreshConstraints: () => void;
inaccurateConstraints: InaccurateConstraints;
setInaccurateConstraints: (
value: React.SetStateAction<InaccurateConstraints>,
) => void;
};

export function Presentational(props: PresentationalProps) {
const {
title,
description,
constraints,
metadata,
disclaimer,
inaccurateConstraints,
setInaccurateConstraints,
} = props;

const error = constraints.error || undefined;
const showError = error || !Object.values(constraints)?.length;
if (showError) return <ConstraintsFetchError error={error} {...props} />;

const positiveConstraints = Object.values(constraints).filter(
(v: Constraint) => v.text && v.value,
);
const negativeConstraints = Object.values(constraints).filter(
(v: Constraint) => v.text && !v.value,
);

return (
<Card handleSubmit={props.handleSubmit}>
<CardHeader title={title} description={description} />
{positiveConstraints.length > 0 && (
<>
<Typography variant="h3" component="h2" mt={3}>
These are the planning constraints we think apply to this property
</Typography>
<ConstraintsList
data={positiveConstraints}
metadata={metadata}
inaccurateConstraints={inaccurateConstraints}
setInaccurateConstraints={setInaccurateConstraints}
/>
{negativeConstraints.length > 0 && (
<SimpleExpand
id="negative-constraints-list"
data-testid="negative-constraints-list"
buttonText={{
open: "Constraints that don't apply to this property",
closed: "Hide constraints that don't apply",
}}
>
<ConstraintsList
data={negativeConstraints}
metadata={metadata}
inaccurateConstraints={inaccurateConstraints}
setInaccurateConstraints={setInaccurateConstraints}
/>
</SimpleExpand>
)}
<Disclaimer text={disclaimer} />
</>
)}
{positiveConstraints.length === 0 && negativeConstraints.length > 0 && (
<>
<Typography variant="h3" component="h2" gutterBottom mt={3}>
It looks like there are no constraints on this property
</Typography>
<Typography variant="body1" gutterBottom>
Based on the information you've given it looks like there are no
planning constraints on your property that might limit what you can
do.
</Typography>
<Typography variant="body1" gutterBottom>
Continue with your application to tell us more about your project.
</Typography>
<SimpleExpand
id="negative-constraints-list"
buttonText={{
open: "Show the things we checked",
closed: "Hide constraints that don't apply",
}}
>
<ConstraintsList
data={negativeConstraints}
metadata={metadata}
inaccurateConstraints={inaccurateConstraints}
setInaccurateConstraints={setInaccurateConstraints}
/>
</SimpleExpand>
<Disclaimer text={disclaimer} />
</>
)}
</Card>
);
}

const Disclaimer = (props: { text: string }) => (
<WarningContainer>
<ErrorOutline />
<Typography variant="body1" component="div" ml={2} mb={1}>
<ReactMarkdownOrHtml
source={props.text || DEFAULT_PLANNING_CONDITIONS_DISCLAIMER}
openLinksOnNewTab
/>
</Typography>
</WarningContainer>
);

interface ConstraintsFetchErrorProps {
error: any;
title: string;
description: string;
refreshConstraints: () => void;
handleSubmit?: HandleSubmit;
}

const ConstraintsFetchError = (props: ConstraintsFetchErrorProps) => (
<Card handleSubmit={props.handleSubmit} isValid>
<CardHeader title={props.title} description={props.description} />
<ErrorSummaryContainer role="status" data-testid="error-summary-no-info">
<Typography variant="h4" component="h2" gutterBottom>
No information available
</Typography>
{props.error &&
typeof props.error === "string" &&
props.error.endsWith("local authority") ? (
<Typography variant="body2">{capitalize(props.error)}</Typography>
) : (
<>
<Typography variant="body2">
We couldn't find any information about your property. Click search
again to try again. You can continue your application without this
information but it might mean we ask additional questions about your
project.
</Typography>
<button onClick={props.refreshConstraints}>Search again</button>
</>
)}
</ErrorSummaryContainer>
</Card>
);
Loading
Loading