diff --git a/src/actions/LandOwnershipActions.js b/src/actions/LandOwnershipActions.js index a33cdd3a..7b357af5 100644 --- a/src/actions/LandOwnershipActions.js +++ b/src/actions/LandOwnershipActions.js @@ -56,9 +56,29 @@ export const setProprietorName = (proprietorName) => { return { type: "SET_PROPRIETOR_NAME", payload: proprietorName, + } +}; + +export const setActivePropertyId = (propertyId) => { } + +export const setSelectedProperty = (property) => { + return (dispatch) => { + dispatch({ + type: "SET_SELECTED_PROPERTY", + payload: property, + }); }; }; +export const clearSelectedProperty = (property) => { + return (dispatch) => { + dispatch({ + type: "CLEAR_SELECTED_PROPERTY", + payload: property + }) + } +} + export const showPropertyPolygon = (propertyCoordinates) => { return (dispatch) => { dispatch({ diff --git a/src/components/left-pane/LeftPaneInfo.js b/src/components/left-pane/LeftPaneInfo.js index a2566974..e59a2913 100644 --- a/src/components/left-pane/LeftPaneInfo.js +++ b/src/components/left-pane/LeftPaneInfo.js @@ -4,6 +4,7 @@ import LeftPaneTray from "./LeftPaneTray"; import MarkerSection from "./MarkerSection"; import PolygonSection from "./PolygonSection"; import PropertySection from "./PropertySection"; +import RelatedPropertySection from "./RelatedPropertySection"; const LeftPaneInfo = ({ onClose, open }) => { const markers = useSelector((state) => state.markers.markers); @@ -11,10 +12,17 @@ const LeftPaneInfo = ({ onClose, open }) => { const properties = useSelector( (state) => state.landOwnership.highlightedProperties ); + const selectedProperties = useSelector( + (state) => state.relatedProperties.selectedProperty + ); + return ( - {polygons.length || markers.length || properties.length ? ( + {polygons.length || + markers.length || + properties.length || + selectedProperties.length > 0 ? ( <> {markers.map((marker, i) => ( @@ -25,6 +33,9 @@ const LeftPaneInfo = ({ onClose, open }) => { {properties.map((property, i) => ( ))} + {selectedProperties.map((property, i) => ( + + ))} ) : (
{ // Set loading state const loading = useSelector((state) => state.relatedProperties.loading); - const [activeProperty, setActiveProperty] = useState(null); + // Move to nested component - to allow multiple properties to be selected + // const [activeProperty, setActiveProperty] = useState(null); + // Use a Set to store unique properties const uniqueProperties = new Set(); @@ -36,10 +38,11 @@ const LeftPaneRelatedProperties = ({ onClose, open, itemsPerPage }) => { indexOfLastProperty ); + // Remove this function and move to nested component // Pass down the active property to the RelatedProperties component - const handlePropertyClick = (property) => { - setActiveProperty(property); - }; + // const handlePropertyClick = (property) => { + // setActiveProperty(property); + // }; return ( @@ -65,8 +68,8 @@ const LeftPaneRelatedProperties = ({ onClose, open, itemsPerPage }) => { handlePropertyClick(property)} + // isActive={property === activeProperty} + // onPropertyClick={() => handlePropertyClick(property)} /> ))} {noOfPages > 1 && ( diff --git a/src/components/left-pane/PropertySection.js b/src/components/left-pane/PropertySection.js index 366f6d90..167b57d9 100644 --- a/src/components/left-pane/PropertySection.js +++ b/src/components/left-pane/PropertySection.js @@ -48,8 +48,10 @@ const PropertySection = ({ property, active }) => { if (property.proprietor_name_1 === proprietorName) { dispatch({ type: "CLEAR_PROPERTIES_AND_PROPRIETOR_NAME" }); } + console.log("handleClear Property", property); }; + return (
{ +const RelatedProperties = ({ property }) => { const dispatch = useDispatch(); + const [active, setActive] = useState(false); + const { selectedProperty } = useSelector(state => state.relatedProperties); const lng = property.geom.coordinates[0][0][1]; const lat = property.geom.coordinates[0][0][0]; const handlePropertyClick = () => { - onPropertyClick(); - dispatch(showPropertyPolygon(property.geom.coordinates[0])); + const propertyIsSelected = selectedProperty.find(item => item[0].id === property.id); + + if (propertyIsSelected) + dispatch(clearSelectedProperty([property])); + else + dispatch(setSelectedProperty([property])); + + setActive(!active); }; const gotoProperty = () => { @@ -19,11 +30,10 @@ const RelatedProperties = ({ property, isActive, onPropertyClick }) => { } return
- + { /> -
+

{property.property_address}

diff --git a/src/components/left-pane/RelatedPropertySection.js b/src/components/left-pane/RelatedPropertySection.js new file mode 100644 index 00000000..ed1d9b0d --- /dev/null +++ b/src/components/left-pane/RelatedPropertySection.js @@ -0,0 +1,203 @@ +import React from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { setActiveProperty } from "../../actions/LandOwnershipActions"; +import Button from "../common/Button"; +import { getRelatedProperties } from "../../actions/LandOwnershipActions"; + +const RelatedPropertySection = ({ property, active }) => { + const dispatch = useDispatch(); + const activePropertyId = useSelector( + (state) => state.landOwnership.activePropertyId + ); + + const { + poly_id, + title_no, + proprietor_category_1, + property_address, + proprietor_name_1, + proprietor_1_address_1, + tenure, + date_proprietor_added, + } = property[0]; + + const open = poly_id === activePropertyId; + + const openTray = (tray) => { + active === tray + ? dispatch({ type: "CLOSE_TRAY" }) + : dispatch({ type: "SET_ACTIVE", payload: tray }); + }; + + const handleSearch = () => { + dispatch({ type: "CLEAR_PROPERTIES" }); + dispatch(getRelatedProperties(proprietor_name_1)); + openTray("Ownership Search"); + }; + + const handleClear = () => { + // dispatch({ type: "CLEAR_HIGHLIGHT", payload: property[0] }); + // Clear properties if the property being cleared is the searched property + // if (property.proprietor_name_1 === proprietorName) { + // dispatch({ type: "CLEAR_PROPERTIES_AND_PROPRIETOR_NAME" }); + // } + dispatch({ + type: "CLEAR_SELECTED_PROPERTY", + payload: activePropertyId, + }); + console.log("handleClear RelatedProperty", property[0]); + }; + + + return ( +
+
{ + if (open) { + dispatch({ type: "CLEAR_ACTIVE_PROPERTY" }); + } else { + dispatch(setActiveProperty(poly_id)); + } + }} + > +

+ Related Property {poly_id} +

+
+ +
+
+ {open && ( +
+ {proprietor_category_1 && ( + <> +
{property_address}
+
+
+ Proprietor Name: +
+
+ {proprietor_name_1} +
+
+
+
+ Proprietor Address: +
+
+ {proprietor_1_address_1} +
+
+
+
+
+ Proprietor Category: +
+
+ {proprietor_category_1} +
+
+
+
Tenure:
+
+ {tenure} +
+
+
+
+ Date Proprietor Added: +
+
+ {date_proprietor_added} +
+
+
+ + )} +
+
+
+ INSPIRE ID: +
+
{poly_id}
+
+
+
+ Title Number: +
+
{title_no}
+
+
+

+ You can access these documents for a small fee by visiting the{" "} + + Land Registry website + {" "} + using the above IDs. +

+
+
+ +
+ +
+
+ +
+
+ )} +
+ ); +}; + +export default RelatedPropertySection; diff --git a/src/components/map/MapProperties.js b/src/components/map/MapProperties.js index 7fd8953e..91e1c3e2 100644 --- a/src/components/map/MapProperties.js +++ b/src/components/map/MapProperties.js @@ -1,24 +1,35 @@ import React, { useState, useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; -import { Layer, Feature } from 'react-mapbox-gl'; +import { Layer, Feature } from "react-mapbox-gl"; import axios from "axios"; import constants from "../../constants"; import { getAuthHeader } from "../../utils/Auth"; import LoadingData from "./LoadingData"; -import { highlightProperty, setActiveProperty } from "../../actions/LandOwnershipActions"; +import { + highlightProperty, + setActiveProperty, +} from "../../actions/LandOwnershipActions"; const MapProperties = ({ center, map }) => { const [properties, setProperties] = useState([]); const [loadingProperties, setLoadingProperties] = useState(false); - const displayActive = useSelector(state => state.landOwnership.displayActive); - const zoom = useSelector(state => state.map.zoom); - const highlightedProperties = useSelector(state => state.landOwnership.highlightedProperties); - const activePropertyId = useSelector(state => state.landOwnership.activePropertyId); - const activeProperty = activePropertyId !== null ? highlightedProperties.find(p => p.poly_id === activePropertyId) : null; - + const displayActive = useSelector( + (state) => state.landOwnership.displayActive + ); + const zoom = useSelector((state) => state.map.zoom); + const highlightedProperties = useSelector( + (state) => state.landOwnership.highlightedProperties + ); + const activePropertyId = useSelector( + (state) => state.landOwnership.activePropertyId + ); + const activeProperty = + activePropertyId !== null + ? highlightedProperties.find((p) => p.poly_id === activePropertyId) + : null; - const activePanel = useSelector(state => state.leftPane.active); + const activePanel = useSelector((state) => state.leftPane.active); const dispatch = useDispatch(); @@ -27,9 +38,8 @@ const MapProperties = ({ center, map }) => { setLoadingProperties(true); - const response = await axios - .get( - `${constants.ROOT_URL}/api/ownership?sw_lng=` + + const response = await axios.get( + `${constants.ROOT_URL}/api/ownership?sw_lng=` + mapBoundaries._sw.lng + "&sw_lat=" + mapBoundaries._sw.lat + @@ -37,82 +47,93 @@ const MapProperties = ({ center, map }) => { mapBoundaries._ne.lng + "&ne_lat=" + mapBoundaries._ne.lat, - getAuthHeader() - ); + getAuthHeader() + ); const newProperties = response.data.map((property) => ({ ...property, - coordinates: property.geom.coordinates[0].map(coordinate => coordinate.reverse()) //mapbox wants [lng,lat] but db gives [lat,lng] + coordinates: property.geom.coordinates[0].map((coordinate) => + coordinate.reverse() + ), //mapbox wants [lng,lat] but db gives [lat,lng] })); - if (newProperties.length > 0) - setProperties(newProperties); + if (newProperties.length > 0) setProperties(newProperties); setLoadingProperties(false); - } + }; useEffect(() => { if (displayActive && zoom >= constants.PROPERTY_BOUNDARIES_ZOOM_LEVEL) getProperties(); - }, [center, map, zoom, displayActive]) + }, [center, map, zoom, displayActive]); const onClickNewProperty = (property) => { - if (activePanel !== 'Drawing Tools') { + if (activePanel !== "Drawing Tools") { dispatch(highlightProperty(property)); } - } + }; const onClickHighlightedProperty = (property) => { - if (activePanel !== 'Drawing Tools') { + if (activePanel !== "Drawing Tools") { dispatch(setActiveProperty(property.poly_id)); } - } + }; const detailedPropertyFeatures = []; const basicPropertyFeatures = []; - properties.forEach(property => { + properties.forEach((property) => { if (property.date_proprietor_added) - detailedPropertyFeatures.push( onClickNewProperty(property)} - />) + detailedPropertyFeatures.push( + onClickNewProperty(property)} + /> + ); else - basicPropertyFeatures.push( onClickNewProperty(property)} - />) + basicPropertyFeatures.push( + onClickNewProperty(property)} + /> + ); }); - const highlightedPropertyFeatures = highlightedProperties.map(highlightedProperty => - onClickHighlightedProperty(highlightedProperty)} - /> + const highlightedPropertyFeatures = highlightedProperties.map( + (highlightedProperty) => ( + onClickHighlightedProperty(highlightedProperty)} + /> + ) ); // Add another polygon for the active property so it appears darker if (activeProperty) { - highlightedPropertyFeatures.push(); + highlightedPropertyFeatures.push( + + ); } - return <> - { - displayActive && zoom >= constants.PROPERTY_BOUNDARIES_ZOOM_LEVEL && ( + return ( + <> + {displayActive && zoom >= constants.PROPERTY_BOUNDARIES_ZOOM_LEVEL && ( <> - {loadingProperties && } + {loadingProperties && ( + + )} {detailedPropertyFeatures} @@ -121,24 +142,25 @@ const MapProperties = ({ center, map }) => { type={"fill"} paint={{ "fill-opacity": 0.15, - "fill-color": 'orange', - "fill-outline-color": 'green', + "fill-color": "orange", + "fill-outline-color": "green", }} > {basicPropertyFeatures} - ) - } - - {highlightedPropertyFeatures} - - ; -} + )} + + {highlightedPropertyFeatures} + + + ); +}; export default MapProperties; diff --git a/src/components/map/MapboxMap.js b/src/components/map/MapboxMap.js index acc98869..de2ccf42 100644 --- a/src/components/map/MapboxMap.js +++ b/src/components/map/MapboxMap.js @@ -50,6 +50,7 @@ const MapboxMap = ({ user }) => { const propertyCoordinates = useSelector( (state) => state.propertySearchPoly.propertyCoordinates ); + const { selectedProperty } = useSelector(state => state.relatedProperties); // Check the propertyCoordinates update propagates to the MapboxMap component useEffect(() => { @@ -268,8 +269,8 @@ const MapboxMap = ({ user }) => { baseLayer === "aerial" ? "#091324" : constants.USE_OS_TILES - ? "#aadeef" - : "#72b6e6", + ? "#aadeef" + : "#72b6e6", }} zoom={zoom} onZoomEnd={(map) => dispatch(setZoom([map.getZoom()]))} @@ -299,7 +300,7 @@ const MapboxMap = ({ user }) => { }} /> {/* Property Search Poly / No clue where this should go */} - {propertyCoordinates.length > 0 && ( + {selectedProperty.length > 0 && ( )} {/*For displaying the property boundaries*/} diff --git a/src/components/map/PropertySearchPoly.js b/src/components/map/PropertySearchPoly.js index 12a9a839..4eef57f0 100644 --- a/src/components/map/PropertySearchPoly.js +++ b/src/components/map/PropertySearchPoly.js @@ -1,52 +1,48 @@ import React, { useEffect } from "react"; -import { useSelector } from "react-redux"; -import { GeoJSONLayer } from "react-mapbox-gl"; +import { useSelector, useDispatch } from "react-redux"; +import { Feature, Layer } from "react-mapbox-gl"; +import { setActiveProperty } from "../../actions/LandOwnershipActions"; -const PropertySearchPoly = ({ property }) => { - const propertyCoordinates = useSelector( - (state) => state.propertySearchPoly.propertyCoordinates - ); +const PropertySearchPoly = () => { + const dispatch = useDispatch(); - const polyId = useSelector((state) => state.propertySearchPoly.polyId); + const { selectedProperty } = useSelector(state => state.relatedProperties) - const polygonData = { - geometry: { - coordinates: [propertyCoordinates.map((coord) => [coord[1], coord[0]])], //mapbox expects coords as lng,lat - type: "Polygon", - }, - id: polyId, - properties: {}, - type: "Feature", - }; + console.log("prop", selectedProperty) - const polygonLayer = ( - - ); + const handlePolygonClick = (property) => { + dispatch(setActiveProperty(property.poly_id)); + console.log("Polygon clicked!", property.poly_id); + }; - useEffect(() => { - console.log("Property coordinates exist!", propertyCoordinates, polyId); - console.log("Polygon Layer", polygonLayer); - }, [propertyCoordinates, polyId]); + const polygonLayer = selectedProperty.map(property => [coord[1], coord[0]])]} + key={property[0].poly_id} + onClick={() => handlePolygonClick(property[0])} + />) // Check if propertyCoordinates exist before rendering GeoJSONLayer - if (!propertyCoordinates || propertyCoordinates.length === 0) { + if (!selectedProperty || selectedProperty.length === 0) { console.log("Property coordinates do not exist!"); return null; } - return <>{polygonLayer}; + console.log(polygonLayer) + + return ( + <> + + {polygonLayer} + + + ); }; export default PropertySearchPoly; diff --git a/src/reducers/RelatedPropertiesReducer.js b/src/reducers/RelatedPropertiesReducer.js index eb34c12a..39740aa2 100644 --- a/src/reducers/RelatedPropertiesReducer.js +++ b/src/reducers/RelatedPropertiesReducer.js @@ -3,8 +3,13 @@ const INITIAL_STATE = { error: null, loading: false, proprietorName: null, + activePropertyId: null, + selectedProperty: [], }; +let propertyToClear; +let selectedProperty; + export default (state = INITIAL_STATE, action) => { switch (action.type) { case "FETCH_PROPERTIES_SUCCESS": @@ -31,6 +36,20 @@ export default (state = INITIAL_STATE, action) => { ...state, properties: [], }; + case "SET_SELECTED_PROPERTY": + return { + ...state, + selectedProperty: [...state.selectedProperty, action.payload], + }; + case "CLEAR_SELECTED_PROPERTY": + propertyToClear = action.payload; + selectedProperty = state.selectedProperty.filter( + (property) => property[0].poly_id !== propertyToClear[0].poly_id + ); + return { + ...state, + selectedProperty, + }; case "SET_PROPRIETOR_NAME": return { ...state, @@ -45,7 +64,19 @@ export default (state = INITIAL_STATE, action) => { return { ...state, properties: [], - proprietorName: null, + proprietorName: null + }; + case "SET_ACTIVE_PROPERTY_ID": + return INITIAL_STATE; + case "SET_SELECTED_PROPERTY": + return { + ...state, + selectedProperty: [...state.selectedProperty, action.payload], + }; + case "CLEAR_ALL_SELECTED_PROPERTY": + return { + ...state, + selectedProperty: [], }; default: return state; diff --git a/src/reducers/ShowPropertyPolyReducer.js b/src/reducers/ShowPropertyPolyReducer.js index 0dcb402a..e0984131 100644 --- a/src/reducers/ShowPropertyPolyReducer.js +++ b/src/reducers/ShowPropertyPolyReducer.js @@ -1,6 +1,5 @@ const INITIAL_STATE = { propertyCoordinates: [], - polyId: null, }; export default (state = INITIAL_STATE, action) => { @@ -9,7 +8,6 @@ export default (state = INITIAL_STATE, action) => { return { ...state, propertyCoordinates: action.payload, - polyId: action.payload.poly_id, }; default: return state;