Skip to content

Commit

Permalink
Merge pull request #69 from SmartColumbusOS/smrt-1245
Browse files Browse the repository at this point in the history
Smrt 1245 - Accepts url params for route filtering
  • Loading branch information
dickthedev authored May 30, 2019
2 parents 7946aea + 7f30996 commit f424e5f
Show file tree
Hide file tree
Showing 26 changed files with 1,702 additions and 618 deletions.
1,750 changes: 1,276 additions & 474 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"file-loader": "1.1.5",
"fs-extra": "3.0.1",
"html-webpack-plugin": "2.29.0",
"jest": "20.0.4",
"jest": "^23.6.0",
"leaflet": "^1.3.1",
"lodash": "^4.17.10",
"moment": "^2.22.2",
Expand All @@ -48,9 +48,11 @@
"react-leaflet-rotatedmarker": "^0.1.0",
"react-loader": "^2.4.5",
"react-redux": "^5.0.7",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0",
"react-select": "^2.0.0",
"redux": "^4.0.0",
"redux-saga": "^0.16.0",
"redux-saga": "^0.16.2",
"resolve": "1.6.0",
"style-loader": "0.19.0",
"sw-precache-webpack-plugin": "0.11.4",
Expand Down
11 changes: 8 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import React from 'react'
import COTAPositionMap from './components/cota-position-map'
import RouteFilter from './components/route-filter'
import DropdownRouteFilter from './components/dropdown-route-filter'
import UrlRouteFilter from './components/url-route-filter'
import Header from './components/header'
import { HashRouter as Router, Route } from 'react-router-dom'

import './App.scss'

export default () => (
<main-app-element>
<Header />
<div className='main-content'>
<RouteFilter />
<COTAPositionMap />
<Router>
<DropdownRouteFilter />
<Route path='/:routeId?' component={UrlRouteFilter} />
<COTAPositionMap />
</Router>
</div>
</main-app-element>
)
4 changes: 2 additions & 2 deletions src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export const ceavUpdate = (message) => {
return { type: CEAV_UPDATE, update: message }
}

