From 1dea8fcf6bbab9a2a9144639b2e6841a9b65ab13 Mon Sep 17 00:00:00 2001 From: Trevor Gerhardt Date: Sat, 29 Oct 2016 16:49:55 +0700 Subject: [PATCH] feat(fetch): Remove unused files. Add action logs for everything. DeepEqualify. --- .travis.yml | 4 +- package.json | 4 +- src/actions/index.js | 165 ++++++++++++------- src/components/canvas-tile-layer.js | 29 ---- src/components/deep-equal.js | 14 ++ src/components/destinations-select.js | 34 ---- src/components/icon.js | 4 +- src/components/log-item/index.js | 6 +- src/components/log-item/style.css | 1 + src/components/log/index.js | 11 +- src/components/map/index.js | 32 ---- src/components/route-card.js | 106 ++++++------ src/components/timecutoff-select.js | 5 +- src/components/transit-mode-select.js | 31 ---- src/components/transit-scenario-select.js | 31 ---- src/components/transitive-map-layer/index.js | 7 +- src/containers/indianapolis/form.js | 112 +++++++------ src/containers/indianapolis/index.js | 1 + src/containers/indianapolis/map.js | 4 +- src/reducers/geocoder.js | 20 --- src/router.js | 15 -- src/utils/hash.js | 20 +++ src/utils/initialize-browsochrones.js | 4 +- src/utils/raf-scheduler.js | 42 ----- yarn.lock | 39 +---- 25 files changed, 294 insertions(+), 447 deletions(-) delete mode 100644 src/components/canvas-tile-layer.js create mode 100644 src/components/deep-equal.js delete mode 100644 src/components/destinations-select.js delete mode 100644 src/components/map/index.js delete mode 100644 src/components/transit-mode-select.js delete mode 100644 src/components/transit-scenario-select.js delete mode 100644 src/router.js create mode 100644 src/utils/hash.js delete mode 100644 src/utils/raf-scheduler.js diff --git a/.travis.yml b/.travis.yml index 85f26ca..c355b09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ sudo: false language: node_js cache: directories: - - node_modules + - ~/.yarn-cache notifications: email: false node_js: @@ -12,7 +12,7 @@ before_install: install: - yarn after_success: - - npm run semantic-release + - yarn run semantic-release branches: except: - /^v\d+\.\d+\.\d+$/ diff --git a/package.json b/package.json index e381ae4..332bb57 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "leaflet-transitivelayer": "^0.2.0", "lodash.camelcase": "^4.3.0", "lodash.capitalize": "^4.2.1", + "lodash.isequal": "^4.4.0", "lodash.lowercase": "^4.3.0", "lodash.merge": "^4.6.0", "lonlng": "0.1.0", @@ -45,12 +46,9 @@ "normalize.css": "^5.0.0", "qs": "^6.1.0", "react": "^15.3.2", - "react-addons-perf": "^15.3.2", "react-dom": "^15.3.2", "react-leaflet": "^0.12.2", - "react-pure-render": "^1.0.2", "react-redux": "^4.4.5", - "react-router": "^2.8.1", "react-select-geocoder": "^0.2.1", "redux": "^3.6.0", "redux-actions": "^0.12.0", diff --git a/src/actions/index.js b/src/actions/index.js index d8edd40..6ef627d 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -5,6 +5,7 @@ import {createAction} from 'redux-actions' import fetch from 'mastarm/react/fetch' import featureToLabel from '../utils/feature-to-label' +import {setKeyTo} from '../utils/hash' import {reverse} from '../utils/mapbox-geocoder' const reverseGeocode = ({latlng}) => reverse(process.env.MAPBOX_ACCESS_TOKEN, latlng) @@ -14,21 +15,35 @@ export const addActionLogItem = createAction('add action log item', (item) => { ? { text: item } : item - return Object.assign({ + return { createdAt: new Date(), - level: 'info' - }, payload) + level: 'info', + ...payload + } +}) + +export const setDestination = createAction('set destination', (destination) => { + setKeyTo('end', destination ? destination.label : null) + return destination +}) + +export const setOrigin = createAction('set origin', (origin) => { + setKeyTo('start', origin ? origin.label : null) + return origin +}) + +export const clearEnd = createAction('clear end', () => { + setKeyTo('end', null) +}) +export const clearStart = createAction('clear start', () => { + setKeyTo('start', null) }) export const setAccessibility = createAction('set accessibility') export const setAccessibilityFor = createAction('set accessibility for') -export const clearEnd = createAction('clear end') -export const clearStart = createAction('clear start') export const setBrowsochronesBase = createAction('set browsochrones base') export const setBrowsochronesComparison = createAction('set browsochrones comparison') -export const setDestination = createAction('set destination') -export const setOrigin = createAction('set origin') export const setSelectedTimeCutoff = createAction('set selected time cutoff') export const setTransitiveNetwork = createAction('set transitive network') export const setDestinationDataFor = createAction('set destination data for') @@ -46,9 +61,6 @@ export const setComparisonActive = createAction('set comparison active') export const updateMap = createAction('update map') export const updateSelectedDestination = createAction('update selected destination') -export const updateSelectedTransitMode = createAction('update selected transit mode') -export const updateSelectedTransitScenario = createAction('update selected transit scenario') - /** * What happens on origin update: * - Map marker should get set to the new origin immmediately (if it wasn't a drag/drop) @@ -59,16 +71,27 @@ export const updateSelectedTransitScenario = createAction('update selected trans * - Accessibility is calculated for grids */ export function updateOrigin ({browsochrones, destinationLatlng, latlng, label, timeCutoff, zoom}) { - const actions = [clearIsochrone()] + const actions = [ + addActionLogItem('Generating origins...'), + clearIsochrone() + ] if (label) { - actions.push(setOrigin({label, latlng})) + actions.push( + addActionLogItem(`Set start address to: ${label}`), + setOrigin({label, latlng}) + ) } else { actions.push( + addActionLogItem(`Finding start address for ${lonlng(latlng).toString()}`), reverseGeocode({latlng}) .then(({features}) => { if (!features || features.length < 1) return - return setOrigin({label: featureToLabel(features[0]), latlng: lonlng(features[0].geometry.coordinates)}) + const label = featureToLabel(features[0]) + return [ + addActionLogItem(`Set start address to: ${label}`), + setOrigin({label, latlng: lonlng(features[0].geometry.coordinates)}) + ] }) ) } @@ -77,22 +100,24 @@ export function updateOrigin ({browsochrones, destinationLatlng, latlng, label, const point = browsochrones.base.pixelToOriginPoint(Leaflet.CRS.EPSG3857.latLngToPoint(latlng, zoom), zoom) if (browsochrones.base.pointInQueryBounds(point)) { - actions.push(fetchBrowsochronesFor({ - browsochrones: browsochrones.base, - destinationLatlng, - latlng, - name: 'base', - timeCutoff, - zoom - })) - actions.push(fetchBrowsochronesFor({ - browsochrones: browsochrones.comparison, - destinationLatlng, - latlng, - name: 'comparison', - timeCutoff, - zoom - })) + actions.push( + fetchBrowsochronesFor({ + browsochrones: browsochrones.base, + destinationLatlng, + latlng, + name: 'base', + timeCutoff, + zoom + }), + fetchBrowsochronesFor({ + browsochrones: browsochrones.comparison, + destinationLatlng, + latlng, + name: 'comparison', + timeCutoff, + zoom + }) + ) } else { console.log('point out of bounds') // TODO: Handle } @@ -109,45 +134,65 @@ function fetchBrowsochronesFor ({ zoom }) { const point = browsochrones.pixelToOriginPoint(Leaflet.CRS.EPSG3857.latLngToPoint(latlng, zoom), zoom) - return fetch({ - url: `${browsochrones.originsUrl}/${point.x | 0}/${point.y | 0}.dat`, - next: async (response) => { - const actions = [] - await browsochrones.setOrigin(response.value, point) - await browsochrones.generateSurface() - - actions.push(generateAccessiblityFor({browsochrones, name, timeCutoff})) - actions.push(generateIsochroneFor({browsochrones, latlng, name, timeCutoff})) - - if (destinationLatlng) { - actions.push(generateDestinationDataFor({browsochrones, latlng: destinationLatlng, name, zoom})) + return [ + addActionLogItem(`Fetching origin data for ${name} scenario`), + fetch({ + url: `${browsochrones.originsUrl}/${point.x | 0}/${point.y | 0}.dat`, + next: async (response) => { + const actions = [] + await browsochrones.setOrigin(response.value, point) + await browsochrones.generateSurface() + + actions.push( + generateAccessiblityFor({browsochrones, name, timeCutoff}), + generateIsochroneFor({browsochrones, latlng, name, timeCutoff}) + ) + + if (destinationLatlng) { + actions.push(generateDestinationDataFor({browsochrones, latlng: destinationLatlng, name, zoom})) + } + + return actions } - - return actions - } - }) + }) + ] } -async function generateAccessiblityFor ({browsochrones, name, timeCutoff}) { - const accessibility = {} - for (const grid of browsochrones.grids) { - accessibility[grid] = await browsochrones.getAccessibilityForGrid(grid, timeCutoff) - } - return setAccessibilityFor({accessibility, name}) +function generateAccessiblityFor ({browsochrones, name, timeCutoff}) { + return [ + addActionLogItem(`Generating accessibility surface for ${name}`), + (async () => { + const accessibility = {} + for (const grid of browsochrones.grids) { + accessibility[grid] = await browsochrones.getAccessibilityForGrid(grid, timeCutoff) + } + return setAccessibilityFor({accessibility, name}) + })() + ] } -async function generateIsochroneFor ({browsochrones, latlng, name, timeCutoff}) { - const isochrone = await browsochrones.getIsochrone(timeCutoff) - isochrone.key = `${name}-${lonlng.toString(latlng)}-${timeCutoff}` +function generateIsochroneFor ({browsochrones, latlng, name, timeCutoff}) { + return [ + addActionLogItem(`Generating travel time isochrone for ${name}`), + (async () => { + const isochrone = await browsochrones.getIsochrone(timeCutoff) + isochrone.key = `${name}-${lonlng.toString(latlng)}-${timeCutoff}` - return setIsochroneFor({isochrone, name}) + return setIsochroneFor({isochrone, name}) + })() + ] } -async function generateDestinationDataFor ({browsochrones, latlng, name, zoom}) { - const destinationPoint = browsochrones.pixelToOriginPoint(Leaflet.CRS.EPSG3857.latLngToPoint(latlng, zoom), zoom) - const data = await browsochrones.generateDestinationData(destinationPoint, zoom) - data.transitive.key = `${name}-${lonlng.toString(latlng)}` - return setDestinationDataFor({data, name}) +function generateDestinationDataFor ({browsochrones, latlng, name, zoom}) { + return [ + addActionLogItem(`Generating transit data for ${name}`), + (async () => { + const destinationPoint = browsochrones.pixelToOriginPoint(Leaflet.CRS.EPSG3857.latLngToPoint(latlng, zoom), zoom) + const data = await browsochrones.generateDestinationData(destinationPoint, zoom) + data.transitive.key = `${name}-${lonlng.toString(latlng)}` + return setDestinationDataFor({data, name}) + })() + ] } export function updateSelectedTimeCutoff ({browsochrones, latlng, timeCutoff}) { diff --git a/src/components/canvas-tile-layer.js b/src/components/canvas-tile-layer.js deleted file mode 100644 index 2418ef7..0000000 --- a/src/components/canvas-tile-layer.js +++ /dev/null @@ -1,29 +0,0 @@ -import {tileLayer} from 'leaflet' -import {PropTypes} from 'react' -import {BaseTileLayer} from 'react-leaflet' - -export default class CanvasTileLayer extends BaseTileLayer { - static propTypes = { - drawTile: PropTypes.func.isRequired - }; - - componentWillMount () { - super.componentWillMount() - this.leafletElement = tileLayer.canvas({ detectRetina: true }) - this.leafletElement.drawTile = this.props.drawTile - } - - componentDidMount () { - super.componentDidMount() - this.leafletElement.redraw() - } - - componentWillReceiveProps (nextProps) { - this.leafletElement.drawTile = nextProps.drawTile - } - - componentDidUpdate (prevProps, prevState) { - super.componentDidUpdate(prevProps, prevState) - this.leafletElement.redraw() - } -} diff --git a/src/components/deep-equal.js b/src/components/deep-equal.js new file mode 100644 index 0000000..7636209 --- /dev/null +++ b/src/components/deep-equal.js @@ -0,0 +1,14 @@ +import isEqual from 'lodash.isequal' +import {Component} from 'react' + +function shouldComponentUpdate (newProps, newState) { + return !isEqual(newProps, this.props) || !isEqual(newState, this.state) +} + +export default class DeepEqual extends Component {} +DeepEqual.prototype.shouldComponentUpdate = shouldComponentUpdate + +export function pure (Component) { + Component.prototype.shouldComponentUpdate = shouldComponentUpdate + return Component +} diff --git a/src/components/destinations-select.js b/src/components/destinations-select.js deleted file mode 100644 index 28e8b38..0000000 --- a/src/components/destinations-select.js +++ /dev/null @@ -1,34 +0,0 @@ -import React, {PropTypes} from 'react' -import PureComponent from 'react-pure-render/component' -import {connect} from 'react-redux' - -import {updateSelectedDestination} from '../actions' - -class DestinationsSelect extends PureComponent { - static propTypes = { - options: PropTypes.arrayOf(PropTypes.object).isRequired - }; - - render () { - return ( - - ) - } -} - -function mapStateToProps (state) { - return { - defaultValue: state.destinations.selected, - options: state.destinations.sets - } -} - -function mapDispatchToProps (dispatch) { - return { - onChange: (event) => dispatch(updateSelectedDestination(event.target.value)) - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(DestinationsSelect) diff --git a/src/components/icon.js b/src/components/icon.js index 87ee118..197a18d 100644 --- a/src/components/icon.js +++ b/src/components/icon.js @@ -1,5 +1,7 @@ import React from 'react' +import {pure} from './deep-equal' + const Icon = ({ className = '', type, @@ -10,4 +12,4 @@ const Icon = ({ {...props} /> -export default Icon +export default pure(Icon) diff --git a/src/components/log-item/index.js b/src/components/log-item/index.js index 763fc28..14ec012 100644 --- a/src/components/log-item/index.js +++ b/src/components/log-item/index.js @@ -1,9 +1,11 @@ -import React, {Component, PropTypes} from 'react' +import React, {PropTypes} from 'react' import moment from 'moment' +import DeepEqual from '../deep-equal' + const format = 'HH:mm:ss' -export default class LogItem extends Component { +export default class LogItem extends DeepEqual { static propTypes = { createdAt: PropTypes.object, level: PropTypes.string, diff --git a/src/components/log-item/style.css b/src/components/log-item/style.css index 7004cab..e946771 100644 --- a/src/components/log-item/style.css +++ b/src/components/log-item/style.css @@ -1,6 +1,7 @@ .LogItem { margin-bottom: 0.5rem; + display: flex; } .LogItem-label { diff --git a/src/components/log/index.js b/src/components/log/index.js index 33531af..4ad95cf 100644 --- a/src/components/log/index.js +++ b/src/components/log/index.js @@ -1,13 +1,18 @@ -import React, {Component, PropTypes} from 'react' +import React, {PropTypes} from 'react' +import DeepEqual from '../deep-equal' import LogItem from '../log-item' -export default class Log extends Component { +export default class Log extends DeepEqual { static propTypes = { items: PropTypes.arrayOf(PropTypes.object).isRequired }; render () { - return
{this.props.items.map((item, index) => )}
+ return ( +
+ {this.props.items.map((item, index) => )} +
+ ) } } diff --git a/src/components/map/index.js b/src/components/map/index.js deleted file mode 100644 index 600b0ab..0000000 --- a/src/components/map/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import React, {Component, PropTypes} from 'react' -import {Map as BaseMap, TileLayer} from 'react-leaflet' - -export default class Map extends Component { - static propTypes = { - className: PropTypes.string, - children: PropTypes.any, - map: PropTypes.object, - onChange: PropTypes.func, - onClick: PropTypes.func - }; - - render () { - const {children, map, onChange, onClick} = this.props - const {attribution, center, zoom} = map - - return ( - onChange({ zoom: e.target._zoom })} - {...this.props}> - - {children} - - ) - } -} diff --git a/src/components/route-card.js b/src/components/route-card.js index 9a7b3b6..58ce078 100644 --- a/src/components/route-card.js +++ b/src/components/route-card.js @@ -3,53 +3,57 @@ import React from 'react' import toCapitalCase from 'lodash.capitalize' import toSpaceCase from 'lodash.lowercase' +import DeepEqual from './deep-equal' import Icon from './icon' import messages from '../utils/messages' -const RouteCard = ({ - active, - alternate, - accessibility, - children, - oldAccessibility, - oldTravelTime, - oldWaitTime, - onClick, - transitiveData, - travelTime, - waitTime -}) => { - const className = 'Card' + (alternate ? ' Card-alternate' : '') + (active ? ' Card-active' : '') - const accessibilityKeys = Object.keys(accessibility) - const comparisonAccessibilityKeys = Object.keys(oldAccessibility || {}) - - const access = comparisonAccessibilityKeys.length > 0 - ? showDiff(accessibilityKeys, accessibility, oldAccessibility) - : showAccess(accessibilityKeys, accessibility) +export default class RouteCard extends DeepEqual { + render () { + const { + active, + alternate, + accessibility, + children, + oldAccessibility, + oldTravelTime, + oldWaitTime, + onClick, + transitiveData, + travelTime, + waitTime + } = this.props + const className = 'Card' + (alternate ? ' Card-alternate' : '') + (active ? ' Card-active' : '') + const accessibilityKeys = Object.keys(accessibility) + const comparisonAccessibilityKeys = Object.keys(oldAccessibility || {}) + + const access = comparisonAccessibilityKeys.length > 0 + ? showDiff(accessibilityKeys, accessibility, oldAccessibility) + : showAccess(accessibilityKeys, accessibility) - return ( -
-
{children} - - {active && } - {!active && 'show'} - -
-
- {access} - {travelTime && transitiveData && - renderJourneys({ - oldTravelTime, - oldWaitTime, - travelTime, - transitiveData, - waitTime - })} + return ( +
+
{children} + + {active && } + {!active && 'show'} + +
+
+ {access} + {travelTime && transitiveData && + renderJourneys({ + oldTravelTime, + oldWaitTime, + travelTime, + transitiveData, + waitTime + })} +
-
- ) + ) + } } function TripDiff ({ @@ -194,20 +198,24 @@ function showAccess (keys, base) { function AccessDiffPercentage ({ diff }) { - if (diff > 0) return {diff.toLocaleString()}% - else if (diff < 0) return {(diff * -1).toLocaleString()}% + if (diff > 0) return {diff}% + else if (diff < 0) return {diff * -1}% + else return } function showDiff (keys, base, comparison) { return (
Access to
- {keys.map((k, i) => { - const diff = parseInt((base[k] - comparison[k]) / base[k] * 100, 10) - return
{(base[k] | 0).toLocaleString()} {toSpaceCase(k)}
+ {keys.map((key, i) => { + const diff = parseInt(((base[key] - comparison[key]) / base[key] * 100).toFixed(1)) + return ( +
+ {(base[key] | 0).toLocaleString()} {toSpaceCase(key)} + +
+ ) })}
) } - -export default RouteCard diff --git a/src/components/timecutoff-select.js b/src/components/timecutoff-select.js index 096f214..3342837 100644 --- a/src/components/timecutoff-select.js +++ b/src/components/timecutoff-select.js @@ -1,8 +1,9 @@ import React, {PropTypes} from 'react' -import PureComponent from 'react-pure-render/component' import {connect} from 'react-redux' -class TimeCutoffSelect extends PureComponent { +import DeepEqual from './deep-equal' + +class TimeCutoffSelect extends DeepEqual { static propTypes = { className: PropTypes.string, onChange: PropTypes.func.isRequired, diff --git a/src/components/transit-mode-select.js b/src/components/transit-mode-select.js deleted file mode 100644 index e190a1e..0000000 --- a/src/components/transit-mode-select.js +++ /dev/null @@ -1,31 +0,0 @@ -import React, {Component, PropTypes} from 'react' -import {connect} from 'react-redux' - -import {addActionLogItem, updateSelectedTransitMode} from '../actions' - -class TransitModeSelect extends Component { - static propTypes = { - className: PropTypes.string, - dispatch: PropTypes.func, - modes: PropTypes.arrayOf(PropTypes.object).isRequired, - selected: PropTypes.object - }; - - render () { - const {dispatch, className, modes, selected} = this.props - - return ( - - ) - } -} - -export default connect((s) => s.transitMode)(TransitModeSelect) diff --git a/src/components/transit-scenario-select.js b/src/components/transit-scenario-select.js deleted file mode 100644 index 89bfef9..0000000 --- a/src/components/transit-scenario-select.js +++ /dev/null @@ -1,31 +0,0 @@ -import React, {Component, PropTypes} from 'react' -import {connect} from 'react-redux' - -import {addActionLogItem, updateSelectedTransitScenario} from '../actions' - -class TransitScenarioSelect extends Component { - static propTypes = { - className: PropTypes.string, - dispatch: PropTypes.function, - scenarios: PropTypes.arrayOf(PropTypes.object).isRequired, - selected: PropTypes.object - }; - - render () { - const {dispatch, className, scenarios, selected} = this.props - - return ( - - ) - } -} - -export default connect((s) => s.transitScenario)(TransitScenarioSelect) diff --git a/src/components/transitive-map-layer/index.js b/src/components/transitive-map-layer/index.js index b387b64..7ac0a43 100644 --- a/src/components/transitive-map-layer/index.js +++ b/src/components/transitive-map-layer/index.js @@ -1,4 +1,5 @@ import {Map} from 'leaflet' +import isEqual from 'lodash.isequal' import {PropTypes} from 'react' import {MapLayer} from 'react-leaflet' import Transitive from 'transitive-js' @@ -9,7 +10,11 @@ export default class TransitiveMapLayer extends MapLayer { data: PropTypes.object.isRequired, map: PropTypes.instanceOf(Map), styles: PropTypes.object - }; + } + + shouldComponentUpdate (newProps, newState) { + return !isEqual(newProps, this.props) || !isEqual(newState, this.state) + } componentWillMount () { super.componentWillMount() diff --git a/src/containers/indianapolis/form.js b/src/containers/indianapolis/form.js index d502d46..aac83b7 100644 --- a/src/containers/indianapolis/form.js +++ b/src/containers/indianapolis/form.js @@ -1,61 +1,65 @@ import React from 'react' import Geocoder from 'react-select-geocoder' +import DeepEqual from '../../components/deep-equal' import featureToLabel from '../../utils/feature-to-label' import {search} from '../../utils/mapbox-geocoder' import messages from '../../utils/messages' -const Form = ({ - geocoder, - onChangeEnd, - onChangeStart, - onTimeCutoffChange, - selectedTimeCutoff -}) => ( -
-
{messages.Geocoding.StartTitle}
-
- f.id} - name='start-address' - onChange={onChangeStart} - placeholder={messages.Geocoding.StartPlaceholder} - search={search} - searchPromptText={messages.Geocoding.PromptText} - value={geocoder.origin} - /> -
-
{messages.Geocoding.EndTitle}
-
- f.id} - name='end-address' - onChange={onChangeEnd} - placeholder={messages.Geocoding.EndPlaceholder} - search={search} - searchPromptText={messages.Geocoding.PromptText} - value={geocoder.destination} - /> -
-
{messages.Strings.HighlightAreaAccessibleWithin}
-
-
{selectedTimeCutoff} {messages.Units.Minutes}
- -
-
-) - -export default Form +export default class Form extends DeepEqual { + render () { + const { + geocoder, + onChangeEnd, + onChangeStart, + onTimeCutoffChange, + selectedTimeCutoff + } = this.props + return ( +
+
{messages.Geocoding.StartTitle}
+
+ f.id} + name='start-address' + onChange={onChangeStart} + placeholder={messages.Geocoding.StartPlaceholder} + search={search} + searchPromptText={messages.Geocoding.PromptText} + value={geocoder.origin} + /> +
+
{messages.Geocoding.EndTitle}
+
+ f.id} + name='end-address' + onChange={onChangeEnd} + placeholder={messages.Geocoding.EndPlaceholder} + search={search} + searchPromptText={messages.Geocoding.PromptText} + value={geocoder.destination} + /> +
+
{messages.Strings.HighlightAreaAccessibleWithin}
+
+
{selectedTimeCutoff} {messages.Units.Minutes}
+ +
+
+ ) + } +} diff --git a/src/containers/indianapolis/index.js b/src/containers/indianapolis/index.js index 42fe64c..20539d1 100644 --- a/src/containers/indianapolis/index.js +++ b/src/containers/indianapolis/index.js @@ -219,6 +219,7 @@ class Indianapolis extends Component { }
+
Log
diff --git a/src/containers/indianapolis/map.js b/src/containers/indianapolis/map.js index 9ca1dd6..7de571e 100644 --- a/src/containers/indianapolis/map.js +++ b/src/containers/indianapolis/map.js @@ -1,14 +1,14 @@ import {Browser} from 'leaflet' import React, {PropTypes} from 'react' import {GeoJson, Map as LeafletMap, Marker, Popup, TileLayer} from 'react-leaflet' -import PureComponent from 'react-pure-render/component' +import DeepEqual from '../../components/deep-equal' import Icon from '../../components/icon' import messages from '../../utils/messages' import TransitiveLayer from '../../components/transitive-map-layer' import transitiveStyle from './transitive-style' -export default class Map extends PureComponent { +export default class Map extends DeepEqual { static propTypes = { centerCoordinates: PropTypes.arrayOf(PropTypes.number), clearStartAndEnd: PropTypes.func.isRequired, diff --git a/src/reducers/geocoder.js b/src/reducers/geocoder.js index 6b79d9a..7151b82 100644 --- a/src/reducers/geocoder.js +++ b/src/reducers/geocoder.js @@ -1,15 +1,7 @@ import {handleActions} from 'redux-actions' -function setQueryParameters (opts) { - window.location.hash = `start=${encodeURIComponent(opts.start)}&end=${encodeURIComponent(opts.end || '')}` -} - export default handleActions({ 'set origin' (state, {payload}) { - setQueryParameters({ - start: payload.label, - end: (state.destination && state.destination.label) - }) return { ...state, origin: { @@ -19,10 +11,6 @@ export default handleActions({ } }, 'set destination' (state, {payload}) { - setQueryParameters({ - start: (state.origin && state.origin.label), - end: payload.label - }) return { ...state, destination: { @@ -32,20 +20,12 @@ export default handleActions({ } }, 'clear start' (state) { - setQueryParameters({ - start: null, - end: (state.destination && state.destination.label) - }) return { ...state, origin: null } }, 'clear end' (state) { - setQueryParameters({ - start: (state.origin && state.origin.label), - end: null - }) return { ...state, destination: null diff --git a/src/router.js b/src/router.js deleted file mode 100644 index 669bf65..0000000 --- a/src/router.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react' -import { - Route, - Router -} from 'react-router' - -import Indianapolis from './containers/indianapolis' - -export default function ApplicationRouter ({history}) { - return ( - - - - ) -} diff --git a/src/utils/hash.js b/src/utils/hash.js new file mode 100644 index 0000000..babea23 --- /dev/null +++ b/src/utils/hash.js @@ -0,0 +1,20 @@ +import {parse as parseQueryString} from 'qs' + +function set (opts) { + window.location.hash = Object + .keys(opts) + .filter((key) => opts[key] !== undefined && opts[key] !== null) + .map((key) => `${key}=${encodeURIComponent(opts[key])}`) + .join('&') +} + +export function getAsObject () { + return parseQueryString(window.location.hash.split('#')[1]) +} + +export function setKeyTo (key, value) { + set({ + ...getAsObject(), + [`${key}`]: value + }) +} diff --git a/src/utils/initialize-browsochrones.js b/src/utils/initialize-browsochrones.js index 73ff6ed..8322eaf 100644 --- a/src/utils/initialize-browsochrones.js +++ b/src/utils/initialize-browsochrones.js @@ -1,8 +1,8 @@ import Browsochrones from 'browsochrones' import fetch from 'isomorphic-fetch' import lonlng from 'lonlng' -import {parse as parseQueryString} from 'qs' +import {getAsObject as getHash} from './hash' import {geocode} from './mapbox-geocoder' import messages from './messages' @@ -33,7 +33,7 @@ export default async function initialize ({ actions.push(setBrowsochronesComparison(bs2)) } - const qs = parseQueryString(window.location.hash.split('#')[1]) + const qs = getHash() if (qs.start) { actions.push(...(await loadFromQueryString({bs1, bs2, geocoder, map, qs}))) } diff --git a/src/utils/raf-scheduler.js b/src/utils/raf-scheduler.js deleted file mode 100644 index a953b59..0000000 --- a/src/utils/raf-scheduler.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Schedules actions with { meta: { raf: true } } to be dispatched inside a rAF loop - * frame. Makes `dispatch` return a function to remove the action from the queue in - * this case. http://redux.js.org/docs/advanced/Middleware.html - */ - -export default function rafScheduler (store) { - return function (next) { - let queuedActions = [] - let frame = null - - function loop () { - frame = null - try { - if (queuedActions.length) { - next(queuedActions.shift()) - } - } finally { - maybeRaf() - } - } - - function maybeRaf () { - if (queuedActions.length && !frame) { - frame = window.requestAnimationFrame(loop) - } - } - - return function (action) { - if (!action.meta || !action.meta.raf) { - return next(action) - } - - queuedActions.push(action) - maybeRaf() - - return function cancel () { - queuedActions = queuedActions.filter((a) => a !== action) - } - } - } -} diff --git a/yarn.lock b/yarn.lock index ebc7bb8..f08661b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1303,9 +1303,9 @@ browserslist@^1.0.0, browserslist@^1.0.1, browserslist@^1.4.0, browserslist@~1.4 dependencies: caniuse-db "^1.0.30000539" -browsochrones@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/browsochrones/-/browsochrones-0.7.1.tgz#736a9bb9ef8cec722aacb777d003b86a370914bd" +browsochrones@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/browsochrones/-/browsochrones-0.8.0.tgz#c8b3c6b19c7d632241409a26974ed7d6a615b1e6" dependencies: color "^0.11.3" debug "^2.2.0" @@ -1937,10 +1937,6 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" -declarative-fetch@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/declarative-fetch/-/declarative-fetch-0.1.13.tgz#4b1d67c595bd8ee3ea1977a02f8113445f86bc72" - dedent@0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.6.0.tgz#0e6da8f0ce52838ef5cec5c8f9396b0c1b64a3cb" @@ -2167,10 +2163,6 @@ es6-map@^0.1.3: es6-symbol "~3.1.0" event-emitter "~0.3.4" -es6-promise@^3.0.2: - version "3.3.1" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" - es6-set@~0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" @@ -4040,6 +4032,10 @@ lodash.isempty@^4.2.1: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" +lodash.isequal: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.4.0.tgz#6295768e98e14dc15ce8d362ef6340db82852031" + lodash.isobject@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d" @@ -5560,27 +5556,6 @@ redux-actions@^0.12.0: lodash "^4.13.1" reduce-reducers "^0.1.0" -redux-batched-subscribe@^0.1.4: - version "0.1.6" - resolved "https://registry.yarnpkg.com/redux-batched-subscribe/-/redux-batched-subscribe-0.1.6.tgz#de928602708df7198b4d0c98c7119df993780d59" - -redux-effects-fetch@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/redux-effects-fetch/-/redux-effects-fetch-0.5.5.tgz#a54e9842c96caf60a1dcf786b82cdd57649dffc8" - dependencies: - es6-promise "^3.0.2" - isomorphic-fetch "^2.1.1" - -redux-effects-timeout@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/redux-effects-timeout/-/redux-effects-timeout-0.1.7.tgz#7d8fe8fca13f94d6e91ec92e6286383c80eae562" - -redux-effects@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/redux-effects/-/redux-effects-0.4.3.tgz#147302d90a2674e6201dd9fe92e2ee9f5f16b0c6" - dependencies: - is-promise "^2.1.0" - redux-logger@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-2.7.0.tgz#77f0ee5c473b1440c7e1b3c3c7775e59741c5dbf"