diff --git a/editor.planx.uk/src/@planx/components/PlanningConstraints/List.tsx b/editor.planx.uk/src/@planx/components/PlanningConstraints/List.tsx index 4169ecb00a..4566db3326 100644 --- a/editor.planx.uk/src/@planx/components/PlanningConstraints/List.tsx +++ b/editor.planx.uk/src/@planx/components/PlanningConstraints/List.tsx @@ -8,6 +8,7 @@ import ListItem from "@mui/material/ListItem"; import ListSubheader from "@mui/material/ListSubheader"; import { styled } from "@mui/material/styles"; import Typography from "@mui/material/Typography"; +import visuallyHidden from "@mui/utils/visuallyHidden"; import type { Constraint, GISResponse, @@ -19,6 +20,7 @@ import ReactHtmlParser from "react-html-parser"; import { FONT_WEIGHT_SEMI_BOLD } from "theme"; import Caret from "ui/icons/Caret"; import ReactMarkdownOrHtml from "ui/shared/ReactMarkdownOrHtml"; +import { parse } from "wkt"; const CATEGORY_COLORS: Record = { "General policy": "#99C1DE", @@ -64,11 +66,13 @@ const StyledAccordion = styled(Accordion, { interface ConstraintsListProps { data: Constraint[]; metadata: GISResponse["metadata"]; + site: string; } export default function ConstraintsList({ data, metadata, + site, }: ConstraintsListProps) { const groupedConstraints = groupBy(data, (constraint: Constraint) => { return constraint.category; @@ -112,6 +116,7 @@ export default function ConstraintsList({ content={con.text} data={con.value ? con.data : null} metadata={metadata?.[con.fn]} + site={site} category={category} > {metadata?.[con.fn]?.plural || ReactHtmlParser(con.text)} @@ -130,6 +135,7 @@ interface ConstraintListItemProps { content: string; data: Constraint["data"] | null; metadata?: Metadata; + site: string; category: string; children: ReactNode; } @@ -163,40 +169,47 @@ function ConstraintListItem({ children, ...props }: ConstraintListItemProps) { {`This property ${props?.content}`} {Boolean(props.data?.length) && ( - - {props.data && - props.data.map( - (record: any) => - record.name && ( - - - {record.name}{" "} - {record.name && record["documentation-url"] && ( - - ( - - source - - ) - - )} - - - ), - )} - + <> + + {props.data && + props.data.map( + (record: any) => + record.name && ( + + + {record.name}{" "} + {record.name && record["documentation-url"] && ( + + ( + + source + + ) + + )} + + + ), + )} + + + )} @@ -213,3 +226,54 @@ function ConstraintListItem({ children, ...props }: ConstraintListItemProps) { ); } + +interface ConstraintMapProps { + data: Constraint["data"] | null; + site: string; + category: string; +} + +function ConstraintMap({ ...props }: ConstraintMapProps) { + const geojson = { type: "FeatureCollection", features: [] }; + + // Add constraints as features (can be > 1 per dataset) + props.data?.map((record: any) => { + if (record?.geometry) { + const constraintsGeojson = parse(record.geometry); + geojson.features.push({ + type: "Feature", + properties: { color: "#2c2c2c" }, // TODO category color (very pale)? team theme color? + geometry: constraintsGeojson, + } as never); + } + // TODO `record.geometry` is a Planning Data thing, what about classified roads?? + }); + + // Add site boundary or point as top-most feature in red + const siteGeojson = parse(props.site); + geojson.features.push({ + type: "Feature", + properties: { color: "#ff0000" }, + geometry: siteGeojson, + } as never); + + return ( + <> +

+ A static map displaying this constraint in relation to your site. +

+ {/* @ts-ignore */} + + + ); +} diff --git a/editor.planx.uk/src/@planx/components/PlanningConstraints/PlanningConstraints.stories.tsx b/editor.planx.uk/src/@planx/components/PlanningConstraints/PlanningConstraints.stories.tsx index 5a6ad4da1c..7245c871ea 100644 --- a/editor.planx.uk/src/@planx/components/PlanningConstraints/PlanningConstraints.stories.tsx +++ b/editor.planx.uk/src/@planx/components/PlanningConstraints/PlanningConstraints.stories.tsx @@ -42,6 +42,7 @@ const propsWithIntersections: PlanningConstraintsContentProps = { ...digitalLandResponseMock["metadata"], ...classifiedRoadsResponseMock["metadata"], }, + site: "WKT(test)", handleSubmit: () => {}, refreshConstraints: () => {}, }; @@ -61,6 +62,7 @@ const propsWithoutIntersections: PlanningConstraintsContentProps = { ...digitalLandNegativeResponseMock["metadata"], ...classifiedRoadsNegativeResponseMock["metadata"], }, + site: "WKT(test)", handleSubmit: () => {}, refreshConstraints: () => {}, }; diff --git a/editor.planx.uk/src/@planx/components/PlanningConstraints/Public.tsx b/editor.planx.uk/src/@planx/components/PlanningConstraints/Public.tsx index 5a857226ae..8009bbfbdb 100644 --- a/editor.planx.uk/src/@planx/components/PlanningConstraints/Public.tsx +++ b/editor.planx.uk/src/@planx/components/PlanningConstraints/Public.tsx @@ -135,6 +135,7 @@ function Component(props: Props) { disclaimer={props.disclaimer} constraints={constraints} metadata={metadata} + site={wktPolygon || wktPoint} handleSubmit={() => { const _constraints: Array< EnhancedGISResponse | GISResponse["constraints"] @@ -198,6 +199,7 @@ export type PlanningConstraintsContentProps = { disclaimer: string; constraints: GISResponse["constraints"]; metadata: GISResponse["metadata"]; + site: string; handleSubmit: () => void; refreshConstraints: () => void; }; @@ -210,6 +212,7 @@ export function PlanningConstraintsContent( description, constraints, metadata, + site, refreshConstraints, disclaimer, } = props; @@ -238,7 +241,11 @@ export function PlanningConstraintsContent( These are the planning constraints we think apply to this property - + {negativeConstraints.length > 0 && ( - + )} @@ -275,7 +286,11 @@ export function PlanningConstraintsContent( closed: "Hide constraints that don't apply", }} > - +