-
diff --git a/frontend/src/components/Public/CrossingListItem/PublicCrossingListItem.js b/frontend/src/components/Public/CrossingListItem/PublicCrossingListItem.js
index 180653b0..23a03537 100644
--- a/frontend/src/components/Public/CrossingListItem/PublicCrossingListItem.js
+++ b/frontend/src/components/Public/CrossingListItem/PublicCrossingListItem.js
@@ -55,7 +55,7 @@ class PublicCrossingListItem extends React.Component {
- Status: {statusConstants.strings[crossing.latestStatusId]}
+ Status: {statusConstants.statusNames[crossing.latestStatusId]}
diff --git a/frontend/src/components/Shared/CrossingMapPage/CrossingMapPage.js b/frontend/src/components/Shared/CrossingMapPage/CrossingMapPage.js
index 41fc80ef..d26627ca 100644
--- a/frontend/src/components/Shared/CrossingMapPage/CrossingMapPage.js
+++ b/frontend/src/components/Shared/CrossingMapPage/CrossingMapPage.js
@@ -23,28 +23,13 @@ class CrossingMapPage extends Component {
super(props);
// If we have a current user, we're on the dashboard, we should get their viewport
- const envelope = this.props.currentUser
- ? JSON.parse(
- this.props.currentUser.communityByCommunityId.viewportgeojson,
- )
- : JSON.parse(
- `{"type":"Polygon","coordinates":[[[-98.086914,30.148464],[-98.086914,30.433285],[-97.615974,30.433285],[-97.615974,30.148464],[-98.086914,30.148464]]]}`,
- );
-
- // I actually like doing the padding here because it keeps the data/view separation
- const viewport = [
- [
- Math.min(...envelope.coordinates[0].map(arr => arr[0])) - 0.1,
- Math.min(...envelope.coordinates[0].map(arr => arr[1])) - 0.1,
- ],
- [
- Math.max(...envelope.coordinates[0].map(arr => arr[0])) + 0.1,
- Math.max(...envelope.coordinates[0].map(arr => arr[1])) + 0.1,
- ],
- ];
+ const viewportgeojson = this.props.currentUser
+ ? this.props.currentUser.communityByCommunityId.viewportgeojson
+ : `{"type":"Polygon","coordinates":[[[-98.086914,30.148464],[-98.086914,30.433285],[-97.615974,30.433285],[-97.615974,30.148464],[-98.086914,30.148464]]]}`;
+
+ const viewportAndCenter = this.getViewportAndCenter(viewportgeojson);
this.state = {
- viewport: viewport,
selectedCrossingId: null,
selectedCrossingStatus: null,
fullscreen: false,
@@ -55,9 +40,39 @@ class CrossingMapPage extends Component {
showCaution: true,
showLongterm: true,
visibleCrossings: [],
+ selectedLocationCoordinates: null,
+ selectedCommunity: null,
+ viewport: viewportAndCenter.viewport,
+ center: viewportAndCenter.center,
+ mapCenter: viewportAndCenter.center,
};
}
+ getViewportAndCenter = viewportgeojson => {
+ const envelope = JSON.parse(viewportgeojson);
+
+ const viewport = [
+ [
+ Math.min(...envelope.coordinates[0].map(arr => arr[0])) - 0.1,
+ Math.min(...envelope.coordinates[0].map(arr => arr[1])) - 0.1,
+ ],
+ [
+ Math.max(...envelope.coordinates[0].map(arr => arr[0])) + 0.1,
+ Math.max(...envelope.coordinates[0].map(arr => arr[1])) + 0.1,
+ ],
+ ];
+
+ const center = {
+ lng: (viewport[0][0] + viewport[1][0]) / 2,
+ lat: (viewport[0][1] + viewport[1][1]) / 2,
+ };
+
+ return {
+ viewport: viewport,
+ center: center,
+ };
+ };
+
formatSearchQuery(query) {
return `%${query.replace(/ /g, '%')}%`;
}
@@ -98,15 +113,40 @@ class CrossingMapPage extends Component {
this.setState({ showLongterm: !this.state.showLongterm });
};
+ getMapCenter = center => {
+ this.setState({ mapCenter: center });
+ };
+
+ setSelectedLocationCoordinates = coordinates => {
+ this.setState({ selectedLocationCoordinates: coordinates });
+ };
+
+ setSelectedCommunity = community => {
+ this.setState({ selectedCommunity: community });
+ if (community && community.viewportgeojson) {
+ const viewportAndCenter = this.getViewportAndCenter(
+ community.viewportgeojson,
+ );
+ this.setState({
+ viewport: viewportAndCenter.viewport,
+ center: viewportAndCenter.center,
+ mapCenter: viewportAndCenter.mapCenter,
+ });
+ }
+ };
+
render() {
const {
viewport,
+ mapCenter,
selectedCrossingId,
selectedCrossingStatus,
searchQuery,
formattedSearchQuery,
visibleCrossings,
selectedCrossingName,
+ selectedLocationCoordinates,
+ selectedCommunity,
} = this.state;
const { currentUser } = this.props;
const allCommunities =
@@ -132,6 +172,7 @@ class CrossingMapPage extends Component {
searchQuery={searchQuery}
searchQueryUpdated={this.searchQueryUpdated}
selectedCrossingName={selectedCrossingName}
+ setSelectedCommunity={this.setSelectedCommunity}
/>
)}
{params.fullsize && (
@@ -162,6 +203,11 @@ class CrossingMapPage extends Component {
toggleShowLongterm={this.toggleShowLongterm}
visibleCrossings={visibleCrossings}
allCommunities={allCommunities}
+ center={mapCenter}
+ setSelectedLocationCoordinates={
+ this.setSelectedLocationCoordinates
+ }
+ setSelectedCommunity={this.setSelectedCommunity}
/>
)}
{!params.fullsize &&
@@ -211,6 +262,7 @@ const allCommunities = gql`
nodes {
id
name
+ viewportgeojson
}
}
}
diff --git a/frontend/src/components/Shared/CrossingMapPage/CrossingMapSearchBar.js b/frontend/src/components/Shared/CrossingMapPage/CrossingMapSearchBar.js
index cf583672..49e7298a 100644
--- a/frontend/src/components/Shared/CrossingMapPage/CrossingMapSearchBar.js
+++ b/frontend/src/components/Shared/CrossingMapPage/CrossingMapSearchBar.js
@@ -1,50 +1,261 @@
import React, { Component } from 'react';
import 'components/Shared/CrossingMapPage/CrossingMapSearchBar.css';
import FontAwesome from 'react-fontawesome';
+import Autosuggest from 'react-autosuggest';
+import MapboxClient from 'mapbox';
+import CrossingMapSearchCrossingSuggestions from 'components/Shared/CrossingMapPage/CrossingMapSearchCrossingSuggestions';
+
+const mapboxClient = new MapboxClient(
+ 'pk.eyJ1IjoiY3Jvd2VhdHgiLCJhIjoiY2o1NDFvYmxkMHhkcDMycDF2a3pseDFpZiJ9.UcnizcFDleMpv5Vbv8Rngw',
+);
+
+// When suggestion is clicked, Autosuggest needs to populate the input
+// based on the clicked suggestion. Teach Autosuggest how to calculate the
+// input value for every given suggestion.
+const getSuggestionValue = suggestion => {
+ return suggestion.place_name || suggestion.name;
+};
+
+// Use your imagination to render suggestions.
+const Suggestion = suggestion => (
+
+
+ {suggestion.__typename === 'Crossing' && (
+
+ )}
+ {suggestion.__typename === 'Community' && (
+
+ )}
+ {suggestion.type === 'Feature' && (
+
+ )}
+
+
+ {suggestion.place_name || suggestion.name}
+
+
+);
+
+const renderSectionTitle = section => {
+ return null;
+};
+
+const getSectionSuggestions = section => {
+ return section.suggestions;
+};
+
+const formatSearchQuery = query => {
+ return `%${query.replace(/ /g, '%')}%`;
+};
class CrossingMapSearchBar extends Component {
+ constructor() {
+ super();
+
+ let autosuggestInput;
+
+ this.state = {
+ typedValue: '',
+ selectedValue: '',
+ mapboxSuggestions: [],
+ crossingSuggestions: [],
+ communitySuggestions: [],
+ };
+ }
+
+ onChange = (event, { newValue, method }) => {
+ if (method === 'type') {
+ this.setState({
+ typedValue: newValue,
+ selectedValue: null,
+ });
+ } else if (method === 'escape') {
+ this.setState({
+ selectedValue: null,
+ });
+ } else if (method === 'enter' || method === 'click') {
+ this.setState({
+ selectedValue: newValue,
+ typedValue: newValue,
+ });
+ } else if (method === 'down' || method === 'up') {
+ this.setState({
+ selectedValue: newValue,
+ });
+ }
+ };
+
+ onSuggestionSelected = (
+ event,
+ { suggestion, suggestionValue, suggestionIndex, sectionIndex, method },
+ ) => {
+ // If we've selected a crossing, center in on it
+ if (suggestion.__typename === 'Crossing') {
+ this.props.selectCrossing(suggestion.id);
+ }
+
+ // If we've selected a mapbox location, center on it
+ if (suggestion.type === 'Feature') {
+ this.props.setSelectedLocationCoordinates(suggestion.center);
+ }
+
+ // If we've selected a commuity, set the map bounds and filter
+ if (suggestion.__typename === 'Community') {
+ this.props.setSelectedCommunity(suggestion);
+ }
+
+ // Unfocus the search bar
+ this.autosuggestInput.blur();
+ };
+
+ // Autosuggest will call this function every time you need to update suggestions.
+ onSuggestionsFetchRequested = ({ value }) => {
+ const { center, communityId, communities } = this.props;
+
+ const inputValue = value.trim().toLowerCase();
+ const inputLength = inputValue.length;
+
+ // Get the suggestions from the mapbox geocoder
+ if (inputLength > 2) {
+ mapboxClient.geocodeForward(
+ inputValue,
+ {
+ proximity: { latitude: center.lat, longitude: center.lng },
+ // Hardcoding this for now to get better results
+ // TODO: Design a better solution for accurate geocode results
+ bbox: [-100, 27, -94, 34],
+ },
+ (err, res) => {
+ this.setState({ mapboxSuggestions: res.features });
+ },
+ );
+ } else {
+ this.setState({ mapboxSuggestions: [] });
+ }
+
+ // If we aren't filtering by community, get the communities
+ if (!communityId) {
+ const communitySuggestions = communities
+ .filter(c => c.name.toLowerCase().includes(inputValue))
+ .slice(0, 4);
+ this.setState({ communitySuggestions: communitySuggestions });
+ }
+ };
+
+ // Autosuggest will call this function every time you need to clear suggestions.
+ onSuggestionsClearRequested = () => {
+ this.setState({
+ mapboxSuggestions: [],
+ communitySuggestions: [],
+ });
+ };
+
clearSearch = () => {
this.props.searchQueryUpdated({ target: { value: '' } });
this.props.selectCrossing(null, null);
+ this.props.setSelectedCommunity(null);
+ this.setState({ typedValue: '', selectedValue: null });
+ };
+
+ updateCrossingSuggestions = suggestions => {
+ this.setState({
+ crossingSuggestions: suggestions,
+ });
+ };
+
+ onInputFocus = () => {
+ this.props.toggleSearchFocus(true);
+ };
+
+ onInputBlur = () => {
+ this.props.toggleSearchFocus(false);
};
render() {
+ const { selectedCrossingId, communityId } = this.props;
+
const {
- searchQuery,
- selectedCrossingId,
- searchQueryUpdated,
- selectedCrossingName,
- } = this.props;
+ typedValue,
+ selectedValue,
+ mapboxSuggestions,
+ crossingSuggestions,
+ communitySuggestions,
+ } = this.state;
+
+ const suggestions = [
+ {
+ title: 'Communities',
+ suggestions: communitySuggestions,
+ },
+ {
+ title: 'Crossings',
+ suggestions: crossingSuggestions,
+ },
+ {
+ title: 'Locations',
+ suggestions: mapboxSuggestions,
+ },
+ ];
+
+ const value = selectedValue ? selectedValue : typedValue;
+
+ // Autosuggest will pass through all these props to the input.
+ const inputProps = {
+ placeholder: 'Search...',
+ value,
+ onChange: this.onChange,
+ onFocus: this.onInputFocus,
+ onBlur: this.onInputBlur,
+ };
+
+ const formattedQuery = formatSearchQuery(typedValue);
return (
+
- SEARCH FOR A PLACE, AREA, OR CROSSING
+ SEARCH FOR A PLACE, COMMUNITY, OR CROSSING
- {selectedCrossingId && (
-
- {selectedCrossingName}
-
- )}
- {!selectedCrossingId && (
-
-
+ {selectedCrossingId && (
+
+ Back to Search
+
+ )}
+ {!selectedCrossingId && (
+
{
+ if (autosuggest !== null) {
+ this.autosuggestInput = autosuggest.input;
+ }
+ }}
+ suggestions={suggestions}
+ multiSection={true}
+ getSectionSuggestions={getSectionSuggestions}
+ renderSectionTitle={renderSectionTitle}
+ onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
+ onSuggestionsClearRequested={this.onSuggestionsClearRequested}
+ onSuggestionSelected={this.onSuggestionSelected}
+ onSuggestionHighlighted={this.onSuggestionHighlighted}
+ getSuggestionValue={getSuggestionValue}
+ renderSuggestion={Suggestion}
+ inputProps={inputProps}
+ shouldRenderSuggestions={() => true}
+ focusInputOnSuggestionClick={false}
/>
-
- )}
- {!selectedCrossingId && (
-
-
-
- )}
+ )}
+
({
+ variables: {
+ search: ownProps.searchQuery,
+ communityId: ownProps.communityId,
+ },
+ }),
+})(CrossingMapSearchCrossingSuggestions);
diff --git a/frontend/src/components/Shared/CrossingMapPage/CrossingMapSidebar.js b/frontend/src/components/Shared/CrossingMapPage/CrossingMapSidebar.js
index b27324a0..f0fa26e3 100644
--- a/frontend/src/components/Shared/CrossingMapPage/CrossingMapSidebar.js
+++ b/frontend/src/components/Shared/CrossingMapPage/CrossingMapSidebar.js
@@ -1,11 +1,23 @@
import React, { Component } from 'react';
import SelectedCrossingContainer from 'components/Shared/CrossingMapPage/SelectedCrossingContainer';
import CrossingMapSearchBar from 'components/Shared/CrossingMapPage/CrossingMapSearchBar';
-import CrossingSidebarSearchResultItem from 'components/Shared/CrossingMapPage/CrossingSidebarSearchResultItem';
+import CrossingSidebarNearbyCrossingItem from 'components/Shared/CrossingMapPage/CrossingSidebarNearbyCrossingItem';
import 'components/Shared/CrossingMapPage/CrossingMapSidebar.css';
import FontAwesome from 'react-fontawesome';
import classnames from 'classnames';
+const FilterCheckbox = ({defaultChecked, onClick, title}) => (
+
+
+ {title}
+
+)
+
class CrossingMapSidebar extends Component {
constructor(props) {
super(props);
@@ -13,6 +25,7 @@ class CrossingMapSidebar extends Component {
this.state = {
visible: true,
showFilters: false,
+ searchFocused: false,
};
}
@@ -24,8 +37,12 @@ class CrossingMapSidebar extends Component {
this.setState({ showFilters: !this.state.showFilters });
};
+ toggleSearchFocus = focused => {
+ this.setState({ searchFocused: focused });
+ };
+
render() {
- const { visible } = this.state;
+ const { visible, searchFocused } = this.state;
const {
toggleShowOpen,
toggleShowClosed,
@@ -43,6 +60,9 @@ class CrossingMapSidebar extends Component {
visibleCrossings,
allCommunities,
selectedCrossingName,
+ center,
+ setSelectedLocationCoordinates,
+ setSelectedCommunity,
} = this.props;
return (
@@ -55,83 +75,83 @@ class CrossingMapSidebar extends Component {
searchQuery={searchQuery}
searchQueryUpdated={searchQueryUpdated}
selectedCrossingName={selectedCrossingName}
+ center={center}
+ setSelectedLocationCoordinates={setSelectedLocationCoordinates}
+ toggleSearchFocus={this.toggleSearchFocus}
+ communities={allCommunities}
+ communityId={currentUser && currentUser.communityId}
+ setSelectedCommunity={setSelectedCommunity}
/>
- {selectedCrossingId && (
-
- )}
-
-
-
- {this.state.showFilters ? (
-
- ) : (
-
- )}{' '}
- FILTER
-
-
-
- {this.state.showFilters && (
-
-
-
- Open
-
-
-
- Caution
-
-
-
- Closed
-
-
-
+ {selectedCrossingId && (
+
- Long Term Closure
-
+ )}
+
+
+
+ {this.state.showFilters ? (
+
+ ) : (
+
+ )}{' '}
+ FILTER
+
+
+
+ {this.state.showFilters && (
+
+
+
+
+
+
+ )}
+
+ {visibleCrossings.map(c => (
+
+ ))}
+
)}
-
- {visibleCrossings.map(c => (
-
- ))}
-
)}
selectCrossing(crossingId)}
+ >
+
+
+
+
+
+ {statusNames[statusId]}
+
+
+ {crossingName}
+
+
+ {allCommunities &&
+ communityIds
+ .map(id => allCommunities.find(c => c.id === id).name)
+ .join(', ')}
+
+
+
+
+ {moment(latestStatus).calendar(null, {
+ lastDay: '[Yesterday]',
+ sameDay: '[Today]',
+ sameElse: 'MM/DD/YYYY',
+ })}
+
+
+ {moment(latestStatus).format('h:mm A')}
+
+
+
+ );
+ }
+}
+
+export default CrossingSidebarNearbyCrossingItem;
diff --git a/frontend/src/components/Shared/CrossingMapPage/CrossingSidebarSearchResultItem.js b/frontend/src/components/Shared/CrossingMapPage/CrossingSidebarSearchResultItem.js
deleted file mode 100644
index 42b44224..00000000
--- a/frontend/src/components/Shared/CrossingMapPage/CrossingSidebarSearchResultItem.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from 'react';
-import 'components/Shared/CrossingMapPage/CrossingMapPage.css';
-import { strings, statusIcons } from 'constants/StatusConstants';
-import moment from 'moment';
-
-class CrossingSidebarSearchResultItem extends React.Component {
- render() {
- const {
- latestStatus,
- statusId,
- crossingName,
- communityIds,
- allCommunities,
- } = this.props;
-
- return (
-
-
-
-
-
-
- {strings[statusId]}
-
-
- {crossingName}
-
-
- {allCommunities &&
- communityIds
- .map(id => allCommunities.find(c => c.id === id).name)
- .join(', ')}
-
-
-
-
- {moment(latestStatus).calendar(null, {
- lastDay: '[Yesterday]',
- sameDay: '[Today]',
- sameElse: 'MM/DD/YYYY',
- })}
-
-
- {moment(latestStatus).format('h:mm A')}
-
-
-
- );
- }
-}
-
-export default CrossingSidebarSearchResultItem;
diff --git a/frontend/src/components/Shared/CrossingMapPage/queries/suggestCrossingsQuery.js b/frontend/src/components/Shared/CrossingMapPage/queries/suggestCrossingsQuery.js
new file mode 100644
index 00000000..7782f9a4
--- /dev/null
+++ b/frontend/src/components/Shared/CrossingMapPage/queries/suggestCrossingsQuery.js
@@ -0,0 +1,23 @@
+import gql from 'graphql-tag';
+
+const suggestCrossings = gql`
+ query suggestCrossings($search: String, $communityId: Int) {
+ searchCrossings(
+ search: $search
+ communityId: $communityId
+ showOpen: true
+ showClosed: true
+ showCaution: true
+ showLongterm: true
+ first: 5
+ ) {
+ nodes {
+ id
+ name
+ geojson
+ }
+ }
+ }
+`;
+
+export default suggestCrossings;
diff --git a/frontend/src/components/Shared/Map/CrossingMap.js b/frontend/src/components/Shared/Map/CrossingMap.js
index b00f3a6c..5ffdc193 100644
--- a/frontend/src/components/Shared/Map/CrossingMap.js
+++ b/frontend/src/components/Shared/Map/CrossingMap.js
@@ -19,17 +19,29 @@ class CrossingMap extends React.Component {
selectedCrossingId: -1, // Mapbox filters don't support null values
selectedCrossing: null,
selectedCrossingCoordinates: null,
+ selectedLocationCoordinates: null,
firstLoadComplete: false,
- center: [
- (this.props.viewport[0][0] + this.props.viewport[1][0]) / 2,
- (this.props.viewport[0][1] + this.props.viewport[1][1]) / 2,
- ],
};
componentWillReceiveProps(nextProps) {
+ // If we've selected a crossing
if (nextProps.selectedCrossingId !== this.props.selectedCrossingId) {
if (nextProps.selectedCrossingId) {
this.setState({ selectedCrossingId: nextProps.selectedCrossingId });
+ const crossing =
+ this.props.openCrossings.searchCrossings.nodes.find(
+ c => c.id === nextProps.selectedCrossingId,
+ ) ||
+ this.props.closedCrossings.searchCrossings.nodes.find(
+ c => c.id === nextProps.selectedCrossingId,
+ ) ||
+ this.props.cautionCrossings.searchCrossings.nodes.find(
+ c => c.id === nextProps.selectedCrossingId,
+ ) ||
+ this.props.cautionCrossings.searchCrossings.nodes.find(
+ c => c.id === nextProps.selectedCrossingId,
+ );
+ this.selectCrossing(crossing);
} else {
this.setState({ selectedCrossingId: -1 });
this.setState({ selectedCrossing: null });
@@ -46,6 +58,19 @@ class CrossingMap extends React.Component {
this.setState({ selectedCrossing: selectedCrossing });
}
+ // If we are selecting a location, fly to it
+ if (
+ nextProps.selectedLocationCoordinates !==
+ this.state.selectedLocationCoordinates
+ ) {
+ this.setState({
+ selectedLocationCoordinates: nextProps.selectedLocationCoordinates,
+ });
+ if (nextProps.selectedLocationCoordinates) {
+ this.flyTo(nextProps.selectedLocationCoordinates);
+ }
+ }
+
// This is a slightly strange litle fix here, we used to check loading in render, and not render the map until it loaded
// that worked well for a single query, but led to the map disappearing on search. I then updated it to hide the crossing
// layers instead of hiding the whole map on load, but this led to the map not correctly filling the containing div. By checking
@@ -72,6 +97,10 @@ class CrossingMap extends React.Component {
this.addGeoLocateControl(map);
this.addCrossingClickHandlers(map);
this.addUpdateVisibleCrossingHandlers(map);
+
+ // update the map page center on map move
+ map.on('moveend', this.getMapCenter);
+
// disable map rotation using right click + drag
map.dragRotate.disable();
@@ -104,6 +133,23 @@ class CrossingMap extends React.Component {
map.on('data', this.updateVisibleCrossings);
}
+ getMapCenter = () => {
+ const { map } = this.state;
+ const center = map.getCenter();
+
+ this.props.getMapCenter(center);
+ };
+
+ flyTo = point => {
+ const { map } = this.state;
+ if (map) {
+ map.flyTo({
+ center: point,
+ zoom: 13,
+ });
+ }
+ };
+
updateVisibleCrossings = e => {
if (e.type === 'data' && !e.isSourceLoaded) return;
@@ -148,13 +194,35 @@ class CrossingMap extends React.Component {
map.on('click', this.onMapClick);
}
+ selectCrossing = crossing => {
+ const coordinates = JSON.parse(crossing.geojson).coordinates;
+
+ const mapCrossing = {
+ crossingId: crossing.id,
+ crossingName: crossing.name,
+ crossingStatus: crossing.latestStatusId,
+ geojson: crossing.geojson,
+ };
+
+ this.setState({
+ selectedCrossingCoordinates: coordinates,
+ selectedCrossing: mapCrossing,
+ });
+ this.flyTo(coordinates);
+ this.props.selectCrossing(
+ crossing.id,
+ crossing.latestStatusId,
+ crossing.name,
+ );
+ };
+
onCrossingClick = crossing => {
this.setState({ selectedCrossingId: crossing.properties.crossingId });
this.setState({ selectedCrossing: crossing.properties });
this.setState({
selectedCrossingCoordinates: crossing.geometry.coordinates,
});
- this.setState({ center: crossing.geometry.coordinates });
+ this.flyTo(crossing.geometry.coordinates);
this.props.selectCrossing(
crossing.properties.crossingId,
crossing.properties.crossingStatus,
@@ -214,7 +282,13 @@ class CrossingMap extends React.Component {
? this.props.longtermCrossings.searchCrossings.nodes
: null;
- const { showOpen, showClosed, showCaution, showLongterm } = this.props;
+ const {
+ showOpen,
+ showClosed,
+ showCaution,
+ showLongterm,
+ center,
+ } = this.props;
return (
{!isLoading &&
showOpen && (
@@ -471,7 +545,7 @@ export default compose(
ownProps.currentUser &&
ownProps.currentUser.role !== 'floods_super_admin'
? ownProps.currentUser.communityId
- : null,
+ : ownProps.selectedCommunityId,
},
}),
}),
@@ -488,7 +562,7 @@ export default compose(
ownProps.currentUser &&
ownProps.currentUser.role !== 'floods_super_admin'
? ownProps.currentUser.communityId
- : null,
+ : ownProps.selectedCommunityId,
},
}),
}),
@@ -505,7 +579,7 @@ export default compose(
ownProps.currentUser &&
ownProps.currentUser.role !== 'floods_super_admin'
? ownProps.currentUser.communityId
- : null,
+ : ownProps.selectedCommunityId,
},
}),
}),
@@ -522,7 +596,7 @@ export default compose(
ownProps.currentUser &&
ownProps.currentUser.role !== 'floods_super_admin'
? ownProps.currentUser.communityId
- : null,
+ : ownProps.selectedCommunityId,
},
}),
}),
diff --git a/frontend/src/components/Shared/Map/CrossingStaticMap.js b/frontend/src/components/Shared/Map/CrossingStaticMap.js
index bebb1ae0..00a62396 100644
--- a/frontend/src/components/Shared/Map/CrossingStaticMap.js
+++ b/frontend/src/components/Shared/Map/CrossingStaticMap.js
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import ReactMapboxGl, { Marker } from 'react-mapbox-gl';
import mapboxstyle from 'components/Shared/Map/mapboxstyle.json';
-import { statusIcons } from 'constants/StatusConstants';
+import StatusIcon from 'components/Shared/StatusIcon';
const Map = ReactMapboxGl({ accessToken: null, interactive: false });
@@ -23,7 +23,7 @@ class CrossingStaticMap extends Component {
onStyleLoad={this.onStyleLoad}
>
-
+
);
diff --git a/frontend/src/components/Shared/StatusIcon.js b/frontend/src/components/Shared/StatusIcon.js
new file mode 100644
index 00000000..dd372189
--- /dev/null
+++ b/frontend/src/components/Shared/StatusIcon.js
@@ -0,0 +1,13 @@
+import React from 'react';
+
+import { statusNames, statusIcons } from 'constants/StatusConstants';
+
+export default function StatusIcon({ statusId, ...props }) {
+ return (
+
+ );
+}
diff --git a/frontend/src/constants/StatusConstants.js b/frontend/src/constants/StatusConstants.js
index eaa474c2..b40e90c9 100644
--- a/frontend/src/constants/StatusConstants.js
+++ b/frontend/src/constants/StatusConstants.js
@@ -12,7 +12,7 @@ export const CLOSED = 2;
export const CAUTION = 3;
export const LONGTERM = 4;
-export const strings = {
+export const statusNames = {
1: 'Open',
2: 'Closed',
3: 'Caution',
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 264a1006..affde866 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -5863,6 +5863,13 @@ mapbox-gl@^0.40.0:
vt-pbf "^3.0.1"
webworkify "^1.4.0"
+mapbox@^1.0.0-beta9:
+ version "1.0.0-beta9"
+ resolved "https://registry.yarnpkg.com/mapbox/-/mapbox-1.0.0-beta9.tgz#580bbacd9990bbe10f2f729ff4031a3b898d27a4"
+ dependencies:
+ es6-promise "^4.0.5"
+ rest "^2.0.0"
+
mapnik-vector-tile@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/mapnik-vector-tile/-/mapnik-vector-tile-1.4.0.tgz#f46742514cd3ad3554c5d640614804fe9beb49e5"
@@ -6397,6 +6404,10 @@ object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+object-assign@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
+
object-hash@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.8.tgz#28a659cf987d96a4dabe7860289f3b5326c4a03c"
@@ -7359,6 +7370,22 @@ react-apollo@^1.4.2:
object-assign "^4.0.1"
prop-types "^15.5.8"
+react-autosuggest@^9.3.3:
+ version "9.3.3"
+ resolved "https://registry.yarnpkg.com/react-autosuggest/-/react-autosuggest-9.3.3.tgz#400a9173d291380daa625a599dcbf5cf1c908d01"
+ dependencies:
+ prop-types "^15.5.10"
+ react-autowhatever "^10.1.0"
+ shallow-equal "^1.0.0"
+
+react-autowhatever@^10.1.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/react-autowhatever/-/react-autowhatever-10.1.0.tgz#41f6d69382437d3447a0a3c8913bb8ca2feaabc1"
+ dependencies:
+ prop-types "^15.5.8"
+ react-themeable "^1.1.0"
+ section-iterator "^2.0.0"
+
react-container-query@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/react-container-query/-/react-container-query-0.9.1.tgz#57136d98c1ada18084b27cb45a0006a9f03a95d6"
@@ -7635,6 +7662,12 @@ react-test-renderer@^16.0.0-rc.3:
fbjs "^0.8.9"
object-assign "^4.1.0"
+react-themeable@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e"
+ dependencies:
+ object-assign "^3.0.0"
+
react-transition-group@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.0.tgz#b51fc921b0c3835a7ef7c571c79fc82c73e9204f"
@@ -8087,6 +8120,10 @@ resolve@^1.1.5, resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.2, resolve@~1.4.0:
dependencies:
path-parse "^1.0.5"
+rest@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/rest/-/rest-2.0.0.tgz#6dfadf66a405c49cfbd5b4bd25b59fd29cd861bc"
+
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
@@ -8214,6 +8251,10 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8"
source-map "^0.4.2"
+section-iterator@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a"
+
seedrandom@^2.4.2:
version "2.4.3"
resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-2.4.3.tgz#2438504dad33917314bff18ac4d794f16d6aaecc"
@@ -8325,6 +8366,10 @@ shallow-copy@~0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170"
+shallow-equal@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.0.0.tgz#508d1838b3de590ab8757b011b25e430900945f7"
+
shallowequal@0.2.x, shallowequal@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e"