diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..eb260ed
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "todo-tree.flat": true,
+ "todo-tree.grouped": false,
+ "todo-tree.expanded": true
+}
\ No newline at end of file
diff --git a/src/actions/index.js b/src/actions/index.js
index 1317976..97423d2 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -91,6 +91,13 @@ export const polygonReset = () => {
}
}
+export const mapCenterUpdate = (lat, lon) => {
+ return {
+ type: types.GEO_MAPCENTER_UPDATE,
+ payload: [lat, lon]
+ }
+}
+
// AGENCY
export const getAgency = () => ({
diff --git a/src/actions/route.js b/src/actions/route.js
new file mode 100644
index 0000000..0996619
--- /dev/null
+++ b/src/actions/route.js
@@ -0,0 +1,64 @@
+import { RSAA } from 'redux-api-middleware'
+
+import * as types from '../constants/ActionTypes'
+import { RSAAHeaders } from '../utils/ApiClient'
+import { API_URL } from '../constants/Api'
+
+
+export const getRoute = (query) => ({
+ [RSAA]: {
+ endpoint: `${API_URL}/route/?${query || ''}`,
+ method: 'GET',
+ headers: RSAAHeaders,
+ bailout: (state) => state.route.fetching,
+ types: [
+ types.ROUTE_REQUEST,
+ types.ROUTE_SUCCESS,
+ types.ROUTE_FAILURE,
+ ]
+ }
+})
+
+export const updateRoute = (id, body) => ({
+ [RSAA]: {
+ endpoint: `${API_URL}/route/${id}/`,
+ body: JSON.stringify(body),
+ method: 'PATCH',
+ headers: RSAAHeaders,
+ types: [
+ types.ROUTE_REQUEST,
+ types.ROUTE_UPDATE,
+ types.ROUTE_FAILURE,
+ ]
+ }
+})
+
+export const createRoute = (body) => ({
+ [RSAA]: {
+ endpoint: `${API_URL}/route/`,
+ body: JSON.stringify(body),
+ method: 'POST',
+ headers: RSAAHeaders,
+ types: [
+ types.ROUTE_REQUEST,
+ types.ROUTE_CREATE,
+ types.ROUTE_FAILURE,
+ ]
+ }
+})
+
+export const deleteRoute = (id) => ({
+ [RSAA]: {
+ endpoint: `${API_URL}/route/${id}/`,
+ method: 'DELETE',
+ headers: RSAAHeaders,
+ types: [
+ types.ROUTE_REQUEST,
+ {
+ type: types.ROUTE_DELETE,
+ meta: { id }
+ },
+ types.ROUTE_FAILURE,
+ ]
+ }
+})
diff --git a/src/actions/stop.js b/src/actions/stop.js
new file mode 100644
index 0000000..ad77118
--- /dev/null
+++ b/src/actions/stop.js
@@ -0,0 +1,64 @@
+import { RSAA } from 'redux-api-middleware'
+
+import * as types from '../constants/ActionTypes'
+import { RSAAHeaders } from '../utils/ApiClient'
+import { API_URL } from '../constants/Api'
+
+
+export const getStop = (query) => ({
+ [RSAA]: {
+ endpoint: `${API_URL}/stop/?${query || ''}`,
+ method: 'GET',
+ headers: RSAAHeaders,
+ bailout: (state) => state.stop.fetching,
+ types: [
+ types.STOP_REQUEST,
+ types.STOP_SUCCESS,
+ types.STOP_FAILURE,
+ ]
+ }
+})
+
+export const updateStop = (id, body) => ({
+ [RSAA]: {
+ endpoint: `${API_URL}/stop/${id}/`,
+ body: JSON.stringify(body),
+ method: 'PATCH',
+ headers: RSAAHeaders,
+ types: [
+ types.STOP_REQUEST,
+ types.STOP_UPDATE,
+ types.STOP_FAILURE,
+ ]
+ }
+})
+
+export const createStop = (body) => ({
+ [RSAA]: {
+ endpoint: `${API_URL}/stop/`,
+ body: JSON.stringify(body),
+ method: 'POST',
+ headers: RSAAHeaders,
+ types: [
+ types.STOP_REQUEST,
+ types.STOP_CREATE,
+ types.STOP_FAILURE,
+ ]
+ }
+})
+
+export const deleteStop = (id) => ({
+ [RSAA]: {
+ endpoint: `${API_URL}/stop/${id}/`,
+ method: 'DELETE',
+ headers: RSAAHeaders,
+ types: [
+ types.STOP_REQUEST,
+ {
+ type: types.STOP_DELETE,
+ meta: { id }
+ },
+ types.STOP_FAILURE,
+ ]
+ }
+})
diff --git a/src/actions/stoptime.js b/src/actions/stoptime.js
index f574ca0..b4822a6 100644
--- a/src/actions/stoptime.js
+++ b/src/actions/stoptime.js
@@ -10,7 +10,7 @@ export const getStopTime = (query) => ({
endpoint: `${API_URL}/stoptime/?${query || ''}`,
method: 'GET',
headers: RSAAHeaders,
- bailout: (state) => state.stoptime.fetching,
+ bailout: (state) => state.stoptime.fetching || state.stoptime.query === query,
types: [
{
type: types.STOPTIME_REQUEST,
diff --git a/src/components/AgencyForm.js b/src/components/AgencyForm.js
index 57ebae2..2e4c665 100644
--- a/src/components/AgencyForm.js
+++ b/src/components/AgencyForm.js
@@ -184,7 +184,7 @@ const mapStateToProps = state => ({
agency: state.agency
})
-const connectAgencyList = connect(
+const connectAgencyForm = connect(
mapStateToProps,
)(AgencyForm)
-export default connectAgencyList
+export default connectAgencyForm
diff --git a/src/components/AgencyItem.js b/src/components/AgencyItem.js
index f1d8ac0..c6e93cf 100644
--- a/src/components/AgencyItem.js
+++ b/src/components/AgencyItem.js
@@ -1,10 +1,11 @@
import React, { Component } from 'react'
import styled from 'styled-components'
import { connect } from 'react-redux'
-import { Link, Redirect, Route } from 'react-router-dom'
+import { Link, Redirect, Route, Switch} from 'react-router-dom'
import Spinner from './Spinner'
import RouteList from './RouteList'
+import RouteForm from './RouteForm'
import FareAttrList from './FareAttrList'
const StyledAgencyItem = styled.div`
@@ -62,10 +63,13 @@ class AgencyItem extends Component {
Edit
-
-
-
-
+
+
+
+
+
+
+
{agencyChild === undefined && Pick options on the tab
}
diff --git a/src/components/Breadcrumb.js b/src/components/Breadcrumb.js
index 346c779..8dc0ea2 100644
--- a/src/components/Breadcrumb.js
+++ b/src/components/Breadcrumb.js
@@ -10,15 +10,19 @@ margin-bottom: 5px !important;
const Breadcrumb = (props) => (
-
+
- - ALL
+ - Stop
+ - Agency
{props.agencyId && -
{props.agencyId}
}
{props.routeId && -
{props.routeId}
}
+ {props.stopId && -
+
+ {props.stopId}
}
)
diff --git a/src/components/FloatPane.js b/src/components/FloatPane.js
index 9b0181f..dceed6e 100644
--- a/src/components/FloatPane.js
+++ b/src/components/FloatPane.js
@@ -1,11 +1,14 @@
import React, { Component } from 'react'
-import { Link, Route } from 'react-router-dom'
+import { Link, Route, Switch } from 'react-router-dom'
import { connect } from 'react-redux'
import styled from 'styled-components'
import { logout } from '../utils/Auth'
import RouteList from './RouteList'
import RouteDetail from './RouteDetail'
+import StopList from './StopList'
+import StopForm from './StopForm'
+import RouteForm from './RouteForm'
import Breadcrumb from './Breadcrumb'
import { polygonReset } from '../actions'
import store from '../store'
@@ -61,6 +64,11 @@ const SimpleAgencyList = (props) => (
Agency
+
+
+ New agency
+
+
{props.agencies.map(ele => (
{ele.name}
@@ -133,15 +141,29 @@ class FloatPane extends Component {
{this.renderTopLevel(loggedIn)}
- (
- )} />
+
+ (
+ )} />
+ (
+ )} />
+
+ (
+ )} />
+ (
+ )} />
+ (
+ )} />
+ (
+ )} />
+
(
)} />
-
- (
- )} />
diff --git a/src/components/RouteDetail.js b/src/components/RouteDetail.js
index ea8c102..ebacc45 100644
--- a/src/components/RouteDetail.js
+++ b/src/components/RouteDetail.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import styled from 'styled-components'
-import { Link, Route } from 'react-router-dom'
+import { Link, Route, Redirect } from 'react-router-dom'
import { connect } from 'react-redux'
import Spinner from './Spinner'
@@ -8,12 +8,6 @@ import { getRoute, polygonUpdate } from '../actions'
import { getStopTime } from '../actions/stoptime'
import store from '../store'
-/*
-TODO: add shape
-TODO: add Route detail
-
-*/
-
const StyledTripDesc = styled.div`
font-size: 0.87rem;
line-height: 0.85rem;
@@ -58,7 +52,7 @@ const TripList = (props) => (
{props.trips.map(ele => (
{ store.dispatch(getStopTime(`trip=${ele.id}`))}}>
+ onClick={() => { store.dispatch(getStopTime(`trip=${ele.id}&limit=100`))}}>
{ele.trip_id}
(ID {ele.id})
@@ -134,7 +128,10 @@ class RouteDetail extends Component {
const { routeId, agencyId, routeParams } = match.params
const tRoute = route.results.filter(ele => ele.route_id === routeId)
if (tRoute.length === 0) {
- return
+ if (route.fetching)
+ return
+
+ return
}
const item = tRoute[0]
const baseUrl = `/map/${agencyId}/route/${routeId}`
@@ -147,6 +144,7 @@ class RouteDetail extends Component {
detail
trip
fare
+ edit
(
)} />
diff --git a/src/components/RouteForm.js b/src/components/RouteForm.js
new file mode 100644
index 0000000..12a85d4
--- /dev/null
+++ b/src/components/RouteForm.js
@@ -0,0 +1,208 @@
+import React, { Component } from 'react'
+import styled from 'styled-components'
+import { connect } from 'react-redux'
+import { Redirect, Link } from 'react-router-dom'
+
+import HorizontalInput from './parts/HorizontalInput'
+import { updateRoute, createRoute, deleteRoute } from '../actions/route';
+import store from '../store'
+
+const StyledRouteForm = styled.div`
+padding: 1rem;
+background: #fafafa;
+`
+
+// TODO: need to deal with shapes
+
+class RouteForm extends Component {
+
+ state = {
+ id: null,
+ agency: null,
+ route_id: "",
+ short_name: "",
+ long_name: "",
+ desc: "",
+ route_type: "2",
+ route_url: "",
+ route_color: "",
+ route_text_color: "",
+ route_sort_order: "0",
+ }
+
+ constructor() {
+ super()
+ this.handleChange = this.handleChange.bind(this)
+ this.handleSubmit = this.handleSubmit.bind(this)
+ this.handleDelete = this.handleDelete.bind(this)
+ this.renderForm = this.renderForm.bind(this)
+ }
+
+ handleChange(evt) {
+ let updated = {}
+ updated[evt.target.name] = evt.target.value
+ this.setState(updated)
+ }
+
+ handleSubmit() {
+ const { id } = this.state
+ let body = { ...this.state }
+ delete body.id
+ delete body.farerule_set
+ delete body.trip_set
+ delete body.geojson
+ if (id !== null) {
+ store.dispatch(updateRoute(id, body))
+ } else {
+ store.dispatch(createRoute(body))
+ }
+ this.setState({justSubmit: true})
+ }
+
+ handleDelete() {
+ const { id } = this.state
+ store.dispatch(deleteRoute(id))
+ this.setState({justSubmit: true})
+ }
+
+ componentWillMount() {
+ const { props } = this
+ const { agencyId, routeId } = props.match.params
+ const { results } = props.route
+ const ones = results.filter(ele => ele.route_id === routeId)
+ if (ones.length > 0) {
+ this.setState(ones[0])
+ props.updateBreadcrumb({ agencyId, routeId })
+ } else {
+ const agencies = props.agency.results.filter(ele => ele.agency_id === agencyId)
+ if (agencies.length > 0) {
+ let d = {}
+ d["agency_id"] = agencies[0].id
+ this.setState(d)
+ props.updateBreadcrumb({ agencyId, routeId: 'new' })
+ }
+ }
+ }
+
+ renderForm() {
+ const one = this.state
+ const { agencyId, routeId } = this.props.match.params
+ const { agency } = this.props
+ const agencies = agency.results.filter(ele => ele.agency_id === agencyId)
+ const { fetching } = this.props.route
+ return (
+
+ {one.route_id || 'New Route'}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {one.id !== null &&
+
+
}
+
+ {agencies[0] &&
+ Cancel}
+
+
+
+ )
+ }
+
+ render () {
+ const one = this.state
+ const { fetching } = this.props.agency
+ // redirect to view page if no data
+ const { agencyId } = this.props.match.params
+ // redirect to agency list if submitted
+ if (one.justSubmit === true && !fetching) {
+ return
+ }
+ return this.renderForm()
+ }
+
+}
+
+
+const mapStateToProps = state => ({
+ agency: state.agency,
+ route: state.route,
+})
+
+const connectRouteForm = connect(
+ mapStateToProps,
+)(RouteForm)
+export default connectRouteForm
diff --git a/src/components/RouteList.js b/src/components/RouteList.js
index c5a93ee..3ed5d07 100644
--- a/src/components/RouteList.js
+++ b/src/components/RouteList.js
@@ -37,7 +37,7 @@ class RouteList extends Component {
return (