export const routeFilter = (filter) => {
export const applyStreamFilter = (filter) => {
return { type: ROUTE_FILTER, filter: filter }
}

export const routeFetch = () => {
export const fetchAvailableRoutes = () => {
return { type: ROUTE_FETCH }
}

Expand Down
12 changes: 6 additions & 6 deletions src/components/cota-position-map/icon-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import leaflet from 'leaflet'
import busBlueSvg from '../../assets/blue-bus.svg'
import ceavSvg from '../../assets/smart_circuit.svg'
import locationPin from '../../assets/ic_location-dot.svg'
import { CEAV } from '../../variables';
import { CEAV } from '../../variables'

const createBusIcon = (zoomLevel, provider) => {
let iconUrl = busBlueSvg
let iconUrl = busBlueSvg
let iconSize = [3.2 * zoomLevel, 2.75 * zoomLevel]
if(CEAV === provider) {
iconUrl = ceavSvg
iconSize = [2 * zoomLevel, 2 * zoomLevel]
if (CEAV === provider) {
iconUrl = ceavSvg
iconSize = [2 * zoomLevel, 2 * zoomLevel]
}

return leaflet.icon({
iconUrl: iconUrl,
iconSize: iconSize
Expand Down
2 changes: 1 addition & 1 deletion src/components/cota-position-map/icon-factory.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('Icon Factory', () => {
})

it('creates green bus icons for CEAV shuttles', () => {
iconFactory.createBusIcon(10, "CEAV")
iconFactory.createBusIcon(10, 'CEAV')

expect(leaflet.icon).toHaveBeenCalledWith({
iconUrl: smartCircuitIcon,
Expand Down
6 changes: 3 additions & 3 deletions src/components/cota-position-map/map.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('map', () => {

it('gives each marker a bus icon that is constructed with the default zoom level of 12', () => {
expect(subject.find(RotatedMarker).map(it => it.props().icon)).toEqual(vehicles.map(it => fakeIcon))
expect(iconFactory.createBusIcon.mock.calls).toEqual(vehicles.map(it => [12, "LeroyJenkins"]))
expect(iconFactory.createBusIcon.mock.calls).toEqual(vehicles.map(it => [12, 'LeroyJenkins']))
})

describe('viewport is updated', () => {
Expand All @@ -47,7 +47,7 @@ describe('map', () => {
})

it('updates the icon scale when viewport is changed', () => {
expect(iconFactory.createBusIcon.mock.calls).toEqual(vehicles.map(it => ['some new zoom', "LeroyJenkins"]))
expect(iconFactory.createBusIcon.mock.calls).toEqual(vehicles.map(it => ['some new zoom', 'LeroyJenkins']))
})
})

Expand All @@ -72,7 +72,7 @@ describe('map', () => {
longitude: lng,
bearing: bearing,
timestamp: 123000,
provider: "LeroyJenkins"
provider: 'LeroyJenkins'
}
}
})
14 changes: 14 additions & 0 deletions src/components/dropdown-route-filter/connect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { applyStreamFilter, fetchAvailableRoutes } from '../../actions'
import DropdownRouteFilter from './dropdown-route-filter'
import _ from 'lodash'

const mapStateToProps = state => ({
availableRoutes: state.availableRoutes,
selectedRouteId: _.first(state.filter)
})

const mapDispatchToProps = dispatch => bindActionCreators({ applyStreamFilter, fetchAvailableRoutes }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(DropdownRouteFilter)
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import React from 'react'
import Select from 'react-select'
import _ from 'lodash'
import './route-filter.scss'
import './dropdown-route-filter.scss'
import ReactGA from 'react-ga'

export default class extends React.Component {
componentDidMount = () => {
this.props.routeFetch()
this.props.fetchAvailableRoutes()
}

handleChange = selectedOption => {
const value = _.flatten([selectedOption])
.map(option => option.value)
.filter(option => option)

this.props.routeFilter(value)
this.props.applyStreamFilter(value)

ReactGA.event({
category: 'Navigation',
Expand All @@ -24,19 +24,19 @@ export default class extends React.Component {
}

render = () => {
const { routes, selectedRouteId } = this.props
const selectedRoute = _.find(routes, {value: selectedRouteId})
const { availableRoutes, selectedRouteId } = this.props
const selectedRoute = _.find(availableRoutes, { value: selectedRouteId })

return <route-filter>
return <dropdown-route-filter>
<Select
id='routeSelect'
value={selectedRoute}
onChange={this.handleChange}
options={routes}
options={availableRoutes}
placeholder=''
backspaceRemovesValue={false}
isSearchable={false}
/>
</route-filter>
</dropdown-route-filter>
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@import '../../styles/variables.scss';
@import '../../styles/mixins.scss';

route-filter {
dropdown-route-filter {
@include flex-row();
text-align: left;
z-index: 10;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import React from 'react'
import RouteFilter from './route-filter'
import DropdownRouteFilter from './dropdown-route-filter'
import { shallow } from 'enzyme'
import ReactGA from 'react-ga'

jest.mock('react-ga', () => ({
event: jest.fn()
}))

describe('RouteFilter', () => {
let subject, routeFilterStub, routeFetchStub, dropdown, fakeRoutes
describe('DropdownRouteFilter', () => {
let subject, applyStreamFilterStub, fetchAvailableRoutesStub, dropdown, fakeRoutes

beforeEach(() => {
fakeRoutes = [{value: 'some cool route', label: 'a label'}, {value: '2', label: 'second route'}]
fakeRoutes = [{ value: 'some cool route', label: 'a label' }, { value: '2', label: 'second route' }]

ReactGA.event.mockClear()

routeFilterStub = jest.fn()
routeFetchStub = jest.fn()
subject = shallow(<RouteFilter selectedRouteId={fakeRoutes[0].value}
routeFilter={routeFilterStub}
routeFetch={routeFetchStub}
routes={fakeRoutes} />)
applyStreamFilterStub = jest.fn()
fetchAvailableRoutesStub = jest.fn()
subject = shallow(<DropdownRouteFilter selectedRouteId={fakeRoutes[0].value}
applyStreamFilter={applyStreamFilterStub}
fetchAvailableRoutes={fetchAvailableRoutesStub}
availableRoutes={fakeRoutes} />)
dropdown = subject.find('[id="routeSelect"]')
})

Expand All @@ -29,15 +29,15 @@ describe('RouteFilter', () => {
})

it('passes the selected value to its route filter function', () => {
dropdown.simulate('change', {value: '001', label: 'whonko'})
dropdown.simulate('change', { value: '001', label: 'whonko' })

expect(routeFilterStub).toBeCalledWith(['001'])
expect(applyStreamFilterStub).toBeCalledWith(['001'])
})

it('passes an empty list to its route filter when given a change with no value (signal to clear selection)', () => {
dropdown.simulate('change', { label: 'Timmay!' })

expect(routeFilterStub).toBeCalledWith([])
expect(applyStreamFilterStub).toBeCalledWith([])
})

describe('Google Analytics', () => {
Expand Down
3 changes: 3 additions & 0 deletions src/components/dropdown-route-filter/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import DropdownRouteFilter from './connect'

export default DropdownRouteFilter
14 changes: 0 additions & 14 deletions src/components/route-filter/connect.js

This file was deleted.

3 changes: 0 additions & 3 deletions src/components/route-filter/index.js

This file was deleted.

14 changes: 14 additions & 0 deletions src/components/url-route-filter/connect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { applyStreamFilter, fetchAvailableRoutes } from '../../actions'
import UrlRouteFilter from './url-route-filter'
import _ from 'lodash'

const mapStateToProps = state => ({
availableRoutes: state.availableRoutes,
selectedRouteId: _.first(state.filter)
})

const mapDispatchToProps = dispatch => bindActionCreators({ applyStreamFilter, fetchAvailableRoutes }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(UrlRouteFilter)
3 changes: 3 additions & 0 deletions src/components/url-route-filter/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import UrlRouteFilter from './connect'

export default UrlRouteFilter
46 changes: 46 additions & 0 deletions src/components/url-route-filter/url-route-filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react'
import _ from 'lodash'

const CMAX_LINE_NUMBER = '101'

export default class extends React.Component {
componentDidMount = () => {
this.props.fetchAvailableRoutes()
}

updateUrl = (id) => {
return this.props.history.push(id)
}

updateState = (id) => {
return this.props.applyStreamFilter([id])
}

routeIsNotValid = (id) => {
return _.find(this.props.availableRoutes, { value: id }) === undefined
}

componentDidUpdate = (previousProps) => {
const { selectedRouteId, match: { params: { routeId: urlRouteId } } } = this.props

const stateAndUrlOutOfSync = selectedRouteId !== urlRouteId
const stateWasUpdated = selectedRouteId !== previousProps.selectedRouteId

if (this.routeIsNotValid(urlRouteId)) {
this.updateState(CMAX_LINE_NUMBER)
return this.updateUrl(CMAX_LINE_NUMBER)
}

if (stateAndUrlOutOfSync) {
if (stateWasUpdated) {
return this.updateUrl(selectedRouteId)
} else {
return this.updateState(urlRouteId)
}
}
}

render = () => {
return <url-route-filter />
}
}
Loading

0 comments on commit f424e5f

Please sign in to comment.