Skip to content
This repository was archived by the owner on Feb 11, 2026. It is now read-only.
Open
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
3 changes: 2 additions & 1 deletion app/javascript/pages/components/App.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Route, Routes, Navigate, useParams } from 'react-router-dom';

import Community from './Community';
import Faq from './Faq';
import Gallery from './gallery/Gallery';
import Login from './Login';
Expand Down Expand Up @@ -42,6 +42,7 @@ const App = ({ muniOptions, tabOptions }) => (
path="/profile/:muni/:tab?"
element={<ProfileRoute muniOptions={muniOptions} tabOptions={tabOptions} />}
/>
<Route path="/community" element={<Community />} />
<Route path="/gallery" element={<Gallery />} />
<Route path="/login" element={<Login />} />
<Route path="/calendar/:year/:month" element={<CalendarEntry />} />
Expand Down
15 changes: 15 additions & 0 deletions app/javascript/pages/components/Community.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import CommunitySelector from "../containers/CommunitySelector";

class Community extends React.Component {
render() {
return (
<div className="page-section page-section__map">
<a name="community-profiles" />
<CommunitySelector />
</div>
);
}
}

export default Community;
2 changes: 1 addition & 1 deletion app/javascript/pages/components/CommunityProfiles.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const CommunityProfiles = (props) => {
<article className="component CommunityProfiles">
<div className="page-header">
<div className="container back-link">
<Link to="/">{'< Back'}</Link>
<Link to="community">{'< Back'}</Link>
</div>
<div className="container">
<header>
Expand Down
4 changes: 3 additions & 1 deletion app/javascript/pages/components/CommunitySelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class CommunitySelector extends React.Component {

<MapBox
layers={[this.props.muniLines, this.props.muniFill]}
muniPoly={this.props.municipalityPoly}
toProfile={this.props.toProfile}
/>
</section>
);
Expand All @@ -44,4 +46,4 @@ CommunitySelector.propTypes = {
muniFill: PropTypes.shape(layerShape).isRequired,
};

export default CommunitySelector;
export default CommunitySelector;
36 changes: 22 additions & 14 deletions app/javascript/pages/components/Home.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import React from "react";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";

import Particles from './partials/Particles';
import SearchBar from '../containers/SearchBar';
import CategoryGrid from '../containers/CategoryGrid';
import CommunitySelector from '../containers/CommunitySelector';
import CallToAction from './partials/CallToAction';
import CalendarImage from '../assets/images/calendar-home.svg';
import Particles from "./partials/Particles";
import SearchBar from "../containers/SearchBar";
import CategoryGrid from "../containers/CategoryGrid";
import CommunitySelector from "../containers/CommunitySelector";
import CallToAction from "./partials/CallToAction";
import CalendarImage from "../assets/images/calendar-home.svg";

class Home extends React.Component {
constructor() {
Expand Down Expand Up @@ -63,11 +63,19 @@ class Home extends React.Component {

<CategoryGrid />
</div>

<div className="page-section page-section__map">
<a name="community-profiles" />
<CommunitySelector />
</div>
<section className="page-section container tight">
<div className="page-section page-section__map">
<h2>Community Profiles</h2>
<p className="gallery-spotlight__info">
a paragrah to explain what is community profile
</p>
<CallToAction
link="/community"
text="View Community Profiles"
extraClassNames="community-profiles__cta"
/>
</div>
</section>
</section>
);
}
Expand Down
192 changes: 120 additions & 72 deletions app/javascript/pages/components/MapBox.jsx
Original file line number Diff line number Diff line change
@@ -1,105 +1,150 @@
import React from 'react';
import PropTypes from 'prop-types';

import colors from '../constants/colors';

mapboxgl.accessToken = 'pk.eyJ1IjoiaWhpbGwiLCJhIjoiY2plZzUwMTRzMW45NjJxb2R2Z2thOWF1YiJ9.szIAeMS4c9YTgNsJeG36gg';
import React from "react";
import PropTypes from "prop-types";
import mapboxgl from 'mapbox-gl';
import { MAP_CONFIG } from '../constants/mapConfig';
import { setupMouseEvents } from '../utils/mapEventHandlers';
import { addMapLayer, updateMapLayers } from '../utils/layerManager';
import mapcRegions from "../data/mapc-regions.json";
import colors from "../constants/colors";

mapboxgl.accessToken = MAP_CONFIG.accessToken;

class MapBox extends React.Component {
state = {
finishedLoading: false,
showMapcRegions: false,
};

constructor() {
super(...arguments) ;

this.addLayer = this.addLayer.bind(this);

this.state = {
finishedLoading: false,
}
componentDidMount() {
this.initializeMap();
}


addLayer(layer = null) {
if (layer && !this.map.getSource(`ma-${layer.type}`)) {
this.map.addLayer({
id: `ma-${layer.type}`,
type: layer.type,
source: {
type: 'geojson',
data: layer.geojson,
},
paint: {
[`${layer.type}-color`]: colors.BRAND.PRIMARY,
},
});
}
componentDidUpdate() {
this.handleLayerUpdates();
}

componentWillUnmount() {
this.map?.remove();
}

componentDidMount() {
initializeMap() {
this.map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/ihill/ckeucj9gy9vt319qm4dxcn73l',
scrollZoom: false,
style: MAP_CONFIG.style,
dragPan: false,
dragRotate: false,
doubleClickZoom: false,
boxZoom: false,
interactive: false,
...this.props,
});

this.map.fitBounds([[-73.5081481933594, 41.1863288879395], [-69.8615341186523, 42.8867149353027]], {
padding: { top: 30, left: 300, right: 30, bottom: 30 },
this.map.fitBounds(MAP_CONFIG.bounds, {
padding: MAP_CONFIG.padding,
animate: false,
})
});

this.map.on('load', () => {
this.map.resize();
this.map.addControl(
new mapboxgl.NavigationControl(MAP_CONFIG.navigationControl),
MAP_CONFIG.navigationControl.position
);

if (this.props.layers) {
this.props.layers.forEach(this.addLayer);
}
this.map.on("load", () => this.onMapLoad());
}

this.setState({ finishedLoading: true });
});
onMapLoad() {
this.map.resize();
window.map = this.map;

this.initializeHoverLayer();
this.initializeMAPCRegions();

if (this.props.layers) {
this.props.layers.forEach(layer => addMapLayer(this.map, layer));
}

setupMouseEvents(this.map, this.props.muniPoly, this.props.toProfile);
this.setState({ finishedLoading: true });
}

initializeHoverLayer() {
if (!this.props.muniPoly) return;

componentDidUpdate() {
if (
this.state.finishedLoading
&& this.props.layers
) {
this.props.layers.forEach(layer => {
if (layer) {
var source = this.map.getSource(`ma-${layer.type}`);

if (source) {
source.setData(layer.geojson);
}
else {
this.addLayer(layer);
}
}
});
}
this.map.addSource("hover-fill", {
type: "geojson",
data: this.props.muniPoly,
});

this.map.addLayer({
id: "hover-fill",
type: "fill",
source: "hover-fill",
paint: {
"fill-color": colors.BRAND.PRIMARY,
"fill-opacity": 0,
},
});
}

initializeMAPCRegions() {
this.map.addSource("mapc-region", {
type: "geojson",
data: mapcRegions,
});

componentWillUnmount() {
this.map.remove();
this.map.addLayer({
id: "mapc-region-line",
type: "fill",
source: "mapc-region",
layout: { visibility: "none" },
paint: {
"fill-color": "#006400",
"fill-opacity": 0.7,
},
});
}

handleLayerUpdates() {
if (this.state.finishedLoading && this.props.layers) {
updateMapLayers(this.map, this.props.layers);
}
}

toggleLayer = () => {
this.setState(
prevState => ({
showMAPCRegions: !prevState.showMAPCRegions,
}),
() => {
this.map?.setLayoutProperty(
"mapc-region-line",
"visibility",
this.state.showMAPCRegions ? "visible" : "none"
);
}
);
};

render() {
return (
<section className="component MapBox">
<div className="map-layer" ref={el => this.mapContainer = el} />
<div className="map-controls">
<div className="toggle-container">
<label className="toggle-switch">
<input
type="checkbox"
checked={this.state.showMAPCRegions}
onChange={this.toggleLayer}
/>
<span className="slider"></span>
</label>
<div className="slider-text">Show MAPC regions</div>
</div>
</div>
<div
className="map-layer"
ref={el => (this.mapContainer = el)}
/>
</section>
);
}

}

MapBox.propTypes = {
Expand All @@ -109,11 +154,14 @@ MapBox.propTypes = {
zoom: PropTypes.number,
minZoom: PropTypes.number,
maxZoom: PropTypes.number,
layers: PropTypes.arrayOf(PropTypes.shape({
type: PropTypes.string.required,
geojson: PropTypes.object.required,
})),
layers: PropTypes.arrayOf(
PropTypes.shape({
type: PropTypes.string.isRequired,
geojson: PropTypes.object.isRequired,
})
),
muniPoly: PropTypes.object,
toProfile: PropTypes.func,
};

export default MapBox;

Loading