Skip to content

Commit

Permalink
130 Add modal to message about outdated data in CPE
Browse files Browse the repository at this point in the history
 - created advisory modal with copy and inline styling
 - added the modal to three pages:
  - landing page
  - capital project map page
  - capital projects table data page
 - added functionality to dismiss/close the modal
  • Loading branch information
horatiorosa committed Oct 9, 2024
1 parent 41cbd26 commit 63bd4d7
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 91 deletions.
56 changes: 49 additions & 7 deletions app/capitalprojects/LandingPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,74 @@ import { connect } from 'react-redux';
import { Link } from 'react-router';

import Footer from '../common/Footer';
import AdvisoryModal from '../common/AdvisoryModal';

import * as capitalProjectsActions from '../actions/capitalProjects';

import './LandingPage.scss';

class LandingPage extends React.Component {
constructor(props) {
super(props);
this.state = {
showModal: true,
};
}

componentWillMount() {
this.props.resetFilter();
document.addEventListener('keydown', this.handleEscKey);
}

componentWillUnmount() {
document.removeEventListener('keydown', this.handleEscKey);
}

handleClose = () => {
this.setState({ showModal: false });
};

handleEscKey = (event) => {
if (event.key === 'Escape') {
this.handleClose();
}
};

render() {
const { showModal } = this.state;

return (
<div className="capitalprojects-landing">
{showModal && <AdvisoryModal handleClose={this.handleClose} />}
<section className="header-area" id="about">
<div className="container">
<div className="row">
<div className="col-lg-10 col-lg-offset-1 text-center" style={{ background: '#777', padding: '40px' }}>
<div
className="col-lg-10 col-lg-offset-1 text-center"
style={{ background: '#777', padding: '40px' }}
>
<h1 className="section-heading">NYC Capital Projects</h1>
<p className="subtitle">A new way to explore NYC&apos;s Capital Commitment Plan and Capital Spending</p>
<p className="learn-more"><Link to="/about/capitalprojects">Learn More</Link></p>
<p className="subtitle">
A new way to explore NYC&apos;s Capital Commitment Plan and
Capital Spending
</p>
<p className="learn-more">
<Link to="/about/capitalprojects">Learn More</Link>
</p>
<div className="splash-button-section">
<div className="box all-link">
<Link
to="/capitalprojects/table"
className="btn btn-default"
>
<div className="vertical-align">Search the <br /> Capital Commitment Plan</div>
<div className="vertical-align">
Search the <br /> Capital Commitment Plan
</div>
</Link>
<div className="blurb">
Raw data for all capital projects within the most recent Capital Commitment Plan published by the Mayor’s Office of Management and Budget.
Raw data for all capital projects within the most recent
Capital Commitment Plan published by the Mayor&apos;s
Office of Management and Budget.
</div>
</div>

Expand All @@ -46,10 +84,14 @@ class LandingPage extends React.Component {
to="/capitalprojects/explorer"
className="btn btn-default"
>
<div className="vertical-align">Explore <br /> Capital Projects on a Map</div>
<div className="vertical-align">
Explore <br /> Capital Projects on a Map
</div>
</Link>
<div className="blurb">
Capital projects within the Capital Commitment Plan that NYC Planning has worked with agencies to map - a subset of total planned spending.
Capital projects within the Capital Commitment Plan that
NYC Planning has worked with agencies to map - a subset of
total planned spending.
</div>
</div>
</div>
Expand Down
47 changes: 47 additions & 0 deletions app/common/AdvisoryModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal } from 'react-bootstrap';

const AdvisoryModal = ({ handleClose }) => (
<Modal
show
onHide={handleClose}
style={{ top: '5em' }}
>
<Modal.Header
className="advisory-modal-header"
style={{ paddingTop: '45px' }}
/>

<Modal.Body>
<div style={{ margin: '0 3em', fontSize: '18px' }}>
The Capital Projects section of the Capital Planning Explorer is no
longer being updated with the latest data (the most recent data
available in this application are from April 2023). To download the
latest Capital Projects data, please refer to&nbsp;
<a href="https://data.cityofnewyork.us/City-Government/Capital-Projects-Database-CPDB-Projects/fi59-268w/about_data">
NYC Open Data
</a>
&nbsp;or&nbsp;
<a href="https://www.nyc.gov/site/planning/data-maps/open-data.page">
Bytes of the Big Apple
</a>
. Other sections of the Capital Planning Explorer are still being
actively updated, and we encourage you to stay tuned for future
enhancements to this platform.
</div>
</Modal.Body>

<Modal.Footer className="advisory-modal-footer">
<div className="btn dcp-orange" onClick={handleClose}>
Close
</div>
</Modal.Footer>
</Modal>
);

AdvisoryModal.propTypes = {
handleClose: PropTypes.func.isRequired,
};

export default AdvisoryModal;
2 changes: 1 addition & 1 deletion app/common/GlobalModal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
color: #d96b27;
}

.modal-body h5, {
.modal-body h5 {
font-family: 'Oswald';
font-size: 17px;
}
Expand Down
107 changes: 81 additions & 26 deletions app/explorer/Explorer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {

import appConfig from '../config/appConfig';

import AdvisoryModal from "../common/AdvisoryModal";

const { mapbox_accessToken, searchConfig } = appConfig;

const mapboxGLOptions = {
Expand All @@ -52,30 +54,46 @@ class Explorer extends React.Component {
inKilometers: 0,
centerPointCoordinates: [],
},
showModal: true,
};
this.selectedFeaturesCache = [];
this.mapClicked = false;
}

componentWillMount() {
document.addEventListener('keydown', this.handleEscKey);
}

componentWillReceiveProps(nextProps) {
if (!this.mapClicked && (this.props.map.centerOnGeometry !== nextProps.map.centerOnGeometry)) {
if (
!this.mapClicked &&
this.props.map.centerOnGeometry !== nextProps.map.centerOnGeometry
) {
this.centerFromGeometry(nextProps.map.centerOnGeometry);
this.setState({
selectedPointType: 'point',
selectedPointCoordinates: this.centroidFromGeometry(nextProps.map.centerOnGeometry),
highlightPointCoordinates: this.centroidFromGeometry(nextProps.map.centerOnGeometry),
selectedPointCoordinates: this.centroidFromGeometry(
nextProps.map.centerOnGeometry,
),
highlightPointCoordinates: this.centroidFromGeometry(
nextProps.map.centerOnGeometry,
),
});
}
}

componentWillUnmount() {
document.removeEventListener('keydown', this.handleEscKey);
}

onLayerToggle = (layerId, wasEnabled) => {
ReactGA4.gtag('event', 'toggle-layer', {
'action': `toggle-layer-${layerId}`,
'layer_view_value': !wasEnabled,
});
FS.event('capitalPlanningExplorerLayerToggle', {
layer_id: layerId,
layer_enabled: !wasEnabled
layer_enabled: !wasEnabled,
});

const janeLayerIdsMap = {
Expand All @@ -96,7 +114,7 @@ class Explorer extends React.Component {
}
});
}
}
};

// Nasty debounces cause I suck at async
setSelectedFeatures = _.debounce(() => {
Expand All @@ -114,7 +132,10 @@ class Explorer extends React.Component {
});
}

if (payload.action === 'clear' && this.state.selectedPointType === 'address') {
if (
payload.action === 'clear' &&
this.state.selectedPointType === 'address'
) {
this.setState({
selectedPointType: '',
selectedPointCoordinates: [],
Expand Down Expand Up @@ -152,7 +173,10 @@ class Explorer extends React.Component {
});
}

if (features[0].geometry.type === 'Polygon' || features[0].geometry.type === 'MultiPolygon') {
if (
features[0].geometry.type === 'Polygon' ||
features[0].geometry.type === 'MultiPolygon'
) {
this.setState({
selectedPointType: 'point',
selectedPointCoordinates: [event.lngLat.lng, event.lngLat.lat],
Expand All @@ -175,7 +199,7 @@ class Explorer extends React.Component {
centerPointCoordinates: this.state.selectedPointCoordinates,
},
});
}
};

clearSelectedFeatures = () => {
this.props.resetSelectedFeatures();
Expand All @@ -192,9 +216,10 @@ class Explorer extends React.Component {

this.props.resetSelectedFeatures();
this.props.router.push('/map');
}
};

layerIdsInSelectedFeatures = () => _.uniq(this.props.selectedFeatures.map(f => f.layer.id));
layerIdsInSelectedFeatures = () =>
_.uniq(this.props.selectedFeatures.map(f => f.layer.id));

featureRoute = (feature) => {
switch (feature.layer.source) {
Expand All @@ -213,7 +238,7 @@ class Explorer extends React.Component {
default:
return null;
}
}
};

centerMap = _.debounce((lnglat) => {
this.Jane.GLMap.map.easeTo({
Expand All @@ -223,16 +248,32 @@ class Explorer extends React.Component {
});
}, 50);

handleClose = () => {
this.setState({ showModal: false });
};

handleEscKey = (event) => {
if (event.key === "Escape") {
this.handleClose();
}
};

render() {
const setStartingLayer = () => {
if (this.props.children) {
switch (this.props.children.props.route.type) {
case 'capitalproject': return 'capitalprojects';
case 'facility': return 'facilities';
case 'pops': return 'pops';
case 'development': return 'housing';
case 'sca': return 'sca';
case 'budgetrequest': return 'budgetrequests';
case 'capitalproject':
return 'capitalprojects';
case 'facility':
return 'facilities';
case 'pops':
return 'pops';
case 'development':
return 'housing';
case 'sca':
return 'sca';
case 'budgetrequest':
return 'budgetrequests';
default:
return this.props.params.layer || 'capitalprojects';
}
Expand All @@ -244,16 +285,22 @@ class Explorer extends React.Component {
const startingLayer = setStartingLayer();

const popsLocationState = {
filterDimensions: getDefaultFilterDimensions({ selected: {
'Parks, Gardens, and Historical Sites': {
'Parks and Plazas': {
'Privately Owned Public Space': null },
filterDimensions: getDefaultFilterDimensions({
selected: {
'Parks, Gardens, and Historical Sites': {
'Parks and Plazas': {
'Privately Owned Public Space': null,
},
},
},
} }),
}),
};

const { showModal } = this.state;

return (
<div className="full-screen cp-explorer">
<div className='full-screen cp-explorer'>
{showModal && <AdvisoryModal handleClose={this.handleClose} />}
<Jane
mapboxGLOptions={mapboxGLOptions}
search
Expand All @@ -265,7 +312,9 @@ class Explorer extends React.Component {
selectedFeatures={selectedFeatures}
setBottomOffset={this.setBottomOffset}
onLayerToggle={this.onLayerToggle}
ref={(jane) => { this.Jane = jane; }}
ref={(jane) => {
this.Jane = jane;
}}
>
<HighlightJaneLayer
coordinates={this.state.highlightPointCoordinates}
Expand All @@ -288,8 +337,14 @@ class Explorer extends React.Component {
handleRadiusFilter={this.handleRadiusFilter}
sql={this.props.facilitiesSql}
enabled={startingLayer === 'facilities' || startingLayer === 'pops'}
selected={startingLayer === 'facilities' || startingLayer === 'pops'}
locationState={startingLayer === 'pops' ? popsLocationState : this.props.location.state}
selected={
startingLayer === 'facilities' || startingLayer === 'pops'
}
locationState={
startingLayer === 'pops'
? popsLocationState
: this.props.location.state
}
/>

<HousingDevelopmentJaneLayer
Expand Down
Loading

0 comments on commit 63bd4d7

Please sign in to comment.