diff --git a/src/components/RouteDetail.js b/src/components/RouteDetail.js
new file mode 100644
index 0000000..ea8c102
--- /dev/null
+++ b/src/components/RouteDetail.js
@@ -0,0 +1,167 @@
+import React, { Component } from 'react'
+import styled from 'styled-components'
+import { Link, Route } from 'react-router-dom'
+import { connect } from 'react-redux'
+
+import Spinner from './Spinner'
+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;
+margin-left: 10px;
+`
+
+
+const RouteDesc = (props) => (
+
+
+ ID: {props.route.id}
+
+
+ long_name: {props.route.long_name}
+
+
+ short_name: {props.route.short_name}
+
+
+ type: {props.route.route_type}
+
+
+ color:
Text #{props.route.text_color || '-'}
BG #{props.route.route_text_color}
+
+
+ Sort order: {props.route.route_sort_order}
+
+
+ URL: {props.route.route_url || '-'}
+
+
+ desc: {props.route.desc || '-'}
+
+
+ shapes: {props.route.geosjson !== null ? 'yes' : 'n/a'}
+
+
+)
+
+
+const TripList = (props) => (
+
+ {props.trips.map(ele => (
+
{ store.dispatch(getStopTime(`trip=${ele.id}`))}}>
+ {ele.trip_id}
+
+ (ID {ele.id})
+ service {ele.service.service_id}
+
+ {ele.stoptime.count > 0 &&
+ Stop #{ele.stoptime.count}
+
+ Time period {ele.stoptime.period[0]} - {ele.stoptime.period[1]}
+
}
+
+
+ ))}
+ {props.trips.length === 0 &&
+ No trip set
+ }
+
+)
+
+const FareRuleList = (props) => (
+
+ {props.farerules.map(ele => (
+
+ {ele.fare.fare_id} - {ele.fare.price}
+
+ ))}
+ {props.farerules.length === 0 &&
+ No fare rule set
+ }
+
+)
+
+class RouteDetail extends Component {
+
+ state = {
+ tab: 'detail',
+ }
+
+ componentDidMount() {
+ const { updateBreadcrumb, match } = this.props
+ updateBreadcrumb(match.params)
+ }
+
+ componentWillMount() {
+ const { route, match } = this.props
+ if (route.count === 0) {
+ store.dispatch(getRoute(`agency=${match.params.agencyId}`))
+ } else {
+ this.pushShapeToStore(match, route)
+ }
+ }
+
+ componentWillReceiveProps(newProps) {
+ if (this.props.route.count < newProps.route.count) {
+ this.pushShapeToStore(this.props.match, newProps.route)
+ }
+ }
+
+ pushShapeToStore(match, routeStore) {
+ const { routeId } = match.params
+ const tRoute = routeStore.results.filter(ele => ele.route_id === routeId)
+ if (tRoute.length === 0)
+ return
+ const one = tRoute[0]
+ const oneStyle = {}
+ if (one.route_color)
+ oneStyle['color'] = `#${one.route_color}`
+ store.dispatch(polygonUpdate(one.route_id, one.geojson, oneStyle))
+ }
+
+ render() {
+ const { route, match } = this.props
+ const { routeId, agencyId, routeParams } = match.params
+ const tRoute = route.results.filter(ele => ele.route_id === routeId)
+ if (tRoute.length === 0) {
+ return
+ }
+ const item = tRoute[0]
+ const baseUrl = `/map/${agencyId}/route/${routeId}`
+ return (
+
+ )
+ }
+}
+
+const mapStateToProps = state => ({
+ route: state.route,
+})
+export default connect(
+ mapStateToProps
+)(RouteDetail)
diff --git a/src/components/RouteList.js b/src/components/RouteList.js
index 6635d79..c5a93ee 100644
--- a/src/components/RouteList.js
+++ b/src/components/RouteList.js
@@ -1,16 +1,27 @@
import React, { Component } from 'react'
+import styled from 'styled-components'
import { connect } from 'react-redux'
+import { Link } from 'react-router-dom'
import Spinner from './Spinner'
import { getRoute } from '../actions'
import store from '../store'
+const StyledLongName = styled.div`
+margin-left: 1rem;
+font-size: 0.9rem;
+font-style: italic;
+color: #444;
+`
class RouteList extends Component {
componentDidMount() {
- const { agencyId } = this.props.match.params
+ const { updateBreadcrumb, match } = this.props
+ const { agencyId } = match.params
store.dispatch(getRoute(`agency=${agencyId}`))
+ if (updateBreadcrumb)
+ updateBreadcrumb(match.params)
}
componentWillReceiveProps(newProps) {
@@ -20,20 +31,36 @@ class RouteList extends Component {
}
render() {
- const { route } = this.props
+ const { route, match } = this.props
+ const { agencyId } = match.params
return (
-
-
Routes
-
-
- {route.count === 0 && - No route
}
- {route.count > 0
- && route.results.map(ele => (
- - { ele.route_id }
)
- )}
-
-
+
)
}
}
diff --git a/src/components/Spinner.js b/src/components/Spinner.js
index ae24a81..592a2f9 100644
--- a/src/components/Spinner.js
+++ b/src/components/Spinner.js
@@ -2,7 +2,7 @@ import React from 'react'
const Spinner = (props) => (
- {props.show && }
+ {props.show && }
)
diff --git a/src/constants/ActionTypes.js b/src/constants/ActionTypes.js
index 4394a87..5d92150 100644
--- a/src/constants/ActionTypes.js
+++ b/src/constants/ActionTypes.js
@@ -1,14 +1,18 @@
-export const FIRST_INCREMENT_COUNTER = 'FIRST_INCREMENT_COUNTER'
-export const FIRST_ASSIGN_ID = 'FIRST_ASSIGN_ID'
-// export const SET_TOKEN = 'SET_TOKEN'
+export const GEO_LOCATION_SUCCESS = 'GEO_LOCATION_SUCCESS'
+export const GEO_LOCATION_FAILURE = 'GEO_LOCATION_FAILURE'
+export const GEO_POLYGON_ADD = 'GEO_POLYGON_ADD'
+export const GEO_POLYGON_RESET = 'GEO_POLYGON_RESET'
+export const GEO_POLYGON_UPDATE = 'GEO_POLYGON_UPDATE'
+export const GEO_MARKER_ADD = 'GEO_MARKER_ADD'
+export const GEO_MARKER_RESET = 'GEO_MARKER_RESET'
+export const GEO_MARKER_UPDATE = 'GEO_MARKER_UPDATE'
export const REQUEST_LOGIN = 'REQUEST_LOGIN'
export const SUCCESS_LOGIN = 'SUCCESS_LOGIN'
export const FAILED_LOGIN = 'FAILED_LOGIN'
export const SUCCESS_LOGOUT = 'SUCCESS_LOGOUT'
-
export const AGENCY_REQUEST = 'AGENCY_REQUEST'
export const AGENCY_FAILURE = 'AGENCY_FAILURE'
export const AGENCY_SUCCESS = 'AGENCY_SUCCESS'
@@ -18,6 +22,14 @@ export const AGENCY_DELETE = 'AGENCY_DELETE'
export const AGENCY_UPDATE = 'AGENCY_UPDATE'
+export const STOPTIME_REQUEST = 'STOPTIME_REQUEST'
+export const STOPTIME_FAILURE = 'STOPTIME_FAILURE'
+export const STOPTIME_SUCCESS = 'STOPTIME_SUCCESS'
+// below items are SUCCESS for other tasks
+export const STOPTIME_CREATE = 'STOPTIME_CREATE'
+export const STOPTIME_DELETE = 'STOPTIME_DELETE'
+export const STOPTIME_UPDATE = 'STOPTIME_UPDATE'
+
export const ROUTE_REQUEST = 'ROUTE_REQUEST'
export const ROUTE_FAILURE = 'ROUTE_FAILURE'
export const ROUTE_SUCCESS = 'ROUTE_SUCCESS'
diff --git a/src/container/Geo.js b/src/container/Geo.js
new file mode 100644
index 0000000..07bdf48
--- /dev/null
+++ b/src/container/Geo.js
@@ -0,0 +1,134 @@
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+import styled from 'styled-components'
+// import { Redirect, Route, Switch } from 'react-router-dom'
+import {
+ Map, TileLayer, CircleMarker, ZoomControl,
+ FeatureGroup, GeoJSON } from 'react-leaflet'
+// import { EditControl } from 'react-leaflet-draw'
+// import L from 'leaflet'
+
+import { loggedIn } from '../reducers/auth'
+import { geoLocationFailed, geoLocationUpdate, getAgency } from '../actions'
+import FloatPane from '../components/FloatPane'
+import store from '../store'
+
+
+const FullPageBox = styled.div`
+height: 100%;
+min-height: 100vh;
+z-index: 1;
+flex: 1;
+display: flex;
+flex-direction: column;
+`
+
+class Geo extends Component {
+
+ constructor(props) {
+ super(props)
+ this.renderGeoJSON = this.renderGeoJSON.bind(this)
+ }
+
+ componentWillMount() {
+ const { count } = this.props.agency
+ if (count === 0)
+ store.dispatch(getAgency())
+ }
+
+ componentWillUnmount() {
+ navigator.geolocation.clearWatch(this.watchID)
+ }
+
+ componentDidMount() {
+ /* if (!navigator.geolocation) {
+ getCurrentPosition: (success, failure) => {
+ const failureMsg = "Your browser doesn't support geolocation."
+ console.log(success, failure)
+ // failure(dispatch(locationError(failureMsg)))
+ }
+ } */
+ navigator.geolocation.getCurrentPosition(
+ (position) => store.dispatch(geoLocationUpdate(position)),
+ (error) => store.dispatch(geoLocationFailed(error)),
+ { enableHighAccuracy: true, timeout: 10000, maximumAge: 1000 },
+ )
+ this.watchID = navigator.geolocation.watchPosition(
+ (position) => store.dispatch(geoLocationUpdate(position)),
+ (error) => store.dispatch(geoLocationFailed(error)),
+ )
+ }
+
+ renderGeoJSON() {
+ const { polygons } = this.props.geo
+ const style = {
+ color: '#a63eff',
+ weight: 5,
+ opacity: 0.65
+ }
+ return (
+
+ {polygons && polygons.map(ele => (
+
+ ))}
+
+ )
+ }
+
+ render() {
+ const { loggedIn, geo } = this.props
+ const myLocationMarker = geo.coords ? (
+
+ ) : null
+ // const mapCenter = geo.coords
+ // ? [geo.coords.latitude, geo.coords.longitude]
+ // : [13.84626739, 100.538]
+ const mapCenter = [13.84626739, 100.538]
+ return (
+
+ {/* */}
+
+
+
+ )
+ }
+}
+
+
+const mapStateToProps = state => ({
+ loggedIn: loggedIn(state.auth),
+ agency: state.agency,
+ geo: state.geo,
+})
+export default connect(
+ mapStateToProps,
+ {}
+)(Geo)
diff --git a/src/container/Main.js b/src/container/Main.js
index 308cbb5..688341d 100644
--- a/src/container/Main.js
+++ b/src/container/Main.js
@@ -5,6 +5,7 @@ import { Redirect, Route, Switch } from 'react-router-dom'
import { loggedIn } from '../reducers/auth'
import { getAgency } from '../actions'
import Nav from '../components/Nav'
+import Footer from '../components/Footer'
import CalendarForm from '../components/CalendarForm'
import CalendarList from '../components/CalendarList'
import AgencyList from '../components/AgencyList'
@@ -34,7 +35,7 @@ class Main extends Component {
}
return (
-
+
@@ -48,6 +49,7 @@ class Main extends Component {
+
)
}
diff --git a/src/reducers/first.js b/src/reducers/first.js
deleted file mode 100644
index af15385..0000000
--- a/src/reducers/first.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import {
- FIRST_INCREMENT_COUNTER, FIRST_ASSIGN_ID
-} from '../constants/ActionTypes'
-
-const initialState = {
- counter: 1,
- obj: {}
-}
-
-const first = (state = initialState, action) => {
- switch (action.type) {
- case FIRST_INCREMENT_COUNTER:
- return {
- ...state,
- counter: state.counter +1
- }
- case FIRST_ASSIGN_ID:
- return {
- ...state,
- obj: action.newId
- }
- default:
- return state
- }
-}
-
-export default first
-
-
-export const getCounter = state => state.counter
-export const getId = state => state.id
\ No newline at end of file
diff --git a/src/reducers/geo.js b/src/reducers/geo.js
new file mode 100644
index 0000000..12c1b16
--- /dev/null
+++ b/src/reducers/geo.js
@@ -0,0 +1,131 @@
+import {
+ GEO_LOCATION_SUCCESS, GEO_LOCATION_FAILURE,
+ GEO_MARKER_ADD, GEO_MARKER_RESET, GEO_MARKER_UPDATE,
+ GEO_POLYGON_ADD, GEO_POLYGON_RESET, GEO_POLYGON_UPDATE,
+ STOPTIME_SUCCESS,
+} from '../constants/ActionTypes'
+
+const initialState = {
+ timestamp: 0,
+ coords: null,
+ message: '',
+ polygons: [],
+ markers: [],
+}
+
+const geo = (state = initialState, action) => {
+ switch (action.type) {
+ case GEO_LOCATION_SUCCESS:
+ /*
+ action = {
+ coords: {
+ latitude: 13.8462448,
+ longitude: 100.53825479999999,
+ altitude: null,
+ altitudeAccuracy: null,
+ accuracy: 20,
+ speed: 20,
+ },
+ timestamp: 1530214120419
+ }
+ */
+ return {
+ ...state,
+ message: '',
+ timestamp: action.timestamp,
+ coords: {...action.coords},
+ }
+ case GEO_LOCATION_FAILURE:
+ // action = {code: 3, message: "Timeout expired"}
+ return {
+ ...state,
+ timestamp: 0,
+ coords: null,
+ message: action.message,
+ }
+ case GEO_POLYGON_ADD:
+ return {
+ ...state,
+ polygons: [
+ ...state.polygons,
+ action.payload,
+ ],
+ }
+ case STOPTIME_SUCCESS:
+ /* add all stop into another polygon // we will assign unique id as
+ `stoptime` so it won't get in other ways
+ */
+ const stInd = state.polygons.findIndex(ele => ele.id === 'stoptime')
+ let polyWstoptime = [...state.polygons]
+ let stopFeatures = {
+ "type": "FeatureCollection",
+ "features": []
+ }
+ action.payload.results.map(ele => {
+ stopFeatures.features.push({
+ "type": "Feature",
+ "properties": {
+ "name": `${ele.stop.name} - ${ele.arrival}`,
+ },
+ "geometry": ele.stop.geojson,
+ })
+ return true
+ })
+ const n = { id: 'stoptime', geojson: stopFeatures }
+ if (stInd > -1) {
+ polyWstoptime[stInd] = n
+ } else {
+ polyWstoptime.push(n)
+ }
+ return {
+ ...state,
+ polygons: polyWstoptime,
+ }
+ case GEO_POLYGON_UPDATE:
+ const polyInd = state.polygons.findIndex(ele => ele.id === action.payload.id)
+ const oldPolygons = state.polygons
+ let newPolys = [...oldPolygons]
+ if (polyInd > -1) {
+ newPolys[polyInd] = action.payload
+ } else {
+ newPolys.push(action.payload)
+ }
+ return {
+ ...state,
+ polygons: newPolys,
+ }
+ case GEO_POLYGON_RESET:
+ return {
+ ...state,
+ polygons: [],
+ }
+ case GEO_MARKER_ADD:
+ return {
+ ...state,
+ markers: [
+ ...state.markers,
+ action.polygon,
+ ],
+ }
+ case GEO_MARKER_UPDATE:
+ const markerInd = state.markers.findIndex(ele => ele.id === action.marker.id)
+ const oldMarkers = state.markers
+ return {
+ ...state,
+ markers: [
+ ...oldMarkers.slice(0, markerInd),
+ action.polygon,
+ ...oldMarkers.slice(markerInd + 1),
+ ],
+ }
+ case GEO_MARKER_RESET:
+ return {
+ ...state,
+ markers: [],
+ }
+ default:
+ return state
+ }
+}
+
+export default geo
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 1a06b91..e4afb78 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -1,16 +1,18 @@
import { combineReducers } from 'redux'
-import first from './first'
+import geo from './geo'
import auth from './auth'
import agency from './agency'
import route from './route'
import fareattr from './fareattr'
import calendar from './calendar'
+import stoptime from './stoptime'
export default combineReducers({
auth,
- first,
+ geo,
agency,
route,
fareattr,
calendar,
+ stoptime,
})
diff --git a/src/reducers/stoptime.js b/src/reducers/stoptime.js
new file mode 100644
index 0000000..0be9679
--- /dev/null
+++ b/src/reducers/stoptime.js
@@ -0,0 +1,79 @@
+import {
+ STOPTIME_CREATE, STOPTIME_DELETE, STOPTIME_UPDATE,
+ STOPTIME_REQUEST, STOPTIME_SUCCESS, STOPTIME_FAILURE,
+} from '../constants/ActionTypes'
+
+
+const stoptimeInitState = {
+ results: [],
+ next: null,
+ count: 0,
+ fetching: false,
+ query: '',
+}
+const stoptime = (state = stoptimeInitState, action) => {
+ switch (action.type) {
+ case STOPTIME_REQUEST:
+ const { query } = action.meta
+ return {
+ ...state,
+ fetching: true,
+ query,
+ }
+ case STOPTIME_SUCCESS:
+ const { count, next, prev, results } = action.payload
+ return {
+ ...state,
+ fetching: false,
+ count,
+ next,
+ results: [
+ ...((prev) ? state.results : []),
+ ...results,
+ ]
+ }
+ case STOPTIME_UPDATE:
+ const { id } = action.payload
+ const oldResults = state.results
+ const targetInd = oldResults.findIndex(ele => ele.id === id)
+ return {
+ ...state,
+ fetching: false,
+ results: [
+ ...oldResults.slice(0, targetInd),
+ action.payload,
+ ...oldResults.slice(targetInd + 1)
+ ]
+ }
+ case STOPTIME_CREATE:
+ return {
+ ...state,
+ fetching: false,
+ count: state.count + 1,
+ results: [
+ ...state.results,
+ action.payload,
+ ]
+ }
+ case STOPTIME_DELETE:
+ const deleteInd = state.results.findIndex(ele => ele.id === action.meta.id)
+ return {
+ ...state,
+ count: state.count - 1,
+ fetching: false,
+ results: [
+ ...state.results.slice(0, deleteInd),
+ ...state.results.slice(deleteInd + 1)
+ ]
+ }
+ case STOPTIME_FAILURE:
+ return {
+ ...state,
+ fetching: false,
+ }
+ default:
+ return state;
+ }
+}
+
+export default stoptime
diff --git a/src/store.js b/src/store.js
index 0b81059..9a8cb44 100644
--- a/src/store.js
+++ b/src/store.js
@@ -10,7 +10,7 @@ import gruntApp from './reducers'
const persistConfig = {
key: 'root',
storage,
- blacklist: ['agency', 'route', 'calendar']
+ blacklist: ['agency', 'route', 'calendar', 'geo']
}
const middleware = [ thunk, apiMiddleware ]