aboutsummaryrefslogtreecommitdiffstats
path: root/app/javascript
diff options
context:
space:
mode:
authorLuc Donnet2018-02-19 11:04:29 +0100
committerLuc Donnet2018-02-19 11:04:29 +0100
commit7b17deff51545358009cb417cbb9d796565e7540 (patch)
treea43a5586ad39d838dd607e600dbc15ff18a58ab3 /app/javascript
parent89428163fc93a7e09ebb0ca47939f8558afeb5eb (diff)
parent5f6008d165df4499319a2121a71842657d6ac3c9 (diff)
downloadchouette-core-7b17deff51545358009cb417cbb9d796565e7540.tar.bz2
Merge branch 'master' into 0000-docker
Diffstat (limited to 'app/javascript')
-rw-r--r--app/javascript/date_filters/index.js2
-rw-r--r--app/javascript/date_filters/purchase_window.js5
-rw-r--r--app/javascript/helpers/master_slave.coffee16
-rw-r--r--app/javascript/helpers/routes_map.coffee161
-rw-r--r--app/javascript/helpers/save_button.js47
-rw-r--r--app/javascript/helpers/stop_area_header_manager.js56
-rw-r--r--app/javascript/journey_patterns/actions/index.js23
-rw-r--r--app/javascript/journey_patterns/components/ConfirmModal.js4
-rw-r--r--app/javascript/journey_patterns/components/CreateModal.js3
-rw-r--r--app/javascript/journey_patterns/components/EditModal.js16
-rw-r--r--app/javascript/journey_patterns/components/JourneyPattern.js131
-rw-r--r--app/javascript/journey_patterns/components/JourneyPatterns.js42
-rw-r--r--app/javascript/journey_patterns/components/Navigate.js3
-rw-r--r--app/javascript/journey_patterns/components/SaveJourneyPattern.js41
-rw-r--r--app/javascript/journey_patterns/containers/JourneyPatternList.js5
-rw-r--r--app/javascript/journey_patterns/reducers/journeyPatterns.js16
-rw-r--r--app/javascript/packs/calendars/edit.js74
-rw-r--r--app/javascript/packs/journey_patterns/index.js1
-rw-r--r--app/javascript/packs/referential_lines/show.js10
-rw-r--r--app/javascript/packs/referential_overview/overview.js1
-rw-r--r--app/javascript/packs/routes/edit.js6
-rw-r--r--app/javascript/packs/routes/show.js104
-rw-r--r--app/javascript/packs/stop_areas/new.js3
-rw-r--r--app/javascript/packs/vehicle_journeys/index.js12
-rw-r--r--app/javascript/referential_overview/index.coffee113
-rw-r--r--app/javascript/routes/components/App.js7
-rw-r--r--app/javascript/routes/components/BSelect2.js30
-rw-r--r--app/javascript/routes/components/OlMap.js27
-rw-r--r--app/javascript/routes/components/StopPoint.js16
-rw-r--r--app/javascript/routes/components/StopPointList.js16
-rw-r--r--app/javascript/routes/form_helper.js17
-rw-r--r--app/javascript/routes/reducers/stopPoints.js10
-rw-r--r--app/javascript/time_tables/actions/index.js27
-rw-r--r--app/javascript/time_tables/components/ConfirmModal.js14
-rw-r--r--app/javascript/time_tables/components/ErrorModal.js10
-rw-r--r--app/javascript/time_tables/components/ExceptionsInDay.js3
-rw-r--r--app/javascript/time_tables/components/Metas.js28
-rw-r--r--app/javascript/time_tables/components/Navigate.js9
-rw-r--r--app/javascript/time_tables/components/PeriodForm.js18
-rw-r--r--app/javascript/time_tables/components/PeriodManager.js3
-rw-r--r--app/javascript/time_tables/components/PeriodsInDay.js3
-rw-r--r--app/javascript/time_tables/components/SaveTimetable.js3
-rw-r--r--app/javascript/time_tables/components/TagsSelect2.js7
-rw-r--r--app/javascript/time_tables/components/TimeTableDay.js3
-rw-r--r--app/javascript/time_tables/components/Timetable.js11
-rw-r--r--app/javascript/time_tables/containers/App.js3
-rw-r--r--app/javascript/vehicle_journeys/actions/index.js156
-rw-r--r--app/javascript/vehicle_journeys/components/App.js3
-rw-r--r--app/javascript/vehicle_journeys/components/ConfirmModal.js9
-rw-r--r--app/javascript/vehicle_journeys/components/Filters.js28
-rw-r--r--app/javascript/vehicle_journeys/components/Navigate.js8
-rw-r--r--app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js42
-rw-r--r--app/javascript/vehicle_journeys/components/ToggleArrivals.js8
-rw-r--r--app/javascript/vehicle_journeys/components/Tools.js28
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourney.js70
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourneys.js97
-rw-r--r--app/javascript/vehicle_journeys/components/tools/CreateModal.js46
-rw-r--r--app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js50
-rw-r--r--app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js4
-rw-r--r--app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js3
-rw-r--r--app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js118
-rw-r--r--app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js3
-rw-r--r--app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js153
-rw-r--r--app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js3
-rw-r--r--app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js20
-rw-r--r--app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js30
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js7
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js141
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js19
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js5
-rw-r--r--app/javascript/vehicle_journeys/containers/Filters.js3
-rw-r--r--app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js7
-rw-r--r--app/javascript/vehicle_journeys/containers/VehicleJourneysList.js8
-rw-r--r--app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js5
-rw-r--r--app/javascript/vehicle_journeys/containers/tools/PurchaseWindowsEditVehicleJourney.js38
-rw-r--r--app/javascript/vehicle_journeys/containers/tools/VehicleJourneyInfoButton.js20
-rw-r--r--app/javascript/vehicle_journeys/reducers/custom_fields.js6
-rw-r--r--app/javascript/vehicle_journeys/reducers/index.js9
-rw-r--r--app/javascript/vehicle_journeys/reducers/missions.js6
-rw-r--r--app/javascript/vehicle_journeys/reducers/modal.js76
-rw-r--r--app/javascript/vehicle_journeys/reducers/returnVehicleJourneys.js11
-rw-r--r--app/javascript/vehicle_journeys/reducers/vehicleJourneys.js83
82 files changed, 1871 insertions, 612 deletions
diff --git a/app/javascript/date_filters/index.js b/app/javascript/date_filters/index.js
index ee892a7fe..432166008 100644
--- a/app/javascript/date_filters/index.js
+++ b/app/javascript/date_filters/index.js
@@ -3,6 +3,7 @@ import complianceControlSetDF from './compliance_control_set'
import complianceCheckSetDF from './compliance_check_set'
import timetableDF from './time_table'
import importDF from './import'
+import purchaseWindowDF from './purchase_window'
import workbenchDF from './workbench'
const DateFilters = {
@@ -11,6 +12,7 @@ const DateFilters = {
complianceControlSetDF,
importDF,
timetableDF,
+ purchaseWindowDF,
workbenchDF
}
diff --git a/app/javascript/date_filters/purchase_window.js b/app/javascript/date_filters/purchase_window.js
new file mode 100644
index 000000000..2c46b6d52
--- /dev/null
+++ b/app/javascript/date_filters/purchase_window.js
@@ -0,0 +1,5 @@
+import DateFilter from '../helpers/date_filters'
+
+const purchaseWindowDF = new DateFilter("purchase_window_filter_btn", "Tous les champs du filtre de date doivent être remplis", "q_contains_date_NUMi")
+
+export default purchaseWindowDF \ No newline at end of file
diff --git a/app/javascript/helpers/master_slave.coffee b/app/javascript/helpers/master_slave.coffee
new file mode 100644
index 000000000..81bebe36a
--- /dev/null
+++ b/app/javascript/helpers/master_slave.coffee
@@ -0,0 +1,16 @@
+class MasterSlave
+ constructor: (selector)->
+ $(selector).find('[data-master]').each (i, slave)->
+ $slave = $(slave)
+ master = $($slave.data().master)
+ $slave.find("input:disabled, select:disabled").attr "data-slave-force-disabled", "true"
+ toggle = ->
+ val = master.filter(":checked").val() if master.filter("[type=radio]").length > 0
+ val ||= master.val()
+ selected = val == $slave.data().value
+ $slave.toggle selected
+ $slave.find("input, select").filter(":not([data-slave-force-disabled])").attr "disabled", !selected
+ master.change toggle
+ toggle()
+
+export default MasterSlave
diff --git a/app/javascript/helpers/routes_map.coffee b/app/javascript/helpers/routes_map.coffee
new file mode 100644
index 000000000..6834406fc
--- /dev/null
+++ b/app/javascript/helpers/routes_map.coffee
@@ -0,0 +1,161 @@
+class RoutesMap
+ constructor: (@target)->
+ @initMap()
+ @area = []
+ @seenStopIds = []
+ @routes = {}
+
+ initMap: ->
+ @map = new ol.Map
+ target: @target,
+ layers: [ new ol.layer.Tile(source: new ol.source.OSM()) ]
+ controls: [ new ol.control.ScaleLine(), new ol.control.Zoom(), new ol.control.ZoomSlider() ],
+ interactions: ol.interaction.defaults(zoom: true)
+ view: new ol.View()
+
+ addRoutes: (routes)->
+ for route in routes
+ @addRoute route
+
+ addRoute: (route)->
+ geoColPts = []
+ geoColLns = []
+ @routes[route.id] = route if route.id
+ stops = route.stops || route
+ geoColEdges = [
+ new ol.Feature({
+ geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stops[0].longitude), parseFloat(stops[0].latitude)]))
+ }),
+ new ol.Feature({
+ geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stops[stops.length - 1].longitude), parseFloat(stops[stops.length - 1].latitude)]))
+ })
+ ]
+
+ prevStop = null
+ stops.forEach (stop, i) =>
+ if stop.longitude && stop.latitude
+ if prevStop
+ geoColLns.push new ol.Feature
+ geometry: new ol.geom.LineString([
+ ol.proj.fromLonLat([parseFloat(prevStop.longitude), parseFloat(prevStop.latitude)]),
+ ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)])
+ ])
+ prevStop = stop
+
+ geoColPts.push(new ol.Feature({
+ geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)]))
+ }))
+ unless @seenStopIds.indexOf(stop.stoparea_id) > 0
+ @area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)]
+ @seenStopIds.push stop.stoparea_id
+
+ vectorPtsLayer = new ol.layer.Vector({
+ source: new ol.source.Vector({
+ features: geoColPts
+ }),
+ style: @defaultStyles(),
+ zIndex: 2
+ })
+ route.vectorPtsLayer = vectorPtsLayer if route.id
+ vectorEdgesLayer = new ol.layer.Vector({
+ source: new ol.source.Vector({
+ features: geoColEdges
+ }),
+ style: @edgeStyles(),
+ zIndex: 3
+ })
+ route.vectorEdgesLayer = vectorEdgesLayer if route.id
+ vectorLnsLayer = new ol.layer.Vector({
+ source: new ol.source.Vector({
+ features: geoColLns
+ }),
+ style: [@lineStyle()],
+ zIndex: 1
+ })
+ route.vectorLnsLayer = vectorLnsLayer if route.id
+ @map.addLayer vectorPtsLayer
+ @map.addLayer vectorEdgesLayer
+ @map.addLayer vectorLnsLayer
+
+ lineStyle: (highlighted=false)->
+ new ol.style.Style
+ stroke: new ol.style.Stroke
+ color: if highlighted then "#ed7f00" else '#007fbb'
+ width: 3
+
+ edgeStyles: (highlighted=false)->
+ new ol.style.Style
+ image: new ol.style.Circle
+ radius: 5
+ stroke: new ol.style.Stroke
+ color: if highlighted then "#ed7f00" else '#007fbb'
+ width: 2
+ fill: new ol.style.Fill
+ color: if highlighted then "#ed7f00" else '#007fbb'
+ width: 2
+
+ defaultStyles: (highlighted=false)->
+ new ol.style.Style
+ image: new ol.style.Circle
+ radius: 4
+ stroke: new ol.style.Stroke
+ color: if highlighted then "#ed7f00" else '#007fbb'
+ width: 2
+ fill: new ol.style.Fill
+ color: '#ffffff'
+ width: 2
+
+ addRoutesLabels: ->
+ labelsContainer = $("<ul class='routes-labels'></ul>")
+ labelsContainer.appendTo $("##{@target}")
+ @vectorPtsLayer = null
+ @vectorEdgesLayer = null
+ @vectorLnsLayer = null
+ Object.keys(@routes).forEach (id)=>
+ route = @routes[id]
+ label = $("<li>#{route.name}</ul>")
+ label.appendTo labelsContainer
+ label.mouseleave =>
+ route.vectorPtsLayer.setStyle @defaultStyles(false)
+ route.vectorEdgesLayer.setStyle @edgeStyles(false)
+ route.vectorLnsLayer.setStyle @lineStyle(false)
+ route.vectorPtsLayer.setZIndex 2
+ route.vectorEdgesLayer.setZIndex 3
+ route.vectorLnsLayer.setZIndex 1
+ @fitZoom()
+ label.mouseenter =>
+ route.vectorPtsLayer.setStyle @defaultStyles(true)
+ route.vectorEdgesLayer.setStyle @edgeStyles(true)
+ route.vectorLnsLayer.setStyle @lineStyle(true)
+ route.vectorPtsLayer.setZIndex 11
+ route.vectorEdgesLayer.setZIndex 12
+ route.vectorLnsLayer.setZIndex 10
+ @fitZoom(route)
+
+ fitZoom: (route)->
+ if route
+ area = []
+ route.stops.forEach (stop, i) =>
+ area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)]
+ else
+ area = @area
+ boundaries = ol.extent.applyTransform(
+ ol.extent.boundingExtent(area), ol.proj.getTransform('EPSG:4326', 'EPSG:3857')
+ )
+ @map.getView().fit boundaries, @map.getSize()
+ tooCloseToBounds = false
+ mapBoundaries = @map.getView().calculateExtent @map.getSize()
+ mapWidth = mapBoundaries[2] - mapBoundaries[0]
+ mapHeight = mapBoundaries[3] - mapBoundaries[1]
+ marginSize = 0.1
+ heightMargin = marginSize * mapHeight
+ widthMargin = marginSize * mapWidth
+ tooCloseToBounds = tooCloseToBounds || (boundaries[0] - mapBoundaries[0]) < widthMargin
+ tooCloseToBounds = tooCloseToBounds || (mapBoundaries[2] - boundaries[2]) < widthMargin
+ tooCloseToBounds = tooCloseToBounds || (boundaries[1] - mapBoundaries[1]) < heightMargin
+ tooCloseToBounds = tooCloseToBounds || (mapBoundaries[3] - boundaries[3]) < heightMargin
+ if tooCloseToBounds
+ @map.getView().setZoom(@map.getView().getZoom() - 1)
+
+
+export default RoutesMap
diff --git a/app/javascript/helpers/save_button.js b/app/javascript/helpers/save_button.js
new file mode 100644
index 000000000..7e0bd5bbe
--- /dev/null
+++ b/app/javascript/helpers/save_button.js
@@ -0,0 +1,47 @@
+import React, { PropTypes, Component } from 'react'
+
+export default class SaveButton extends Component{
+ constructor(props){
+ super(props)
+ }
+
+ btnDisabled(){
+ return !this.props.status.fetchSuccess || this.props.status.isFetching
+ }
+
+ btnClass(){
+ let className = ['btn btn-default']
+ if(this.btnDisabled()){
+ className.push('disabled')
+ }
+ return className.join(' ')
+ }
+
+ render() {
+ if (!this.hasPolicy()) {
+ return false
+ }else{
+ return (
+ <div className='row mt-md'>
+ <div className='col-lg-12 text-right'>
+ <form className={this.formClassName() + ' formSubmitr ml-xs'} onSubmit={e => {e.preventDefault()}}>
+ <div className="btn-group sticky-actions">
+ <button
+ className={this.btnClass()}
+ type='button'
+ disabled={this.btnDisabled()}
+ onClick={e => {
+ e.preventDefault()
+ this.props.editMode ? this.submitForm() : this.props.onEnterEditMode()
+ }}
+ >
+ {this.props.editMode ? "Valider" : "Editer"}
+ </button>
+ </div>
+ </form>
+ </div>
+ </div>
+ )
+ }
+ }
+}
diff --git a/app/javascript/helpers/stop_area_header_manager.js b/app/javascript/helpers/stop_area_header_manager.js
new file mode 100644
index 000000000..5b18e2f63
--- /dev/null
+++ b/app/javascript/helpers/stop_area_header_manager.js
@@ -0,0 +1,56 @@
+import React, { Component } from 'react'
+
+export default class StopAreaHeaderManager {
+ constructor(ids_list, stopPointsList, features) {
+ this.ids_list = ids_list
+ this.stopPointsList = stopPointsList
+ this.features = features
+ }
+
+ hasFeature(key) {
+ return this.features[key]
+ }
+
+ stopPointHeader(object_id) {
+ let index = this.ids_list.indexOf(object_id)
+ let sp = this.stopPointsList[index]
+ let showHeadline = this.showHeader(object_id)
+ return (
+ <div
+ className={(showHeadline) ? 'headlined' : ''}
+ data-headline={showHeadline}
+ title={sp.city_name ? sp.city_name + ' (' + sp.zip_code +')' : ""}
+ >
+ <span>
+ <span>
+ {sp.name}
+ {sp.time_zone_formatted_offset && <span className="small">
+ &nbsp;({sp.time_zone_formatted_offset})
+ </span>}
+ {sp.area_kind == 'non_commercial' && <span className="fa fa-question-circle" title={sp.area_type_i18n}>
+ </span>}
+ </span>
+ </span>
+ </div>
+ )
+ }
+
+ showHeader(object_id) {
+ let showHeadline = false
+ let headline = ""
+ let attribute_to_check = this.hasFeature('long_distance_routes') ? "country_code" : "city_name"
+ let index = this.ids_list.indexOf(object_id)
+ let sp = this.stopPointsList[index]
+ let previousBreakpoint = this.stopPointsList[index - 1]
+ if(sp == undefined){
+ console.log("STOP_POINT NOT FOUND: " + object_id)
+ console.log("AVAILABLE IDS:" + this.ids_list)
+ return
+ }
+ if(index == 0 || (sp[attribute_to_check] != previousBreakpoint[attribute_to_check])){
+ showHeadline = true
+ headline = this.hasFeature('long_distance_routes') ? sp.country_name : sp.city_name
+ }
+ return showHeadline ? headline : ""
+ }
+}
diff --git a/app/javascript/journey_patterns/actions/index.js b/app/javascript/journey_patterns/actions/index.js
index 4ff3f77ea..a70a2e6f2 100644
--- a/app/javascript/journey_patterns/actions/index.js
+++ b/app/javascript/journey_patterns/actions/index.js
@@ -64,6 +64,11 @@ const actions = {
type : 'DELETE_JOURNEYPATTERN',
index,
}),
+ updateJourneyPatternCosts : (index, costs) => ({
+ type : 'UPDATE_JOURNEYPATTERN_COSTS',
+ index,
+ costs
+ }),
closeModal : () => ({
type : 'CLOSE_MODAL'
}),
@@ -194,15 +199,13 @@ const actions = {
}
})
}
- journeyPatterns.push({
- name: val.name,
- object_id: val.object_id,
- short_id: val.short_id,
- published_name: val.published_name,
- registration_number: val.registration_number,
- stop_points: val.route_short_description.stop_points,
- deletable: false
- })
+ journeyPatterns.push(
+ _.assign({}, val, {
+ stop_points: val.route_short_description.stop_points,
+ costs: val.costs || {},
+ deletable: false
+ })
+ )
}
}
window.currentItemsLength = journeyPatterns.length
@@ -217,4 +220,4 @@ const actions = {
}
}
-export default actions \ No newline at end of file
+export default actions
diff --git a/app/javascript/journey_patterns/components/ConfirmModal.js b/app/javascript/journey_patterns/components/ConfirmModal.js
index 2cc1bef44..ccd0a9384 100644
--- a/app/javascript/journey_patterns/components/ConfirmModal.js
+++ b/app/javascript/journey_patterns/components/ConfirmModal.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCancel, journeyPatterns}) {
return (
diff --git a/app/javascript/journey_patterns/components/CreateModal.js b/app/javascript/journey_patterns/components/CreateModal.js
index d0eff6e57..a6c1b608a 100644
--- a/app/javascript/journey_patterns/components/CreateModal.js
+++ b/app/javascript/journey_patterns/components/CreateModal.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
export default class CreateModal extends Component {
diff --git a/app/javascript/journey_patterns/components/EditModal.js b/app/javascript/journey_patterns/components/EditModal.js
index e7ce24aa1..c960cb41c 100644
--- a/app/javascript/journey_patterns/components/EditModal.js
+++ b/app/javascript/journey_patterns/components/EditModal.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
export default class EditModal extends Component {
@@ -36,7 +37,6 @@ export default class EditModal extends Component {
{this.renderModalTitle()}
<span type="button" className="close modal-close" data-dismiss="modal">&times;</span>
</div>
-
{(this.props.modal.type == 'edit') && (
<form>
<div className='modal-body'>
@@ -85,6 +85,16 @@ export default class EditModal extends Component {
</div>
</div>
</div>
+ <div>
+ <label className='control-label'>Signature métier</label>
+ <input
+ type='text'
+ ref='checksum'
+ className='form-control'
+ disabled='disabled'
+ defaultValue={this.props.modal.modalProps.journeyPattern.checksum}
+ />
+ </div>
</div>
{
this.props.editMode &&
@@ -121,4 +131,4 @@ EditModal.propTypes = {
modal: PropTypes.object,
onModalClose: PropTypes.func.isRequired,
saveModal: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/journey_patterns/components/JourneyPattern.js b/app/javascript/journey_patterns/components/JourneyPattern.js
index d4c9816ec..35765b99a 100644
--- a/app/javascript/journey_patterns/components/JourneyPattern.js
+++ b/app/javascript/journey_patterns/components/JourneyPattern.js
@@ -1,10 +1,21 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
export default class JourneyPattern extends Component{
constructor(props){
super(props)
- this.previousCity = undefined
+ this.previousSpId = undefined
+ this.updateCosts = this.updateCosts.bind(this)
+ }
+
+ updateCosts(e) {
+ let costs = {
+ [e.target.dataset.costsKey]: {
+ [e.target.name]: parseFloat(e.target.value)
+ }
+ }
+ this.props.onUpdateJourneyPatternCosts(costs)
}
vehicleJourneyURL(jpOid) {
@@ -16,16 +27,20 @@ export default class JourneyPattern extends Component{
)
}
- cityNameChecker(sp) {
- let bool = false
- if(sp.city_name != this.previousCity){
- bool = true
- this.previousCity = sp.city_name
- }
+ hasFeature(key) {
+ return this.props.status.features[key]
+ }
+
+ cityNameChecker(sp, i) {
+ return this.props.journeyPatterns.showHeader((sp.stop_area_object_id || sp.object_id) + "-" + i)
+ }
+
+ spNode(sp, headlined){
return (
<div
- className={(bool) ? 'headlined' : ''}
+ className={(headlined) ? 'headlined' : ''}
>
+ <div className={'link '}></div>
<span className='has_radio'>
<input
onChange = {(e) => this.props.onCheckboxChange(e)}
@@ -59,19 +74,60 @@ export default class JourneyPattern extends Component{
return !this.props.status.policy[`journey_patterns.${action}`]
}
- render() {
- this.previousCity = undefined
+ totals(){
+ let totalTime = 0
+ let totalDistance = 0
+ let from = null
+ this.props.value.stop_points.map((stopPoint, i) =>{
+ if(from && stopPoint.checked){
+ let [costsKey, costs, time, distance] = this.getTimeAndDistanceBetweenStops(from, stopPoint.id)
+ totalTime += time
+ totalDistance += distance
+ }
+ if(stopPoint.checked){
+ from = stopPoint.id
+ }
+ })
+ return [this.formatTime(totalTime), this.formatDistance(totalDistance)]
+ }
- return (
- <div className={'t2e-item' + (this.props.value.deletable ? ' disabled' : '') + (this.props.value.object_id ? '' : ' to_record') + (this.props.value.errors ? ' has-error': '')}>
- {/* Errors */}
- {/* this.props.value.errors ? this.getErrors(this.props.value.errors) : '' */}
+ getTimeAndDistanceBetweenStops(from, to){
+ let costsKey = from + "-" + to
+ let costs = this.props.value.costs[costsKey] || {distance: 0, time: 0}
+ let time = costs['time'] || 0
+ let distance = costs['distance'] || 0
+ return [costsKey, costs, time, distance]
+ }
+
+ formatDistance(distance){
+ return parseFloat(Math.round(distance * 100) / 100).toFixed(2) + " km"
+ }
+
+ formatTime(time){
+ if(time < 60){
+ return time + " min"
+ }
+ else{
+ let hours = parseInt(time/60)
+ return hours + " h " + (time - 60*hours)
+ }
+ }
+ render() {
+ this.previousSpId = undefined
+ let [totalTime, totalDistance] = this.totals()
+ return (
+ <div className={'t2e-item' + (this.props.value.deletable ? ' disabled' : '') + (this.props.value.object_id ? '' : ' to_record') + (this.props.value.errors ? ' has-error': '') + (this.hasFeature('costs_in_journey_patterns') ? ' with-costs' : '')}>
<div className='th'>
<div className='strong mb-xs'>{this.props.value.object_id ? this.props.value.short_id : '-'}</div>
<div>{this.props.value.registration_number}</div>
<div>{actions.getChecked(this.props.value.stop_points).length} arrêt(s)</div>
-
+ {this.hasFeature('costs_in_journey_patterns') &&
+ <div className="small row totals">
+ <span className="col-md-6"><i className="fa fa-arrows-h"></i>{totalDistance}</span>
+ <span className="col-md-6"><i className="fa fa-clock-o"></i>{totalTime}</span>
+ </div>
+ }
<div className={this.props.value.deletable ? 'btn-group disabled' : 'btn-group'}>
<div
className={this.props.value.deletable ? 'btn dropdown-toggle disabled' : 'btn dropdown-toggle'}
@@ -80,10 +136,9 @@ export default class JourneyPattern extends Component{
<span className='fa fa-cog'></span>
</div>
<ul className='dropdown-menu'>
- <li className={this.isDisabled('update') ? 'disabled' : ''}>
+ <li>
<button
type='button'
- disabled={this.isDisabled('update')}
onClick={this.props.onOpenEditModal}
data-toggle='modal'
data-target='#JourneyPatternModal'
@@ -112,9 +167,40 @@ export default class JourneyPattern extends Component{
</div>
{this.props.value.stop_points.map((stopPoint, i) =>{
+ let costs = null
+ let costsKey = null
+ let time = null
+ let distance = null
+ let time_in_words = null
+ if(this.previousSpId && stopPoint.checked){
+ [costsKey, costs, time, distance] = this.getTimeAndDistanceBetweenStops(this.previousSpId, stopPoint.id)
+ time_in_words = this.formatTime(time)
+ }
+ if(stopPoint.checked){
+ this.previousSpId = stopPoint.id
+ }
+ let headlined = this.cityNameChecker(stopPoint, i)
return (
- <div key={i} className='td'>
- {this.cityNameChecker(stopPoint)}
+ <div key={i} className={(stopPoint.checked ? 'activated' : 'deactivated') + (this.props.editMode ? ' edit-mode' : '')}>
+ <div className={'td' + (headlined ? ' with-headline' : '')}>
+ {this.spNode(stopPoint, headlined)}
+ </div>
+ {this.hasFeature('costs_in_journey_patterns') && costs && <div className='costs' id={'costs-' + this.props.value.id + '-' + costsKey }>
+ {this.props.editMode && <div>
+ <p>
+ <input type="number" value={costs['distance'] || 0} min='0' name="distance" step="0.01" onChange={this.updateCosts} data-costs-key={costsKey}/>
+ <span>km</span>
+ </p>
+ <p>
+ <input type="number" value={costs['time'] || 0} min='0' name="time" onChange={this.updateCosts} data-costs-key={costsKey}/>
+ <span>min</span>
+ </p>
+ </div>}
+ {!this.props.editMode && <div>
+ <p><i className="fa fa-arrows-h"></i>{this.formatDistance(costs['distance'] || 0)}</p>
+ <p><i className="fa fa-clock-o"></i>{time_in_words}</p>
+ </div>}
+ </div>}
</div>
)
})}
@@ -128,5 +214,6 @@ JourneyPattern.propTypes = {
index: PropTypes.number,
onCheckboxChange: PropTypes.func.isRequired,
onOpenEditModal: PropTypes.func.isRequired,
- onDeleteJourneyPattern: PropTypes.func.isRequired
-} \ No newline at end of file
+ onDeleteJourneyPattern: PropTypes.func.isRequired,
+ journeyPatterns: PropTypes.object.isRequired
+}
diff --git a/app/javascript/journey_patterns/components/JourneyPatterns.js b/app/javascript/journey_patterns/components/JourneyPatterns.js
index 4b2badabb..31727fefc 100644
--- a/app/javascript/journey_patterns/components/JourneyPatterns.js
+++ b/app/javascript/journey_patterns/components/JourneyPatterns.js
@@ -1,16 +1,23 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import _ from 'lodash'
import JourneyPattern from './JourneyPattern'
-
+import StopAreaHeaderManager from '../../helpers/stop_area_header_manager'
export default class JourneyPatterns extends Component {
constructor(props){
super(props)
- this.previousCity = undefined
+ this.headerManager = new StopAreaHeaderManager(
+ _.map(this.props.stopPointsList, (sp, i)=>{return sp.stop_area_object_id + "-" + i}),
+ this.props.stopPointsList,
+ this.props.status.features
+ )
}
+
componentDidMount() {
this.props.onLoadFirstPage()
}
+
componentDidUpdate(prevProps, prevState) {
if(this.props.status.isFetching == false){
$('.table-2entries').each(function() {
@@ -54,21 +61,12 @@ export default class JourneyPatterns extends Component {
}
}
- cityNameChecker(sp) {
- let bool = false
- if(sp.city_name != this.previousCity){
- bool = true
- this.previousCity = sp.city_name
- }
- return (
- <div
- className={(bool) ? 'headlined' : ''}
- data-headline={(bool) ? sp.city_name : ''}
- title={sp.city_name + ' (' + sp.zip_code +')'}
- >
- <span><span>{sp.name}</span></span>
- </div>
- )
+ showHeader(object_id) {
+ return this.headerManager.showHeader(object_id)
+ }
+
+ hasFeature(key) {
+ return this.props.status.features[key]
}
render() {
@@ -115,8 +113,8 @@ export default class JourneyPatterns extends Component {
</div>
{this.props.stopPointsList.map((sp, i) =>{
return (
- <div key={i} className='td'>
- {this.cityNameChecker(sp)}
+ <div key={i} className={'td' + (this.hasFeature('costs_in_journey_patterns') ? ' with-costs' : '')}>
+ {this.headerManager.stopPointHeader(sp.stop_area_object_id + "-" + i)}
</div>
)
})}
@@ -131,8 +129,10 @@ export default class JourneyPatterns extends Component {
onCheckboxChange= {(e) => this.props.onCheckboxChange(e, index)}
onOpenEditModal= {() => this.props.onOpenEditModal(index, journeyPattern)}
onDeleteJourneyPattern={() => this.props.onDeleteJourneyPattern(index)}
+ onUpdateJourneyPatternCosts={(costs) => this.props.onUpdateJourneyPatternCosts(index, costs)}
status= {this.props.status}
editMode= {this.props.editMode}
+ journeyPatterns= {this}
/>
)}
</div>
@@ -152,4 +152,4 @@ JourneyPatterns.propTypes = {
onCheckboxChange: PropTypes.func.isRequired,
onLoadFirstPage: PropTypes.func.isRequired,
onOpenEditModal: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/journey_patterns/components/Navigate.js b/app/javascript/journey_patterns/components/Navigate.js
index f2fdd668f..78f324a7d 100644
--- a/app/javascript/journey_patterns/components/Navigate.js
+++ b/app/javascript/journey_patterns/components/Navigate.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
export default function Navigate({ dispatch, journeyPatterns, pagination, status }) {
diff --git a/app/javascript/journey_patterns/components/SaveJourneyPattern.js b/app/javascript/journey_patterns/components/SaveJourneyPattern.js
index d071fa542..4bb6a73a0 100644
--- a/app/javascript/journey_patterns/components/SaveJourneyPattern.js
+++ b/app/javascript/journey_patterns/components/SaveJourneyPattern.js
@@ -1,34 +1,19 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import SaveButton from '../../helpers/save_button'
import actions from '../actions'
-export default class SaveJourneyPattern extends Component {
- constructor(props){
- super(props)
+export default class SaveJourneyPattern extends SaveButton {
+ hasPolicy(){
+ return this.props.status.policy['journey_patterns.update'] == true
}
- render() {
- if(this.props.status.policy['journey_patterns.update'] == false) {
- return false
- }else{
- return (
- <div className='row mt-md'>
- <div className='col-lg-12 text-right'>
- <form className='jp_collection formSubmitr ml-xs' onSubmit={e => {e.preventDefault()}}>
- <button
- className='btn btn-default'
- type='button'
- onClick={e => {
- e.preventDefault()
- this.props.editMode ? this.props.onSubmitJourneyPattern(this.props.dispatch, this.props.journeyPatterns) : this.props.onEnterEditMode()
- }}
- >
- {this.props.editMode ? "Valider" : "Editer"}
- </button>
- </form>
- </div>
- </div>
- )
- }
+ formClassName(){
+ return 'jp_collection'
+ }
+
+ submitForm(){
+ this.props.onSubmitJourneyPattern(this.props.dispatch, this.props.journeyPatterns)
}
}
@@ -36,4 +21,4 @@ SaveJourneyPattern.propTypes = {
journeyPatterns: PropTypes.array.isRequired,
status: PropTypes.object.isRequired,
page: PropTypes.number.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/journey_patterns/containers/JourneyPatternList.js b/app/javascript/journey_patterns/containers/JourneyPatternList.js
index d98734407..d338345f2 100644
--- a/app/javascript/journey_patterns/containers/JourneyPatternList.js
+++ b/app/javascript/journey_patterns/containers/JourneyPatternList.js
@@ -25,7 +25,10 @@ const mapDispatchToProps = (dispatch) => {
},
onDeleteJourneyPattern: (index) =>{
dispatch(actions.deleteJourneyPattern(index))
- }
+ },
+ onUpdateJourneyPatternCosts: (index, costs) =>{
+ dispatch(actions.updateJourneyPatternCosts(index, costs))
+ },
}
}
diff --git a/app/javascript/journey_patterns/reducers/journeyPatterns.js b/app/javascript/journey_patterns/reducers/journeyPatterns.js
index 0bbcba976..1ce069522 100644
--- a/app/javascript/journey_patterns/reducers/journeyPatterns.js
+++ b/app/javascript/journey_patterns/reducers/journeyPatterns.js
@@ -17,6 +17,7 @@ const journeyPattern = (state = {}, action) =>{
published_name: action.data.published_name.value,
registration_number: action.data.registration_number.value,
stop_points: stopPoints,
+ costs: {},
deletable: false
}
case 'UPDATE_CHECKBOX_VALUE':
@@ -67,6 +68,19 @@ export default function journeyPatterns (state = [], action) {
return j
}
})
+ case 'UPDATE_JOURNEYPATTERN_COSTS':
+ return state.map((j, i) =>{
+ if(i == action.index) {
+ const new_costs = Object.assign({}, j.costs)
+ Object.keys(action.costs).map((key) => {
+ let new_costs_for_key = Object.assign({}, j.costs[key] || {}, action.costs[key])
+ new_costs[key] = new_costs_for_key
+ })
+ return _.assign({}, j, {costs: new_costs})
+ } else {
+ return j
+ }
+ })
case 'ADD_JOURNEYPATTERN':
return [
journeyPattern(state, action),
@@ -87,4 +101,4 @@ export default function journeyPatterns (state = [], action) {
default:
return state
}
-} \ No newline at end of file
+}
diff --git a/app/javascript/packs/calendars/edit.js b/app/javascript/packs/calendars/edit.js
new file mode 100644
index 000000000..bd09657ec
--- /dev/null
+++ b/app/javascript/packs/calendars/edit.js
@@ -0,0 +1,74 @@
+import React from 'react'
+import { render } from 'react-dom'
+import { Provider } from 'react-redux'
+import { createStore } from 'redux'
+import timeTablesApp from '../../time_tables/reducers'
+import App from '../../time_tables/containers/App'
+import clone from '../../helpers/clone'
+
+const actionType = clone(window, "actionType", true)
+
+// logger, DO NOT REMOVE
+// var applyMiddleware = require('redux').applyMiddleware
+// var createLogger = require('redux-logger')
+// var thunkMiddleware = require('redux-thunk').default
+// var promise = require('redux-promise')
+
+let initialState = {
+ status: {
+ actionType: actionType,
+ policy: window.perms,
+ fetchSuccess: true,
+ isFetching: false
+ },
+ timetable: {
+ current_month: [],
+ current_periode_range: '',
+ periode_range: [],
+ time_table_periods: [],
+ time_table_dates: []
+ },
+ metas: {
+ comment: '',
+ day_types: [],
+ initial_tags: []
+ },
+ pagination: {
+ stateChanged: false,
+ currentPage: '',
+ periode_range: []
+ },
+ modal: {
+ type: '',
+ modalProps: {
+ active: false,
+ begin: {
+ day: '01',
+ month: '01',
+ year: String(new Date().getFullYear())
+ },
+ end: {
+ day: '01',
+ month: '01',
+ year: String(new Date().getFullYear())
+ },
+ index: false,
+ error: ''
+ },
+ confirmModal: {}
+ }
+}
+// const loggerMiddleware = createLogger()
+
+let store = createStore(
+ timeTablesApp,
+ initialState,
+ // applyMiddleware(thunkMiddleware, promise, loggerMiddleware)
+)
+
+render(
+ <Provider store={store}>
+ <App />
+ </Provider>,
+ document.getElementById('periods')
+)
diff --git a/app/javascript/packs/journey_patterns/index.js b/app/javascript/packs/journey_patterns/index.js
index fde28b45d..367a8830f 100644
--- a/app/javascript/packs/journey_patterns/index.js
+++ b/app/javascript/packs/journey_patterns/index.js
@@ -16,6 +16,7 @@ var initialState = {
editMode: false,
status: {
policy: window.perms,
+ features: window.features,
fetchSuccess: true,
isFetching: false
},
diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js
new file mode 100644
index 000000000..542188018
--- /dev/null
+++ b/app/javascript/packs/referential_lines/show.js
@@ -0,0 +1,10 @@
+import clone from '../../helpers/clone'
+import RoutesMap from '../../helpers/routes_map'
+
+let routes = clone(window, "routes", true)
+routes = JSON.parse(decodeURIComponent(routes))
+
+var map = new RoutesMap('routes_map')
+map.addRoutes(routes)
+// map.addRoutesLabels()
+map.fitZoom()
diff --git a/app/javascript/packs/referential_overview/overview.js b/app/javascript/packs/referential_overview/overview.js
new file mode 100644
index 000000000..59c326e9a
--- /dev/null
+++ b/app/javascript/packs/referential_overview/overview.js
@@ -0,0 +1 @@
+import ReferentialOverview from '../../referential_overview'
diff --git a/app/javascript/packs/routes/edit.js b/app/javascript/packs/routes/edit.js
index d6ceed60f..b787bec97 100644
--- a/app/javascript/packs/routes/edit.js
+++ b/app/javascript/packs/routes/edit.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
@@ -12,7 +14,7 @@ datas = JSON.parse(decodeURIComponent(datas))
// logger, DO NOT REMOVE
var applyMiddleware = require('redux').applyMiddleware
-var createLogger = require('redux-logger')
+import {createLogger} from 'redux-logger';
var thunkMiddleware = require('redux-thunk').default
var promise = require('redux-promise')
diff --git a/app/javascript/packs/routes/show.js b/app/javascript/packs/routes/show.js
index 7f14a6f11..c20de0800 100644
--- a/app/javascript/packs/routes/show.js
+++ b/app/javascript/packs/routes/show.js
@@ -1,102 +1,8 @@
import clone from '../../helpers/clone'
+import RoutesMap from '../../helpers/routes_map'
+
let route = clone(window, "route", true)
route = JSON.parse(decodeURIComponent(route))
-
-const geoColPts = []
-const geoColLns = []
-const geoColEdges = [
- new ol.Feature({
- geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(route[0].longitude), parseFloat(route[0].latitude)]))
- }),
- new ol.Feature({
- geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(route[route.length - 1].longitude), parseFloat(route[route.length - 1].latitude)]))
- })
-]
-route.forEach(function (stop, i) {
- if (i < route.length - 1) {
- geoColLns.push(new ol.Feature({
- geometry: new ol.geom.LineString([
- ol.proj.fromLonLat([parseFloat(route[i].longitude), parseFloat(route[i].latitude)]),
- ol.proj.fromLonLat([parseFloat(route[i + 1].longitude), parseFloat(route[i + 1].latitude)])
- ])
- }))
- }
- geoColPts.push(new ol.Feature({
- geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)]))
- })
- )
-})
-var edgeStyles = new ol.style.Style({
- image: new ol.style.Circle(({
- radius: 5,
- stroke: new ol.style.Stroke({
- color: '#007fbb',
- width: 2
- }),
- fill: new ol.style.Fill({
- color: '#007fbb',
- width: 2
- })
- }))
-})
-var defaultStyles = new ol.style.Style({
- image: new ol.style.Circle(({
- radius: 4,
- stroke: new ol.style.Stroke({
- color: '#007fbb',
- width: 2
- }),
- fill: new ol.style.Fill({
- color: '#ffffff',
- width: 2
- })
- }))
-})
-var lineStyle = new ol.style.Style({
- stroke: new ol.style.Stroke({
- color: '#007fbb',
- width: 3
- })
-})
-
-var vectorPtsLayer = new ol.layer.Vector({
- source: new ol.source.Vector({
- features: geoColPts
- }),
- style: defaultStyles,
- zIndex: 2
-})
-var vectorEdgesLayer = new ol.layer.Vector({
- source: new ol.source.Vector({
- features: geoColEdges
- }),
- style: edgeStyles,
- zIndex: 3
-})
-var vectorLnsLayer = new ol.layer.Vector({
- source: new ol.source.Vector({
- features: geoColLns
- }),
- style: [lineStyle],
- zIndex: 1
-})
-
-var map = new ol.Map({
- target: 'route_map',
- layers: [
- new ol.layer.Tile({
- source: new ol.source.OSM()
- }),
- vectorPtsLayer,
- vectorEdgesLayer,
- vectorLnsLayer
- ],
- controls: [new ol.control.ScaleLine(), new ol.control.Zoom(), new ol.control.ZoomSlider()],
- interactions: ol.interaction.defaults({
- zoom: true
- }),
- view: new ol.View({
- center: ol.proj.fromLonLat([parseFloat(route[0].longitude), parseFloat(route[0].latitude)]),
- zoom: 13
- })
-});
+var map = new RoutesMap('route_map')
+map.addRoute(route)
+map.fitZoom()
diff --git a/app/javascript/packs/stop_areas/new.js b/app/javascript/packs/stop_areas/new.js
new file mode 100644
index 000000000..ffe702cdb
--- /dev/null
+++ b/app/javascript/packs/stop_areas/new.js
@@ -0,0 +1,3 @@
+import MasterSlave from "../../helpers/master_slave"
+
+new MasterSlave("form")
diff --git a/app/javascript/packs/vehicle_journeys/index.js b/app/javascript/packs/vehicle_journeys/index.js
index 38431af1d..e6867cb17 100644
--- a/app/javascript/packs/vehicle_journeys/index.js
+++ b/app/javascript/packs/vehicle_journeys/index.js
@@ -23,6 +23,7 @@ var initialState = {
filters: {
selectedJourneyPatterns : selectedJP,
policy: window.perms,
+ features: window.features,
toggleArrivals: false,
queryString: '',
query: {
@@ -54,11 +55,12 @@ var initialState = {
},
status: {
- fetchSuccess: true,
+ fetchSuccess: false,
isFetching: false
},
vehicleJourneys: [],
stopPointsList: window.stopPoints,
+ returnStopPointsList: window.returnStopPoints,
pagination: {
page : 1,
totalCount: 0,
@@ -69,7 +71,9 @@ var initialState = {
type: '',
modalProps: {},
confirmModal: {}
- }
+ },
+ missions: window.all_missions,
+ custom_fields: window.custom_fields
}
if (window.jpOrigin){
@@ -96,7 +100,7 @@ let store = createStore(
render(
<Provider store={store}>
- <App />
+ <App returnRouteUrl={window.returnRouteUrl} />
</Provider>,
document.getElementById('vehicle_journeys_wip')
-) \ No newline at end of file
+)
diff --git a/app/javascript/referential_overview/index.coffee b/app/javascript/referential_overview/index.coffee
new file mode 100644
index 000000000..0e6541421
--- /dev/null
+++ b/app/javascript/referential_overview/index.coffee
@@ -0,0 +1,113 @@
+class TimeTravel
+ constructor: (@overview)->
+ @container = @overview.container.find('.time-travel')
+ @todayBt = @container.find(".today")
+ @prevBt = @container.find(".prev-page")
+ @nextBt = @container.find(".next-page")
+ @searchDateBt = @container.find("a.search-date")
+ @searchDateInput = @container.find("input.date-search")
+ @initButtons()
+
+ initButtons: ->
+ @prevBt.click (e)=>
+ @overview.prevPage()
+ e.preventDefault()
+ false
+
+ @nextBt.click (e)=>
+ @overview.nextPage()
+ e.preventDefault()
+ false
+
+ @todayBt.click (e)=>
+ today = new Date()
+ month = today.getMonth() + 1
+ month = "0#{month}" if month < 10
+ day = today.getDate()
+ day = "0#{month}" if day < 10
+ @overview.showDay "#{today.getFullYear()}-#{month}-#{day}"
+ e.preventDefault()
+ false
+
+ @searchDateBt.click (e)=>
+ @overview.showDay @searchDateInput.val() if @searchDateInput.val().length > 0
+ e.preventDefault()
+ false
+
+ scrolledTo: (progress)->
+ @prevBt.removeClass 'disabled'
+ @nextBt.removeClass 'disabled'
+ @prevBt.addClass 'disabled' if progress == 0
+ @nextBt.addClass 'disabled' if progress == 1
+
+class window.ReferentialOverview
+ constructor: (selector)->
+ @container = $(selector)
+ @timeTravel = new TimeTravel(this)
+ @currentOffset = 0
+ $(document).scroll (e)=>
+ @documentScroll(e)
+ @documentScroll pageY: $(document).scrollTop()
+
+ showDay: (date)->
+ day = @container.find(".day.#{date}")
+ @container.find(".day.selected").removeClass('selected')
+ day.addClass "selected"
+ offset = day.offset().left
+ parentOffset = @currentOffset + @container.find(".right").offset().left
+ @scrollTo parentOffset - offset
+
+ currentOffset: ->
+ @container.find(".right .inner").offset().left
+
+ top: ->
+ @_top ||= @container.find('.days').offset().top - 80
+ bottom: ->
+ @_bottom ||= @top() + @container.height() - 50
+
+ prevPage: ->
+ @scrollTo @currentOffset + @container.find(".right").width()
+
+ nextPage: ->
+ @scrollTo @currentOffset - @container.find(".right").width()
+
+ minOffset: ->
+ @_minOffset ||= @container.find(".right").width() - @container.find(".right .line").width()
+ @_minOffset
+
+ scrollTo: (offset)->
+ @currentOffset = offset
+ @currentOffset = Math.max(@currentOffset, @minOffset())
+ @currentOffset = Math.min(@currentOffset, 0)
+ @container.find(".right .inner .lines").css "margin-left": "#{@currentOffset}px"
+ @container.find(".head .week:first-child").css "margin-left", "#{@currentOffset}px"
+ @timeTravel.scrolledTo 1 - (@minOffset() - @currentOffset) / @minOffset()
+ setTimeout =>
+ @movePeriodTitles()
+ , 600
+
+ movePeriodTitles: ->
+ @_right_offset ||= @container.find('.right').offset().left
+ @container.find(".shifted").removeClass("shifted").css "margin-left", 0
+ @container.find(".right .line").each (i, l) =>
+ $(l).find(".period").each (i, _p) =>
+ p = $(_p)
+ offset = parseInt(p.css("left")) + @currentOffset
+ if offset < 0 && - offset < p.width()
+ offset = Math.min(-offset, p.width() - 100)
+ p.find(".title").addClass("shifted").css "margin-left", offset + "px"
+ return
+
+ documentScroll: (e)->
+ if @sticky
+ if e.pageY < @top() || e.pageY > @bottom()
+ @container.removeClass "sticky"
+ @sticky = false
+ else
+ if e.pageY > @top() && e.pageY < @bottom()
+ @sticky = true
+ @container.addClass "sticky"
+
+
+
+export default ReferentialOverview
diff --git a/app/javascript/routes/components/App.js b/app/javascript/routes/components/App.js
index 0f5786407..26e69bf53 100644
--- a/app/javascript/routes/components/App.js
+++ b/app/javascript/routes/components/App.js
@@ -1,4 +1,5 @@
-import React, { Component, PropTypes } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import AddStopPoint from '../containers/AddStopPoint'
import VisibleStopPoints from'../containers/VisibleStopPoints'
import clone from '../../helpers/clone'
@@ -16,8 +17,8 @@ export default class App extends Component {
<VisibleStopPoints />
<AddStopPoint />
</div>
- )
- }
+ )
+ }
}
App.childContextTypes = {
diff --git a/app/javascript/routes/components/BSelect2.js b/app/javascript/routes/components/BSelect2.js
index 340d9df95..035bce155 100644
--- a/app/javascript/routes/components/BSelect2.js
+++ b/app/javascript/routes/components/BSelect2.js
@@ -1,6 +1,7 @@
import _ from'lodash'
-import React, { Component, PropTypes } from 'react'
-import Select2 from 'react-select2'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import Select2 from 'react-select2-wrapper'
// get JSON full path
@@ -84,7 +85,7 @@ class BSelect2 extends Component{
onSelect={ this.props.onSelect }
ref='newSelect'
options={{
- placeholder: this.context.I18n.routes.edit.select2.placeholder,
+ placeholder: this.context.I18n.t("routes.edit.select2.placeholder"),
allowClear: true,
language: 'fr', /* Doesn't seem to work... :( */
theme: 'bootstrap',
@@ -96,17 +97,26 @@ class BSelect2 extends Component{
data: function(params) {
return {
q: params.term,
- target_type: 'zdep'
+ scope: 'route_editor'
};
},
processResults: function(data, params) {
return {
- results: data.map(
- item => _.assign(
- {},
- item,
- { text: item.name + ", " + item.zip_code + " " + item.short_city_name + " <small><em>(" + item.user_objectid + ")</em></small>" }
- )
+ results: data.map(
+ function(item) {
+ var text = item.name;
+ if (item.zip_code || item.short_city_name) {
+ text += ","
+ }
+ if (item.zip_code) {
+ text += ` ${item.zip_code}`
+ }
+ if (item.short_city_name) {
+ text += ` ${item.short_city_name}`
+ }
+ text += ` <small><em>(${item.area_type.toUpperCase()}, ${item.user_objectid})</em></small>`;
+ return _.assign({}, item, { text: text });
+ }
)
};
},
diff --git a/app/javascript/routes/components/OlMap.js b/app/javascript/routes/components/OlMap.js
index 2c01dfa7f..4beb02872 100644
--- a/app/javascript/routes/components/OlMap.js
+++ b/app/javascript/routes/components/OlMap.js
@@ -1,5 +1,6 @@
import _ from 'lodash'
-import React, { Component, PropTypes } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
export default class OlMap extends Component{
constructor(props, context){
@@ -114,40 +115,40 @@ export default class OlMap extends Component{
<strong>{this.props.value.olMap.json.name}</strong>
</p>
<p>
- <strong>{this.context.I18n.routes.edit.stop_point_type} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.stop_point_type')} : </strong>
{this.props.value.olMap.json.area_type}
</p>
<p>
- <strong>{this.context.I18n.routes.edit.short_name} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.short_name')} : </strong>
{this.props.value.olMap.json.short_name}
</p>
<p>
- <strong>{this.context.I18n.id_reflex} : </strong>
+ <strong>{this.context.I18n.t('id_reflex')} : </strong>
{this.props.value.olMap.json.user_objectid}
</p>
- <p><strong>{this.context.I18n.routes.edit.map.coordinates} : </strong></p>
+ <p><strong>{this.context.I18n.t('routes.edit.map.coordinates')} : </strong></p>
<p style={{paddingLeft: 10, marginTop: 0}}>
- <em>{this.context.I18n.routes.edit.map.proj}.: </em>WSG84<br/>
- <em>{this.context.I18n.routes.edit.map.lat}.: </em>{this.props.value.olMap.json.latitude} <br/>
- <em>{this.context.I18n.routes.edit.map.lon}.: </em>{this.props.value.olMap.json.longitude}
+ <em>{this.context.I18n.t('routes.edit.map.proj')}.: </em>WSG84<br/>
+ <em>{this.context.I18n.t('routes.edit.map.lat')}.: </em>{this.props.value.olMap.json.latitude} <br/>
+ <em>{this.context.I18n.t('routes.edit.map.lon')}.: </em>{this.props.value.olMap.json.longitude}
</p>
<p>
- <strong>{this.context.I18n.routes.edit.map.postal_code} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.postal_code')} : </strong>
{this.props.value.olMap.json.zip_code}
</p>
<p>
- <strong>{this.context.I18n.routes.edit.map.city} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.city')} : </strong>
{this.props.value.olMap.json.city_name}
</p>
<p>
- <strong>{this.context.I18n.routes.edit.map.comment} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.comment')} : </strong>
{this.props.value.olMap.json.comment}
</p>
{(this.props.value.stoparea_id != this.props.value.olMap.json.stoparea_id) &&(
<div className='btn btn-outline-primary btn-sm'
onClick= {() => {this.props.onUpdateViaOlMap(this.props.index, this.props.value.olMap.json)}}
- >{this.context.I18n.actions.select}</div>
+ >{this.context.I18n.t('actions.select')}</div>
)}
</div>
<div className='map_content'>
@@ -161,7 +162,7 @@ export default class OlMap extends Component{
}
}
-OlMap.PropTypes = {
+OlMap.propTypes = {
}
OlMap.contextTypes = {
diff --git a/app/javascript/routes/components/StopPoint.js b/app/javascript/routes/components/StopPoint.js
index 606121f99..af51a6bb4 100644
--- a/app/javascript/routes/components/StopPoint.js
+++ b/app/javascript/routes/components/StopPoint.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
import BSelect2 from './BSelect2'
import OlMap from './OlMap'
@@ -16,15 +18,15 @@ export default function StopPoint(props, {I18n}) {
<div>
<select className='form-control' value={props.value.for_boarding} id="for_boarding" onChange={props.onSelectChange}>
- <option value="normal">{I18n.routes.edit.stop_point.boarding.normal}</option>
- <option value="forbidden">{I18n.routes.edit.stop_point.boarding.forbidden}</option>
+ <option value="normal">{I18n.t('routes.edit.stop_point.boarding.normal')}</option>
+ <option value="forbidden">{I18n.t('routes.edit.stop_point.boarding.forbidden')}</option>
</select>
</div>
<div>
<select className='form-control' value={props.value.for_alighting} id="for_alighting" onChange={props.onSelectChange}>
- <option value="normal">{I18n.routes.edit.stop_point.alighting.normal}</option>
- <option value="forbidden">{I18n.routes.edit.stop_point.alighting.forbidden}</option>
+ <option value="normal">{I18n.t('routes.edit.stop_point.alighting.normal')}</option>
+ <option value="forbidden">{I18n.t('routes.edit.stop_point.alighting.forbidden')}</option>
</select>
</div>
@@ -75,7 +77,7 @@ export default function StopPoint(props, {I18n}) {
)
}
-StopPoint.PropTypes = {
+StopPoint.propTypes = {
onToggleMap: PropTypes.func.isRequired,
onToggleEdit: PropTypes.func.isRequired,
onDeleteClick: PropTypes.func.isRequired,
@@ -91,4 +93,4 @@ StopPoint.PropTypes = {
StopPoint.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/routes/components/StopPointList.js b/app/javascript/routes/components/StopPointList.js
index 68af16f57..b227abdea 100644
--- a/app/javascript/routes/components/StopPointList.js
+++ b/app/javascript/routes/components/StopPointList.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
import StopPoint from './StopPoint'
export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange, onToggleMap, onToggleEdit, onSelectMarker, onUnselectMarker, onUpdateViaOlMap }, {I18n}) {
@@ -8,22 +10,22 @@ export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick
<div className="wrapper">
<div style={{width: 100}}>
<div className="form-group">
- <label className="control-label">{I18n.reflex_id}</label>
+ <label className="control-label">{I18n.t('simple_form.labels.stop_point.reflex_id')}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">{I18n.simple_form.labels.stop_point.name}</label>
+ <label className="control-label">{I18n.t('simple_form.labels.stop_point.name')}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">{I18n.simple_form.labels.stop_point.for_boarding}</label>
+ <label className="control-label">{I18n.t('simple_form.labels.stop_point.for_boarding')}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">{I18n.simple_form.labels.stop_point.for_alighting}</label>
+ <label className="control-label">{I18n.t('simple_form.labels.stop_point.for_alighting')}</label>
</div>
</div>
<div className='actions-5'></div>
@@ -54,7 +56,7 @@ export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick
)
}
-StopPointList.PropTypes = {
+StopPointList.propTypes = {
stopPoints: PropTypes.array.isRequired,
onDeleteClick: PropTypes.func.isRequired,
onMoveUpClick: PropTypes.func.isRequired,
@@ -66,4 +68,4 @@ StopPointList.PropTypes = {
StopPointList.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/routes/form_helper.js b/app/javascript/routes/form_helper.js
index 8a3277234..865722fb6 100644
--- a/app/javascript/routes/form_helper.js
+++ b/app/javascript/routes/form_helper.js
@@ -7,14 +7,14 @@ const formHelper = {
input.setAttribute('name', formatedName)
input.setAttribute('value', value)
form.appendChild(input)
- },
+ },
addError: (ids) => {
ids.forEach((id) => {
if (!$(id).parents('.form-group').hasClass('has-error')) {
$(id).parents('.form-group').addClass('has-error')
$(id).parent().append(`<span class='help-block small'>${'doit être rempli(e)'}</span>`)
}
- })
+ })
},
cleanInputs: (ids) => {
ids.forEach((id) =>{
@@ -28,21 +28,22 @@ const formHelper = {
ids.forEach(id => {
$(id).val() == "" ? blankInputs.push(id) : filledInputs.push(id)
})
-
+
if (filledInputs.length > 0) formHelper.cleanInputs(filledInputs)
- if (blankInputs.length > 0) formHelper.addError(blankInputs)
+ if (blankInputs.length > 0) formHelper.addError(blankInputs)
},
handleStopPoints: (event, state) => {
if (state.stopPoints.length >= 2) {
state.stopPoints.map((stopPoint, i) => {
formHelper.addInput('id', stopPoint.stoppoint_id ? stopPoint.stoppoint_id : '', i)
formHelper.addInput('stop_area_id', stopPoint.stoparea_id, i)
- formHelper.addInput('position', i, i)
+ formHelper.addInput('position', stopPoint.index, i)
formHelper.addInput('for_boarding', stopPoint.for_boarding, i)
formHelper.addInput('for_alighting', stopPoint.for_alighting, i)
})
- if ($('.alert.alert-danger').length > 0) $('.alert.alert-danger').remove()
- } else {
+ if ($('.alert.alert-danger').length > 0) $('.alert.alert-danger').remove()
+ }
+ else {
event.preventDefault()
let msg = "L'itinéraire doit comporter au moins deux arrêts"
if ($('.alert.alert-danger').length == 0) {
@@ -52,4 +53,4 @@ const formHelper = {
}
}
-export default formHelper \ No newline at end of file
+export default formHelper
diff --git a/app/javascript/routes/reducers/stopPoints.js b/app/javascript/routes/reducers/stopPoints.js
index eeec06327..0b42b504f 100644
--- a/app/javascript/routes/reducers/stopPoints.js
+++ b/app/javascript/routes/reducers/stopPoints.js
@@ -38,15 +38,15 @@ const stopPoints = (state = [], action) => {
case 'MOVE_STOP_UP':
return [
...state.slice(0, action.index - 1),
- _.assign({}, state[action.index], { stoppoint_id: state[action.index - 1].stoppoint_id }),
- _.assign({}, state[action.index - 1], { stoppoint_id: state[action.index].stoppoint_id }),
+ _.assign({}, state[action.index], { index: action.index - 1 }),
+ _.assign({}, state[action.index - 1], { index: action.index }),
...state.slice(action.index + 1)
]
case 'MOVE_STOP_DOWN':
return [
...state.slice(0, action.index),
- _.assign({}, state[action.index + 1], { stoppoint_id: state[action.index].stoppoint_id }),
- _.assign({}, state[action.index], { stoppoint_id: state[action.index + 1].stoppoint_id }),
+ _.assign({}, state[action.index + 1], { index: action.index }),
+ _.assign({}, state[action.index], { index: action.index + 1 }),
...state.slice(action.index + 2)
]
case 'DELETE_STOP':
@@ -141,4 +141,4 @@ const stopPoints = (state = [], action) => {
}
}
-export default stopPoints \ No newline at end of file
+export default stopPoints
diff --git a/app/javascript/time_tables/actions/index.js b/app/javascript/time_tables/actions/index.js
index 13cb96b64..98b9eab4b 100644
--- a/app/javascript/time_tables/actions/index.js
+++ b/app/javascript/time_tables/actions/index.js
@@ -1,5 +1,5 @@
-import range from 'lodash/range'
import assign from 'lodash/assign'
+import range from 'lodash/range'
import reject from 'lodash/reject'
import some from 'lodash/some'
import every from 'lodash/every'
@@ -8,7 +8,7 @@ const I18n = clone(window, "I18n")
const actions = {
weekDays: (index) => {
- return range(1, 8).map(n => I18n.time_tables.edit.metas.days[n])
+ return range(1, 8).map(n => I18n.t('time_tables.edit.metas.days')[n])
},
strToArrayDayTypes: (str) =>{
return actions.weekDays().map(day => str.indexOf(day) !== -1)
@@ -155,9 +155,9 @@ const actions = {
type : 'CLOSE_MODAL'
}),
monthName(strDate) {
- let monthList = range(1,13).map(n => I18n.calendars.months[n])
+ let monthList = range(1,13).map(n => I18n.t('calendars.months.'+ n ))
let date = new Date(strDate)
- return monthList[date.getMonth()]
+ return monthList[date.getUTCMonth()]
},
getHumanDate(strDate, mLimit) {
let origin = strDate.split('-')
@@ -173,7 +173,7 @@ const actions = {
},
getLocaleDate(strDate) {
let date = new Date(strDate)
- return date.toLocaleDateString()
+ return date.toLocaleDateString(undefined, { timeZone: 'UTC' })
},
updateSynthesis: ({current_month, time_table_dates: dates, time_table_periods: periods}) => {
let newPeriods = reject(periods, 'deleted')
@@ -194,7 +194,7 @@ const actions = {
for (let period of periods) {
let begin = new Date(period.period_start)
- let end = new Date(period.period_end)
+ let end = new Date(period.period_end)
if (date >= begin && date <= end) return true
}
@@ -225,7 +225,7 @@ const actions = {
let period = periods[i]
if (index !== i && !period.deleted) {
if (new Date(period.period_start) <= end && new Date(period.period_end) >= start) {
- error = I18n.time_tables.edit.error_submit.periods_overlaps
+ error = I18n.t('time_tables.edit.error_submit.periods_overlaps')
break
}
}
@@ -239,14 +239,15 @@ const actions = {
for (let day of in_days) {
if (start <= new Date(day.date) && end >= new Date(day.date)) {
- error = I18n.time_tables.edit.error_submit.dates_overlaps
+ error = I18n.t('time_tables.edit.error_submit.dates_overlaps')
break
}
}
return error
},
fetchTimeTables: (dispatch, nextPage) => {
- let urlJSON = window.location.pathname.split('/', 5).join('/')
+ let urlJSON = window.timetablesUrl || window.location.pathname.split('/', 5).join('/')
+
if(nextPage) {
urlJSON += "/month.json?date=" + nextPage
}else{
@@ -277,7 +278,7 @@ const actions = {
let strDayTypes = actions.arrayToStrDayTypes(metas.day_types)
metas.day_types = strDayTypes
let sentState = assign({}, timetable, metas)
- let urlJSON = window.location.pathname.split('/', 5).join('/')
+ let urlJSON = window.timetablesUrl || window.location.pathname.split('/', 5).join('/')
let hasError = false
fetch(urlJSON + '.json', {
credentials: 'same-origin',
@@ -315,9 +316,9 @@ const actions = {
errorModalMessage: (errorKey) => {
switch (errorKey) {
case "withoutPeriodsWithDaysTypes":
- return I18n.time_tables.edit.error_modal.withoutPeriodsWithDaysTypes
+ return I18n.t('time_tables.edit.error_modal.withoutPeriodsWithDaysTypes')
case "withPeriodsWithoutDayTypes":
- return I18n.time_tables.edit.error_modal.withPeriodsWithoutDayTypes
+ return I18n.t('time_tables.edit.error_modal.withPeriodsWithoutDayTypes')
default:
return errorKey
@@ -325,4 +326,4 @@ const actions = {
}
}
-export default actions \ No newline at end of file
+export default actions
diff --git a/app/javascript/time_tables/components/ConfirmModal.js b/app/javascript/time_tables/components/ConfirmModal.js
index d89170ee7..4e8583bc0 100644
--- a/app/javascript/time_tables/components/ConfirmModal.js
+++ b/app/javascript/time_tables/components/ConfirmModal.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCancel, timetable, metas}, {I18n}) {
return (
@@ -7,11 +9,11 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>{I18n.time_tables.edit.confirm_modal.title}</h4>
+ <h4 className='modal-title'>{I18n.t('time_tables.edit.confirm_modal.title')}</h4>
</div>
<div className='modal-body'>
<div className='mt-md mb-md'>
- <p>{I18n.time_tables.edit.confirm_modal.message}</p>
+ <p>{I18n.t('time_tables.edit.confirm_modal.message')}</p>
</div>
</div>
<div className='modal-footer'>
@@ -21,7 +23,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
type='button'
onClick={() => { onModalCancel(modal.confirmModal.callback) }}
>
- {I18n.cancel}
+ {I18n.t('cancel')}
</button>
<button
className='btn btn-primary'
@@ -29,7 +31,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
type='button'
onClick={() => { onModalAccept(modal.confirmModal.callback, timetable, metas) }}
>
- {I18n.actions.submit}
+ {I18n.t('actions.submit')}
</button>
</div>
</div>
@@ -47,4 +49,4 @@ ConfirmModal.propTypes = {
ConfirmModal.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/time_tables/components/ErrorModal.js b/app/javascript/time_tables/components/ErrorModal.js
index e810f49ab..8af12f1d1 100644
--- a/app/javascript/time_tables/components/ErrorModal.js
+++ b/app/javascript/time_tables/components/ErrorModal.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
import actions from '../actions'
export default function ErrorModal({dispatch, modal, onModalClose}, {I18n}) {
@@ -8,7 +10,7 @@ export default function ErrorModal({dispatch, modal, onModalClose}, {I18n}) {
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>{I18n.time_tables.edit.error_modal.title}</h4>
+ <h4 className='modal-title'>{I18n.t('time_tables.edit.error_modal.title')}</h4>
</div>
<div className='modal-body'>
<div className='mt-md mb-md'>
@@ -22,7 +24,7 @@ export default function ErrorModal({dispatch, modal, onModalClose}, {I18n}) {
type='button'
onClick={() => { onModalClose() }}
>
- {I18n.back}
+ {I18n.t('back')}
</button>
</div>
</div>
@@ -39,4 +41,4 @@ ErrorModal.propTypes = {
ErrorModal.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/time_tables/components/ExceptionsInDay.js b/app/javascript/time_tables/components/ExceptionsInDay.js
index 3335ee89d..f5ed625be 100644
--- a/app/javascript/time_tables/components/ExceptionsInDay.js
+++ b/app/javascript/time_tables/components/ExceptionsInDay.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
export default class ExceptionsInDay extends Component {
diff --git a/app/javascript/time_tables/components/Metas.js b/app/javascript/time_tables/components/Metas.js
index 7098d2b82..08a6e26fe 100644
--- a/app/javascript/time_tables/components/Metas.js
+++ b/app/javascript/time_tables/components/Metas.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
import actions from '../actions'
import TagsSelect2 from './TagsSelect2'
@@ -11,7 +13,7 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
{/* comment (name) */}
<div className="form-group">
<label htmlFor="" className="control-label col-sm-4 required">
- {I18n.time_tables.edit.metas.name} <abbr title="">*</abbr>
+ {I18n.t('time_tables.edit.metas.name')} <abbr title="">*</abbr>
</label>
<div className="col-sm-8">
<input
@@ -25,8 +27,8 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
</div>
{/* color */}
- <div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.color}</label>
+ {metas.color !== undefined && <div className="form-group">
+ <label htmlFor="" className="control-label col-sm-4">{I18n.attribute_name('time_table', 'color')}</label>
<div className="col-sm-8">
<div className="dropdown color_selector">
<button
@@ -67,11 +69,11 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
</div>
</div>
</div>
- </div>
+ </div>}
{/* tags */}
- <div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.tag_list}</label>
+ {metas.tags !== undefined && <div className="form-group">
+ <label htmlFor="" className="control-label col-sm-4">{I18n.attribute_name('time_table', 'tag_list')}</label>
<div className="col-sm-8">
<TagsSelect2
initialTags={metas.initial_tags}
@@ -80,20 +82,20 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
onUnselect2Tags={(e) => onUnselect2Tags(e)}
/>
</div>
- </div>
+ </div>}
{/* calendar */}
- <div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.calendar}</label>
+ {metas.calendar !== null && <div className="form-group">
+ <label htmlFor="" className="control-label col-sm-4">{I18n.attribute_name('time_table', 'calendar')}</label>
<div className="col-sm-8">
- <span>{metas.calendar ? metas.calendar.name : I18n.time_tables.edit.metas.no_calendar}</span>
+ <span>{metas.calendar ? metas.calendar.name : I18n.t('time_tables.edit.metas.no_calendar')}</span>
</div>
- </div>
+ </div>}
{/* day_types */}
<div className="form-group">
<label htmlFor="" className="control-label col-sm-4">
- {I18n.time_tables.edit.metas.day_types}
+ {I18n.t('time_tables.edit.metas.day_types')}
</label>
<div className="col-sm-8">
<div className="form-group labelled-checkbox-group">
diff --git a/app/javascript/time_tables/components/Navigate.js b/app/javascript/time_tables/components/Navigate.js
index 7307d819b..1467fffe9 100644
--- a/app/javascript/time_tables/components/Navigate.js
+++ b/app/javascript/time_tables/components/Navigate.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import map from 'lodash/map'
import actions from '../actions'
@@ -23,7 +24,7 @@ export default function Navigate({ dispatch, metas, timetable, pagination, statu
aria-haspopup='true'
aria-expanded='true'
>
- {pagination.currentPage ? (actions.monthName(pagination.currentPage) + ' ' + new Date(pagination.currentPage).getFullYear()) : ''}
+ {pagination.currentPage ? (actions.monthName(pagination.currentPage) + ' ' + new Date(pagination.currentPage).getUTCFullYear()) : ''}
<span className='caret'></span>
</div>
<ul
@@ -40,7 +41,7 @@ export default function Navigate({ dispatch, metas, timetable, pagination, statu
dispatch(actions.checkConfirmModal(e, actions.changePage(dispatch, e.currentTarget.value), pagination.stateChanged, dispatch, metas, timetable))
}}
>
- {actions.monthName(month) + ' ' + new Date(month).getFullYear()}
+ {actions.monthName(month) + ' ' + new Date(month).getUTCFullYear()}
</button>
</li>
))}
@@ -85,4 +86,4 @@ Navigate.propTypes = {
status: PropTypes.object.isRequired,
pagination: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/time_tables/components/PeriodForm.js b/app/javascript/time_tables/components/PeriodForm.js
index d9f1d3437..d17a246f7 100644
--- a/app/javascript/time_tables/components/PeriodForm.js
+++ b/app/javascript/time_tables/components/PeriodForm.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
import filter from 'lodash/filter'
let monthsArray = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
@@ -44,7 +46,7 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
<div>
<div className="form-group">
<label htmlFor="" className="control-label required">
- {I18n.time_tables.edit.period_form.begin}
+ {I18n.t('time_tables.edit.period_form.begin')}
<abbr title="requis">*</abbr>
</label>
</div>
@@ -52,7 +54,7 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
<div>
<div className="form-group">
<label htmlFor="" className="control-label required">
- {I18n.time_tables.edit.period_form.end}
+ {I18n.t('time_tables.edit.period_form.end')}
<abbr title="requis">*</abbr>
</label>
</div>
@@ -103,14 +105,14 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
className='btn btn-link'
onClick={onClosePeriodForm}
>
- {I18n.cancel}
+ {I18n.t('cancel')}
</button>
<button
type='button'
className='btn btn-outline-primary mr-sm'
onClick={() => onValidatePeriodForm(modal.modalProps, timetable.time_table_periods, metas, filter(timetable.time_table_dates, ['in_out', true]))}
>
- {I18n.actions.submit}
+ {I18n.t('actions.submit')}
</button>
</div>
</div>
@@ -122,7 +124,7 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
className='btn btn-outline-primary'
onClick={onOpenAddPeriodForm}
>
- {I18n.time_tables.actions.add_period}
+ {I18n.t('time_tables.actions.add_period')}
</button>
</div>
}
@@ -130,7 +132,7 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
</div>
</div>
</div>
- )
+ )
}
PeriodForm.propTypes = {
@@ -145,4 +147,4 @@ PeriodForm.propTypes = {
PeriodForm.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/time_tables/components/PeriodManager.js b/app/javascript/time_tables/components/PeriodManager.js
index 9922ce2c4..6b817fe73 100644
--- a/app/javascript/time_tables/components/PeriodManager.js
+++ b/app/javascript/time_tables/components/PeriodManager.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
export default class PeriodManager extends Component {
diff --git a/app/javascript/time_tables/components/PeriodsInDay.js b/app/javascript/time_tables/components/PeriodsInDay.js
index 888537579..1aed5c969 100644
--- a/app/javascript/time_tables/components/PeriodsInDay.js
+++ b/app/javascript/time_tables/components/PeriodsInDay.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import PeriodManager from './PeriodManager'
export default class PeriodsInDay extends Component {
diff --git a/app/javascript/time_tables/components/SaveTimetable.js b/app/javascript/time_tables/components/SaveTimetable.js
index d5a57bd1c..704590abd 100644
--- a/app/javascript/time_tables/components/SaveTimetable.js
+++ b/app/javascript/time_tables/components/SaveTimetable.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
export default class SaveTimetable extends Component{
diff --git a/app/javascript/time_tables/components/TagsSelect2.js b/app/javascript/time_tables/components/TagsSelect2.js
index 70a748a04..43cf59fdf 100644
--- a/app/javascript/time_tables/components/TagsSelect2.js
+++ b/app/javascript/time_tables/components/TagsSelect2.js
@@ -1,9 +1,10 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import mapKeys from 'lodash/mapKeys'
import map from 'lodash/map'
import filter from 'lodash/filter'
import assign from 'lodash/assign'
-import Select2 from 'react-select2'
+import Select2 from 'react-select2-wrapper'
// get JSON full path
let origin = window.location.origin
@@ -39,7 +40,7 @@ export default class TagsSelect2 extends Component {
allowClear: true,
theme: 'bootstrap',
width: '100%',
- placeholder: this.context.I18n.time_tables.edit.select2.tag.placeholder,
+ placeholder: this.context.I18n.t('time_tables.edit.select2.tag.placeholder'),
ajax: {
url: origin + path + '/tags.json',
dataType: 'json',
diff --git a/app/javascript/time_tables/components/TimeTableDay.js b/app/javascript/time_tables/components/TimeTableDay.js
index 165c7b848..498e7d0cd 100644
--- a/app/javascript/time_tables/components/TimeTableDay.js
+++ b/app/javascript/time_tables/components/TimeTableDay.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
export default class TimeTableDay extends Component {
constructor(props) {
diff --git a/app/javascript/time_tables/components/Timetable.js b/app/javascript/time_tables/components/Timetable.js
index df6e6016b..991f31435 100644
--- a/app/javascript/time_tables/components/Timetable.js
+++ b/app/javascript/time_tables/components/Timetable.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
import TimeTableDay from './TimeTableDay'
import PeriodsInDay from './PeriodsInDay'
@@ -30,11 +31,11 @@ export default class Timetable extends Component {
<div className="table table-2entries mb-sm">
<div className="t2e-head w20">
<div className="th">
- <div className="strong">{this.context.I18n.time_tables.synthesis}</div>
+ <div className="strong">{this.context.I18n.t('time_tables.edit.synthesis')}</div>
</div>
- <div className="td"><span>{this.context.I18n.time_tables.edit.day_types}</span></div>
- <div className="td"><span>{this.context.I18n.time_tables.edit.periods}</span></div>
- <div className="td"><span>{this.context.I18n.time_tables.edit.exceptions}</span></div>
+ <div className="td"><span>{this.context.I18n.t('time_tables.edit.day_types')}</span></div>
+ <div className="td"><span>{this.context.I18n.t('time_tables.edit.periods')}</span></div>
+ <div className="td"><span>{this.context.I18n.t('time_tables.edit.exceptions')}</span></div>
</div>
<div className="t2e-item-list w80">
<div>
diff --git a/app/javascript/time_tables/containers/App.js b/app/javascript/time_tables/containers/App.js
index 235dccb50..5963f8f1d 100644
--- a/app/javascript/time_tables/containers/App.js
+++ b/app/javascript/time_tables/containers/App.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import { connect } from'react-redux'
import actions from '../actions'
import Metas from './Metas'
diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js
index ce4b9209d..4ca8bd73b 100644
--- a/app/javascript/vehicle_journeys/actions/index.js
+++ b/app/javascript/vehicle_journeys/actions/index.js
@@ -13,8 +13,8 @@ const actions = {
exitEditMode: () => ({
type: "EXIT_EDIT_MODE"
}),
- receiveVehicleJourneys : (json) => ({
- type: "RECEIVE_VEHICLE_JOURNEYS",
+ receiveVehicleJourneys : (json, returnJourneys) => ({
+ type: (returnJourneys ? "RECEIVE_RETURN_VEHICLE_JOURNEYS" : "RECEIVE_VEHICLE_JOURNEYS"),
json
}),
receiveErrors : (json) => ({
@@ -57,15 +57,22 @@ const actions = {
selectedItem: {
id: selectedJP.id,
objectid: selectedJP.object_id,
+ short_id: selectedJP.short_id,
name: selectedJP.name,
published_name: selectedJP.published_name,
- stop_areas: selectedJP.stop_area_short_descriptions
+ stop_areas: selectedJP.stop_area_short_descriptions,
+ costs: selectedJP.costs,
+ full_schedule: selectedJP.full_schedule
}
}),
openEditModal : (vehicleJourney) => ({
type : 'EDIT_VEHICLEJOURNEY_MODAL',
vehicleJourney
}),
+ openInfoModal : (vehicleJourney) => ({
+ type : 'INFO_VEHICLEJOURNEY_MODAL',
+ vehicleJourney
+ }),
openNotesEditModal : (vehicleJourney) => ({
type : 'EDIT_NOTES_VEHICLEJOURNEY_MODAL',
vehicleJourney
@@ -84,7 +91,8 @@ const actions = {
selectedItem:{
id: selectedTT.id,
comment: selectedTT.comment,
- objectid: selectedTT.objectid
+ objectid: selectedTT.objectid,
+ color: selectedTT.color
}
}),
addSelectedTimetable: () => ({
@@ -99,6 +107,31 @@ const actions = {
vehicleJourneys,
timetables
}),
+ openPurchaseWindowsEditModal : (vehicleJourneys) => ({
+ type : 'EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL',
+ vehicleJourneys
+ }),
+ selectPurchaseWindowsModal: (selectedWindow) =>({
+ type: 'SELECT_PURCHASE_WINDOW_MODAL',
+ selectedItem:{
+ id: selectedWindow.id,
+ name: selectedWindow.name,
+ color: selectedWindow.color,
+ objectid: selectedWindow.objectid
+ }
+ }),
+ addSelectedPurchaseWindow: () => ({
+ type: 'ADD_SELECTED_PURCHASE_WINDOW'
+ }),
+ deletePurchaseWindowsModal : (purchaseWindow) => ({
+ type : 'DELETE_PURCHASE_WINDOW_MODAL',
+ purchaseWindow
+ }),
+ editVehicleJourneyPurchaseWindows : (vehicleJourneys, purchase_windows) => ({
+ type: 'EDIT_VEHICLEJOURNEYS_PURCHASE_WINDOWS',
+ vehicleJourneys,
+ purchase_windows
+ }),
openShiftModal : () => ({
type : 'SHIFT_VEHICLEJOURNEY_MODAL'
}),
@@ -162,26 +195,18 @@ const actions = {
resetValidation: (target) => {
$(target).parent().removeClass('has-error').children('.help-block').remove()
},
- validateFields : (...fields) => {
- const test = []
-
- Object.keys(fields).map(function(key) {
- test.push(fields[key].validity.valid)
+ validateFields : (fields) => {
+ let valid = true
+ Object.keys(fields).forEach((key) => {
+ let field = fields[key]
+ if(field.validity && !field.validity.valid){
+ valid = false
+ $(field).parent().addClass('has-error').children('.help-block').remove()
+ $(field).parent().append("<span class='small help-block'>" + field.validationMessage + "</span>")
+ }
})
- if(test.indexOf(false) >= 0) {
- // Form is invalid
- test.map(function(item, i) {
- if(item == false) {
- const k = Object.keys(fields)[i]
- $(fields[k]).parent().addClass('has-error').children('.help-block').remove()
- $(fields[k]).parent().append("<span class='small help-block'>" + fields[k].validationMessage + "</span>")
- }
- })
- return false
- } else {
- // Form is valid
- return true
- }
+
+ return valid
},
toggleArrivals : () => ({
type: 'TOGGLE_ARRIVALS',
@@ -269,10 +294,17 @@ const actions = {
type: 'RECEIVE_TOTAL_COUNT',
total
}),
- fetchVehicleJourneys : (dispatch, currentPage, nextPage, queryString) => {
+ fetchVehicleJourneys : (dispatch, currentPage, nextPage, queryString, url) => {
+ let returnJourneys = false
if(currentPage == undefined){
currentPage = 1
}
+ if(url == undefined){
+ url = window.location.pathname
+ }
+ else{
+ returnJourneys = true
+ }
let vehicleJourneys = []
let page
switch (nextPage) {
@@ -294,7 +326,7 @@ const actions = {
str = '.json?page=' + page.toString()
sep = '&'
}
- let urlJSON = window.location.pathname + str
+ let urlJSON = url + str
if (queryString){
urlJSON = urlJSON + sep + queryString
}
@@ -313,6 +345,7 @@ const actions = {
let val
for (val of json.vehicle_journeys){
var timeTables = []
+ var purchaseWindows = []
let tt
for (tt of val.time_tables){
timeTables.push({
@@ -322,33 +355,56 @@ const actions = {
color: tt.color
})
}
+ if(val.purchase_windows){
+ for (tt of val.purchase_windows){
+ purchaseWindows.push({
+ objectid: tt.objectid,
+ name: tt.name,
+ id: tt.id,
+ color: tt.color
+ })
+ }
+ }
let vjasWithDelta = val.vehicle_journey_at_stops.map((vjas, i) => {
actions.fillEmptyFields(vjas)
return actions.getDelta(vjas)
})
- vehicleJourneys.push({
- journey_pattern: val.journey_pattern,
- published_journey_name: val.published_journey_name,
- objectid: val.objectid,
- short_id: val.short_id,
- footnotes: val.footnotes,
- time_tables: timeTables,
- vehicle_journey_at_stops: vjasWithDelta,
- deletable: false,
- selected: false,
- published_journey_name: val.published_journey_name || 'non renseigné',
- published_journey_identifier: val.published_journey_identifier || 'non renseigné',
- company: val.company || 'non renseigné',
- transport_mode: val.route.line.transport_mode || 'undefined',
- transport_submode: val.route.line.transport_submode || 'undefined'
- })
+
+ vehicleJourneys.push(
+ _.assign({}, val, {
+ time_tables: timeTables,
+ purchase_windows: purchaseWindows,
+ vehicle_journey_at_stops: vjasWithDelta,
+ deletable: false,
+ selected: false,
+ published_journey_name: val.published_journey_name || 'non renseigné',
+ published_journey_identifier: val.published_journey_identifier || 'non renseigné',
+ company: val.company || {name: 'non renseigné'},
+ transport_mode: val.route.line.transport_mode || 'undefined',
+ transport_submode: val.route.line.transport_submode || 'undefined'
+ })
+ )
}
window.currentItemsLength = vehicleJourneys.length
- dispatch(actions.receiveVehicleJourneys(vehicleJourneys))
- dispatch(actions.receiveTotalCount(json.total))
+ dispatch(actions.receiveVehicleJourneys(vehicleJourneys, returnJourneys))
+ if(!returnJourneys){
+ dispatch(actions.receiveTotalCount(json.total))
+ }
}
})
},
+
+ validate : (dispatch, vehicleJourneys, next) => {
+ dispatch(actions.didValidateVehicleJourneys(vehicleJourneys))
+ actions.submitVehicleJourneys(dispatch, vehicleJourneys, next)
+ return true
+ },
+
+ didValidateVehicleJourneys : (vehicleJourneys) => ({
+ type: 'DID_VALIDATE_VEHICLE_JOURNEYS',
+ vehicleJourneys
+ }),
+
submitVehicleJourneys : (dispatch, state, next) => {
dispatch(actions.fetchingApi())
let urlJSON = window.location.pathname + "_collection.json"
@@ -439,6 +495,20 @@ const actions = {
vjas.delta = delta
return vjas
},
+ adjustSchedule: (action, schedule) => {
+ // we enforce that the departure time remains after the arrival time
+ actions.getDelta(schedule)
+ if(schedule.delta < 0){
+ if(action.isDeparture){
+ schedule.arrival_time = schedule.departure_time
+ }
+ else{
+ schedule.departure_time = schedule.arrival_time
+ }
+ actions.getDelta(schedule)
+ }
+ return schedule
+ },
getShiftedSchedule: ({departure_time, arrival_time}, additional_time) => {
// We create dummy dates objects to manipulate time more easily
let departureDT = new Date (Date.UTC(2017, 2, 1, parseInt(departure_time.hour), parseInt(departure_time.minute)))
diff --git a/app/javascript/vehicle_journeys/components/App.js b/app/javascript/vehicle_journeys/components/App.js
index 8e5f7aa9d..5ac284438 100644
--- a/app/javascript/vehicle_journeys/components/App.js
+++ b/app/javascript/vehicle_journeys/components/App.js
@@ -22,6 +22,7 @@ export default function App() {
<Filters />
<VehicleJourneysList />
+ {window.returnRouteUrl && <VehicleJourneysList routeUrl={window.returnRouteUrl}/>}
<div className='row'>
<div className='col-lg-12 text-right'>
@@ -35,4 +36,4 @@ export default function App() {
<ConfirmModal />
</div>
)
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/ConfirmModal.js b/app/javascript/vehicle_journeys/components/ConfirmModal.js
index df3c96c48..75e8a3932 100644
--- a/app/javascript/vehicle_journeys/components/ConfirmModal.js
+++ b/app/javascript/vehicle_journeys/components/ConfirmModal.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCancel, vehicleJourneys}) {
return (
@@ -6,7 +7,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-body'>
- <p> Voulez-vous valider vos modifications avant de changer de page? </p>
+ <p> {I18n.t('vehicle_journeys.vehicle_journeys_matrix.modal_confirm')} </p>
</div>
<div className='modal-footer'>
<button
@@ -30,11 +31,11 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
</div>
</div>
)
-}
+}
ConfirmModal.propTypes = {
vehicleJourneys: PropTypes.array.isRequired,
modal: PropTypes.object.isRequired,
onModalAccept: PropTypes.func.isRequired,
onModalCancel: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/Filters.js b/app/javascript/vehicle_journeys/components/Filters.js
index db6707520..f8697c930 100644
--- a/app/javascript/vehicle_journeys/components/Filters.js
+++ b/app/javascript/vehicle_journeys/components/Filters.js
@@ -1,9 +1,11 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
import MissionSelect2 from'./tools/select2s/MissionSelect2'
import VJSelect2 from'./tools/select2s/VJSelect2'
import TimetableSelect2 from'./tools/select2s/TimetableSelect2'
-export default function Filters({filters, pagination, onFilter, onResetFilters, onUpdateStartTimeFilter, onUpdateEndTimeFilter, onToggleWithoutSchedule, onToggleWithoutTimeTable, onSelect2Timetable, onSelect2JourneyPattern, onSelect2VehicleJourney}) {
+export default function Filters({filters, pagination, missions, onFilter, onResetFilters, onUpdateStartTimeFilter, onUpdateEndTimeFilter, onToggleWithoutSchedule, onToggleWithoutTimeTable, onSelect2Timetable, onSelect2JourneyPattern, onSelect2VehicleJourney}) {
return (
<div className='row'>
<div className='col-lg-12'>
@@ -24,6 +26,7 @@ export default function Filters({filters, pagination, onFilter, onResetFilters,
onSelect2JourneyPattern={onSelect2JourneyPattern}
filters={filters}
isFilter={true}
+ values={missions}
/>
</div>
@@ -33,6 +36,7 @@ export default function Filters({filters, pagination, onFilter, onResetFilters,
onSelect2Timetable={onSelect2Timetable}
hasRoute={true}
chunkURL={("/autocomplete_time_tables.json?route_id=" + String(window.route_id))}
+ searchKey={"comment_or_objectid_cont_any"}
filters={filters}
isFilter={true}
/>
@@ -42,10 +46,10 @@ export default function Filters({filters, pagination, onFilter, onResetFilters,
<div className='ffg-row'>
{/* Plage horaire */}
<div className='form-group togglable'>
- <label className='control-label'>Plage horaire au départ de la course</label>
+ <label className='control-label'>{I18n.t("vehicle_journeys.form.departure_range.label")}</label>
<div className='filter_menu'>
<div className='form-group time filter_menu-item'>
- <label className='control-label time'>Début</label>
+ <label className='control-label time'>{I18n.t("vehicle_journeys.form.departure_range.start")}</label>
<div className='form-inline'>
<div className='input-group time'>
<input
@@ -69,7 +73,7 @@ export default function Filters({filters, pagination, onFilter, onResetFilters,
</div>
</div>
<div className='form-group time filter_menu-item'>
- <label className='control-label time'>Fin</label>
+ <label className='control-label time'>{I18n.t("vehicle_journeys.form.departure_range.end")}</label>
<div className='form-inline'>
<div className='input-group time'>
<input
@@ -97,7 +101,7 @@ export default function Filters({filters, pagination, onFilter, onResetFilters,
{/* Switch avec/sans horaires */}
<div className='form-group has_switch'>
- <label className='control-label pull-left'>Afficher les courses sans horaires</label>
+ <label className='control-label pull-left'>{I18n.t("vehicle_journeys.form.show_journeys_without_schedule")}</label>
<div className='form-group pull-left' style={{padding: 0}}>
<div className='checkbox'>
<label>
@@ -106,8 +110,8 @@ export default function Filters({filters, pagination, onFilter, onResetFilters,
onChange={onToggleWithoutSchedule}
checked={filters.query.withoutSchedule}
></input>
- <span className='switch-label' data-checkedvalue='Non' data-uncheckedvalue='Oui'>
- {filters.query.withoutSchedule ? 'Oui' : 'Non'}
+ <span className='switch-label' data-checkedvalue={I18n.t("no")} data-uncheckedvalue={I18n.t("yes")}>
+ {filters.query.withoutSchedule ? I18n.t("yes") : I18n.t("no")}
</span>
</label>
</div>
@@ -118,7 +122,7 @@ export default function Filters({filters, pagination, onFilter, onResetFilters,
<div className="ffg-row">
{/* Switch avec/sans calendrier */}
<div className='form-group has_switch'>
- <label className='control-label pull-left'>Afficher les courses avec calendrier</label>
+ <label className='control-label pull-left'>{I18n.t("vehicle_journeys.form.show_journeys_with_calendar")}</label>
<div className='form-group pull-left' style={{padding: 0}}>
<div className='checkbox'>
<label>
@@ -127,8 +131,8 @@ export default function Filters({filters, pagination, onFilter, onResetFilters,
onChange={onToggleWithoutTimeTable}
checked={filters.query.withoutTimeTable}
></input>
- <span className='switch-label' data-checkedvalue='Non' data-uncheckedvalue='Oui'>
- {filters.query.withoutTimeTable ? 'Oui' : 'Non'}
+ <span className='switch-label' data-checkedvalue={I18n.t("no")} data-uncheckedvalue={I18n.t("yes")}>
+ {filters.query.withoutTimeTable ? I18n.t("yes") : I18n.t("no")}
</span>
</label>
</div>
@@ -165,4 +169,4 @@ Filters.propTypes = {
onSelect2Timetable: PropTypes.func.isRequired,
onSelect2JourneyPattern: PropTypes.func.isRequired,
onSelect2VehicleJourney: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/Navigate.js b/app/javascript/vehicle_journeys/components/Navigate.js
index 7493b705b..24843babc 100644
--- a/app/javascript/vehicle_journeys/components/Navigate.js
+++ b/app/javascript/vehicle_journeys/components/Navigate.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from'../actions'
export default function Navigate({ dispatch, vehicleJourneys, pagination, status, filters}) {
@@ -16,8 +17,7 @@ export default function Navigate({ dispatch, vehicleJourneys, pagination, status
if(status.fetchSuccess == true) {
return (
<div className="pagination">
- Liste des horaires {minVJ} à {maxVJ} sur {pagination.totalCount}
-
+ {I18n.t("vehicle_journeys.vehicle_journeys_matrix.pagination", {minVJ, maxVJ, total:pagination.totalCount})}
<form className='page_links' onSubmit={e => {e.preventDefault()}}>
<button
onClick={e => {
@@ -52,4 +52,4 @@ Navigate.propTypes = {
status: PropTypes.object.isRequired,
pagination: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js
index e8c27f92e..fb921df9c 100644
--- a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js
@@ -1,34 +1,19 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import SaveButton from '../../helpers/save_button'
import actions from '../actions'
-export default class SaveVehicleJourneys extends Component{
- constructor(props){
- super(props)
+export default class SaveVehicleJourneys extends SaveButton{
+ hasPolicy(){
+ return this.props.filters.policy['vehicle_journeys.update'] == true
}
- render() {
- if (this.props.filters.policy['vehicle_journeys.update'] == false) {
- return false
- }else{
- return (
- <div className='row mt-md'>
- <div className='col-lg-12 text-right'>
- <form className='vehicle_journeys formSubmitr ml-xs' onSubmit={e => {e.preventDefault()}}>
- <button
- className='btn btn-default'
- type='button'
- onClick={e => {
- e.preventDefault()
- this.props.editMode ? this.props.onSubmitVehicleJourneys(this.props.dispatch, this.props.vehicleJourneys) : this.props.onEnterEditMode()
- }}
- >
- {this.props.editMode ? "Valider" : "Editer"}
- </button>
- </form>
- </div>
- </div>
- )
- }
+ formClassName(){
+ return 'vehicle_journeys'
+ }
+
+ submitForm(){
+ this.props.validate(this.props.vehicleJourneys, this.props.dispatch)
}
}
@@ -38,5 +23,6 @@ SaveVehicleJourneys.propTypes = {
status: PropTypes.object.isRequired,
filters: PropTypes.object.isRequired,
onEnterEditMode: PropTypes.func.isRequired,
+ onExitEditMode: PropTypes.func.isRequired,
onSubmitVehicleJourneys: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/ToggleArrivals.js b/app/javascript/vehicle_journeys/components/ToggleArrivals.js
index e26ceec3a..9a2b0097f 100644
--- a/app/javascript/vehicle_journeys/components/ToggleArrivals.js
+++ b/app/javascript/vehicle_journeys/components/ToggleArrivals.js
@@ -1,9 +1,11 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
export default function ToggleArrivals({filters, onToggleArrivals}) {
return (
<div className='has_switch form-group inline'>
- <label htmlFor='toggleArrivals' className='control-label'>Afficher et éditer les horaires d'arrivée</label>
+ <label htmlFor='toggleArrivals' className='control-label'>{I18n.t('vehicle_journeys.form.show_arrival_time')}</label>
<div className='form-group'>
<div className='checkbox'>
<label>
@@ -24,4 +26,4 @@ export default function ToggleArrivals({filters, onToggleArrivals}) {
ToggleArrivals.propTypes = {
filters : PropTypes.object.isRequired,
onToggleArrivals: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/Tools.js b/app/javascript/vehicle_journeys/components/Tools.js
index 7621dfc10..22ea44283 100644
--- a/app/javascript/vehicle_journeys/components/Tools.js
+++ b/app/javascript/vehicle_journeys/components/Tools.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
import AddVehicleJourney from '../containers/tools/AddVehicleJourney'
import DeleteVehicleJourneys from '../containers/tools/DeleteVehicleJourneys'
@@ -7,6 +8,7 @@ import DuplicateVehicleJourney from '../containers/tools/DuplicateVehicleJourney
import EditVehicleJourney from '../containers/tools/EditVehicleJourney'
import NotesEditVehicleJourney from '../containers/tools/NotesEditVehicleJourney'
import TimetablesEditVehicleJourney from '../containers/tools/TimetablesEditVehicleJourney'
+import PurchaseWindowsEditVehicleJourney from '../containers/tools/PurchaseWindowsEditVehicleJourney'
export default class Tools extends Component {
@@ -17,7 +19,12 @@ export default class Tools extends Component {
hasPolicy(key) {
// Check if the user has the policy to disable or not the action
- return this.props.filters.policy[`vehicle_journeys.${key}`]
+ return this.props.filters.policy[`vehicle_journeys.${key}`]
+ }
+
+ hasFeature(key) {
+ // Check if the organisation has the given feature
+ return this.props.filters.features[key]
}
render() {
@@ -25,17 +32,20 @@ export default class Tools extends Component {
return (
<div className='select_toolbox'>
<ul>
- <AddVehicleJourney disabled={this.hasPolicy("create") && !editMode} />
- <DuplicateVehicleJourney disabled={this.hasPolicy("create") && this.hasPolicy("update") && !editMode}/>
- <ShiftVehicleJourney disabled={this.hasPolicy("update") && !editMode}/>
+ <AddVehicleJourney disabled={!this.hasPolicy("create") || !editMode} />
+ <DuplicateVehicleJourney disabled={!this.hasPolicy("create") || !this.hasPolicy("update") || !editMode}/>
+ <ShiftVehicleJourney disabled={!this.hasPolicy("update") || !editMode}/>
<EditVehicleJourney disabled={!this.hasPolicy("update")}/>
<TimetablesEditVehicleJourney disabled={!this.hasPolicy("update")}/>
+ { this.hasFeature('purchase_windows') &&
+ <PurchaseWindowsEditVehicleJourney disabled={!this.hasPolicy("update")}/>
+ }
<NotesEditVehicleJourney disabled={!this.hasPolicy("update")}/>
- <DeleteVehicleJourneys disabled={this.hasPolicy("destroy") && !editMode}/>
+ <DeleteVehicleJourneys disabled={!this.hasPolicy("destroy") || !editMode}/>
</ul>
- <span className='info-msg'>{actions.getSelected(vehicleJourneys).length} course(s) sélectionnée(s)</span>
- <button className='btn btn-xs btn-link pull-right' onClick={onCancelSelection}>Annuler la sélection</button>
+ <span className='info-msg'>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.selected_journeys', {count: actions.getSelected(vehicleJourneys).length})}</span>
+ <button className='btn btn-xs btn-link pull-right' onClick={onCancelSelection}>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.cancel_selection')}</button>
</div>
)
}
@@ -45,4 +55,4 @@ Tools.propTypes = {
vehicleJourneys : PropTypes.array.isRequired,
onCancelSelection: PropTypes.func.isRequired,
filters: PropTypes.object.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js
index 929cbc5c4..4a9432231 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js
@@ -1,5 +1,8 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../actions'
+import EditVehicleJourney from '../containers/tools/EditVehicleJourney'
+import VehicleJourneyInfoButton from '../containers/tools/VehicleJourneyInfoButton'
export default class VehicleJourney extends Component {
constructor(props) {
@@ -8,13 +11,11 @@ export default class VehicleJourney extends Component {
}
cityNameChecker(sp) {
- let bool = false
- if(sp.stop_area_cityname != this.previousCity){
- bool = true
- this.previousCity = sp.stop_area_cityname
- }
+ return this.props.vehicleJourneys.showHeader(sp.stop_point_objectid)
+ }
- return bool
+ hasFeature(key) {
+ return this.props.filters.features[key]
}
timeTableURL(tt) {
@@ -22,7 +23,16 @@ export default class VehicleJourney extends Component {
let ttURL = refURL + '/time_tables/' + tt.id
return (
- <a href={ttURL} title='Voir le calendrier'><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '')}}></span></a>
+ <a href={ttURL} title={I18n.t('vehicle_journeys.vehicle_journeys_matrix.show_timetable')}><span className='fa fa-calendar' style={{ color: (tt.color ? tt.color : '#4B4B4B')}}></span></a>
+ )
+ }
+
+ purchaseWindowURL(tt) {
+ let refURL = window.location.pathname.split('/', 3).join('/')
+ let ttURL = refURL + '/purchase_windows/' + tt.id
+
+ return (
+ <a href={ttURL} title={I18n.t('vehicle_journeys.vehicle_journeys_matrix.show_purchase_window')}><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '')}}></span></a>
)
}
@@ -44,20 +54,35 @@ export default class VehicleJourney extends Component {
render() {
this.previousCity = undefined
- let {time_tables} = this.props.value
+ let {time_tables, purchase_windows} = this.props.value
return (
<div className={'t2e-item' + (this.props.value.deletable ? ' disabled' : '') + (this.props.value.errors ? ' has-error': '')}>
- <div className='th'>
+ <div
+ className='th'
+ onClick={(e) =>
+ !this.props.disabled && ($(e.target).parents("a").length == 0) && this.props.onSelectVehicleJourney(this.props.index)
+ }
+ >
<div className='strong mb-xs'>{this.props.value.short_id || '-'}</div>
+ <div>{this.props.value.published_journey_name && this.props.value.published_journey_name != I18n.t('undefined') ? this.props.value.published_journey_name : '-'}</div>
<div>{this.props.value.journey_pattern.short_id || '-'}</div>
+ <div>{this.props.value.company ? this.props.value.company.name : '-'}</div>
<div>
{time_tables.slice(0,3).map((tt, i)=>
<span key={i} className='vj_tt'>{this.timeTableURL(tt)}</span>
)}
{time_tables.length > 3 && <span className='vj_tt'> + {time_tables.length - 3}</span>}
</div>
- <div className={(this.props.value.deletable ? 'disabled ' : '') + 'checkbox'}>
+ { this.hasFeature('purchase_windows') &&
+ <div>
+ {purchase_windows.slice(0,3).map((tt, i)=>
+ <span key={i} className='vj_tt'>{this.purchaseWindowURL(tt)}</span>
+ )}
+ {purchase_windows.length > 3 && <span className='vj_tt'> + {purchase_windows.length - 3}</span>}
+ </div>
+ }
+ {!this.props.disabled && <div className={(this.props.value.deletable ? 'disabled ' : '') + 'checkbox'}>
<input
id={this.props.index}
name={this.props.index}
@@ -68,20 +93,21 @@ export default class VehicleJourney extends Component {
checked={this.props.value.selected}
></input>
<label htmlFor={this.props.index}></label>
- </div>
+ </div>}
+ {this.props.disabled && <VehicleJourneyInfoButton vehicleJourney={this.props.value} />}
</div>
{this.props.value.vehicle_journey_at_stops.map((vj, i) =>
<div key={i} className='td text-center'>
<div className={'cellwrap' + (this.cityNameChecker(vj) ? ' headlined' : '')}>
{this.props.filters.toggleArrivals &&
- <div data-headline='Arrivée à'>
+ <div data-headline={I18n.t("vehicle_journeys.form.arrival_at")}>
<span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}>
<input
type='number'
min='00'
max='23'
className='form-control'
- disabled={this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}
+ disabled={!this.props.editMode || this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}
readOnly={!this.props.editMode && !vj.dummy}
onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', false, false)}}
value={vj.arrival_time['hour']}
@@ -92,7 +118,7 @@ export default class VehicleJourney extends Component {
min='00'
max='59'
className='form-control'
- disabled={this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}
+ disabled={!this.props.editMode || this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}
readOnly={!this.props.editMode && !vj.dummy}
onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'minute', false, false)}}
value={vj.arrival_time['minute']}
@@ -105,14 +131,14 @@ export default class VehicleJourney extends Component {
<span className='sb sb-chrono sb-lg text-warning' data-textinside={vj.delta}></span>
}
</div>
- <div data-headline='Départ à'>
+ <div data-headline={I18n.t("vehicle_journeys.form.departure_at")}>
<span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}>
<input
type='number'
min='00'
max='23'
className='form-control'
- disabled={this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}
+ disabled={!this.props.editMode || this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}
readOnly={!this.props.editMode && !vj.dummy}
onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', true, this.props.filters.toggleArrivals)}}
value={vj.departure_time['hour']}
@@ -123,13 +149,16 @@ export default class VehicleJourney extends Component {
min='00'
max='59'
className='form-control'
- disabled={this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}
+ disabled={!this.props.editMode || this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}
readOnly={!this.props.editMode && !vj.dummy}
onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, "minute", true, this.props.filters.toggleArrivals)}}
value={vj.departure_time['minute']}
/>
</span>
</div>
+ {vj.errors && <div className="errors">
+ {vj.errors}
+ </div>}
</div>
</div>
)}
@@ -143,5 +172,6 @@ VehicleJourney.propTypes = {
filters: PropTypes.object.isRequired,
index: PropTypes.number.isRequired,
onUpdateTime: PropTypes.func.isRequired,
- onSelectVehicleJourney: PropTypes.func.isRequired
-} \ No newline at end of file
+ onSelectVehicleJourney: PropTypes.func.isRequired,
+ vehicleJourneys: PropTypes.object.isRequired,
+}
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
index 6bce9766b..01e07ee0c 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
@@ -1,15 +1,51 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import _ from 'lodash'
import VehicleJourney from './VehicleJourney'
-
+import StopAreaHeaderManager from '../../helpers/stop_area_header_manager'
export default class VehicleJourneys extends Component {
constructor(props){
super(props)
- this.previousCity = undefined
+ this.headerManager = new StopAreaHeaderManager(
+ _.map(this.stopPoints(), (sp)=>{return sp.object_id}),
+ this.stopPoints(),
+ this.props.filters.features
+ )
+ }
+
+ isReturn() {
+ return this.props.routeUrl != undefined
+ }
+
+ vehicleJourneysList() {
+ if(this.isReturn()){
+ return this.props.returnVehicleJourneys
+ }
+ else{
+ return this.props.vehicleJourneys
+ }
+ }
+
+ stopPoints() {
+ if(this.isReturn()){
+ return this.props.returnStopPointsList
+ }
+ else{
+ return this.props.stopPointsList
+ }
}
+
componentDidMount() {
- this.props.onLoadFirstPage(this.props.filters)
+ this.props.onLoadFirstPage(this.props.filters, this.props.routeUrl)
+ }
+
+ hasFeature(key) {
+ return this.props.filters.features[key]
+ }
+
+ showHeader(object_id) {
+ return this.headerManager.showHeader(object_id)
}
componentDidUpdate(prevProps, prevState) {
@@ -55,25 +91,8 @@ export default class VehicleJourneys extends Component {
}
}
- cityNameChecker(sp) {
- let bool = false
- if(sp.city_name != this.previousCity){
- bool = true
- this.previousCity = sp.city_name
- }
- return (
- <div
- className={(bool) ? 'headlined' : ''}
- data-headline={(bool) ? sp.city_name : ''}
- title={sp.city_name + ' (' + sp.zip_code +')'}
- >
- <span><span>{sp.name}</span></span>
- </div>
- )
- }
-
render() {
- this.previousCity = undefined
+ this.previousBreakpoint = undefined
if(this.props.status.isFetching == true) {
return (
@@ -87,15 +106,15 @@ export default class VehicleJourneys extends Component {
<div className='col-lg-12'>
{(this.props.status.fetchSuccess == false) && (
<div className='alert alert-danger mt-sm'>
- <strong>Erreur : </strong>
- la récupération des missions a rencontré un problème. Rechargez la page pour tenter de corriger le problème.
+ <strong>{I18n.tc("error")}</strong>
+ {I18n.t("vehicle_journeys.vehicle_journeys_matrix.fetching_error")}
</div>
)}
- { _.some(this.props.vehicleJourneys, 'errors') && (
+ { this.vehicleJourneysList().errors && this.vehicleJourneysList().errors.length && _.some(this.vehicleJourneysList(), 'errors') && (
<div className="alert alert-danger mt-sm">
- <strong>Erreur : </strong>
- {this.props.vehicleJourneys.map((vj, index) =>
+ <strong>{I18n.tc("error")}</strong>
+ {this.vehicleJourneysList().map((vj, index) =>
vj.errors && vj.errors.map((err, i) => {
return (
<ul key={i}>
@@ -107,17 +126,20 @@ export default class VehicleJourneys extends Component {
</div>
)}
- <div className={'table table-2entries mt-sm mb-sm' + ((this.props.vehicleJourneys.length > 0) ? '' : ' no_result')}>
+ <div className={'table table-2entries mt-sm mb-sm' + ((this.vehicleJourneysList().length > 0) ? '' : ' no_result')}>
<div className='t2e-head w20'>
<div className='th'>
- <div className='strong mb-xs'>ID course</div>
- <div>ID mission</div>
- <div>Calendriers</div>
+ <div className='strong mb-xs'>{I18n.attribute_name("vehicle_journey", "id")}</div>
+ <div>{I18n.attribute_name("vehicle_journey", "name")}</div>
+ <div>{I18n.attribute_name("vehicle_journey", "journey_pattern_id")}</div>
+ <div>{I18n.model_name("company")}</div>
+ <div>{I18n.model_name("time_table", "plural": true)}</div>
+ { this.hasFeature('purchase_windows') && <div>{I18n.model_name("purchase_window", "plural": true)}</div> }
</div>
- {this.props.stopPointsList.map((sp, i) =>{
+ {this.stopPoints().map((sp, i) =>{
return (
<div key={i} className='td'>
- {this.cityNameChecker(sp)}
+ {this.headerManager.stopPointHeader(sp.object_id)}
</div>
)
})}
@@ -125,15 +147,18 @@ export default class VehicleJourneys extends Component {
<div className='t2e-item-list w80'>
<div>
- {this.props.vehicleJourneys.map((vj, index) =>
+ {this.vehicleJourneysList().map((vj, index) =>
<VehicleJourney
value={vj}
key={index}
index={index}
- editMode={this.props.editMode}
+ editMode={this.isReturn() ? false : this.props.editMode}
filters={this.props.filters}
+ features={this.props.features}
onUpdateTime={this.props.onUpdateTime}
onSelectVehicleJourney={this.props.onSelectVehicleJourney}
+ vehicleJourneys={this}
+ disabled={this.isReturn()}
/>
)}
</div>
@@ -153,4 +178,4 @@ VehicleJourneys.propTypes = {
onLoadFirstPage: PropTypes.func.isRequired,
onUpdateTime: PropTypes.func.isRequired,
onSelectVehicleJourney: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js
index 33873219c..8536f66e6 100644
--- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js
+++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js
@@ -1,16 +1,19 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../../actions'
import MissionSelect2 from './select2s/MissionSelect2'
import CompanySelect2 from './select2s/CompanySelect2'
+import CustomFieldsInputs from './CustomFieldsInputs'
export default class CreateModal extends Component {
constructor(props) {
super(props)
+ this.custom_fields = _.assign({}, this.props.custom_fields)
}
handleSubmit() {
if (actions.validateFields(...this.refs, $('.vjCreateSelectJP')[0]) && this.props.modal.modalProps.selectedJPModal) {
- this.props.onAddVehicleJourney(this.refs, this.props.modal.modalProps.selectedJPModal, this.props.stopPointsList, this.props.modal.modalProps.selectedCompany)
+ this.props.onAddVehicleJourney(_.assign({}, this.refs, {custom_fields: this.custom_fields}), this.props.modal.modalProps.selectedJPModal, this.props.stopPointsList, this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company)
this.props.onModalClose()
$('#NewVehicleJourneyModal').modal('hide')
}
@@ -61,8 +64,9 @@ export default class CreateModal extends Component {
<div className='form-group'>
<label className='control-label'>Nom du transporteur</label>
<CompanySelect2
- company = {undefined}
+ company = {this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company || undefined}
onSelect2Company = {(e) => this.props.onSelect2Company(e)}
+ onUnselect2Company = {() => this.props.onUnselect2Company()}
/>
</div>
</div>
@@ -72,6 +76,7 @@ export default class CreateModal extends Component {
<MissionSelect2
selection={this.props.modal.modalProps}
onSelect2JourneyPattern={this.props.onSelect2JourneyPattern}
+ values={this.props.missions}
isFilter={false}
/>
</div>
@@ -87,6 +92,36 @@ export default class CreateModal extends Component {
/>
</div>
</div>
+ <CustomFieldsInputs
+ values={this.props.custom_fields}
+ onUpdate={(code, value) => this.custom_fields[code]["value"] = value}
+ disabled={false}
+ />
+ { this.props.modal.modalProps.selectedJPModal && this.props.modal.modalProps.selectedJPModal.full_schedule && <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
+ <div className='form-group'>
+ <label className='control-label'>Heure de départ</label>
+ <div className='input-group time'>
+ <input
+ type='number'
+ min='00'
+ max='23'
+ ref='start_time.hour'
+ className='form-control'
+ onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
+ />
+ <input
+ type='number'
+ min='00'
+ max='59'
+ ref='start_time.minute'
+ className='form-control'
+ onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
+ />
+ </div>
+ </div>
+ </div>
+ }
+
</div>
</div>
<div className='modal-footer'>
@@ -129,5 +164,6 @@ CreateModal.propTypes = {
onModalClose: PropTypes.func.isRequired,
onAddVehicleJourney: PropTypes.func.isRequired,
onSelect2JourneyPattern: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired
-} \ No newline at end of file
+ disabled: PropTypes.bool.isRequired,
+ missions: PropTypes.array.isRequired
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js b/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js
new file mode 100644
index 000000000..90d72a801
--- /dev/null
+++ b/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js
@@ -0,0 +1,50 @@
+import _ from 'lodash'
+import Select2 from 'react-select2-wrapper'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+
+export default class CustomFieldsInputs extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ listInput(cf){
+ return(
+ <Select2
+ data={_.map(cf.options.list_values, (v, k) => {
+ return {id: k, text: (v.length > 0 ? v : '\u00A0')}
+ })}
+ ref={'custom_fields.' + cf.code}
+ className='form-control'
+ defaultValue={cf.value}
+ disabled={this.props.disabled}
+ options={{
+ theme: 'bootstrap',
+ width: '100%'
+ }}
+ onSelect={(e) => this.props.onUpdate(cf.code, e.params.data.id) }
+ />
+ )
+ }
+
+ render() {
+ return (
+ <div>
+ {_.map(this.props.values, (cf, code) =>
+ <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12' key={code}>
+ <div className='form-group'>
+ <label className='control-label'>{cf.name}</label>
+ {this[cf.field_type + "Input"](cf)}
+ </div>
+ </div>
+ )}
+ </div>
+ )
+ }
+}
+
+CustomFieldsInputs.propTypes = {
+ onUpdate: PropTypes.func.isRequired,
+ values: PropTypes.object.isRequired,
+ disabled: PropTypes.bool.isRequired
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js b/app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js
index fc13ae964..4815003d3 100644
--- a/app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
+
import actions from '../../actions'
export default function DeleteVehicleJourneys({onDeleteVehicleJourneys, vehicleJourneys, disabled}) {
diff --git a/app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js
index 8083defb9..102a87d85 100644
--- a/app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../../actions'
import _ from 'lodash'
diff --git a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
index f8d6add03..d3c01f154 100644
--- a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
@@ -1,33 +1,47 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../../actions'
import CompanySelect2 from './select2s/CompanySelect2'
+import CustomFieldsInputs from './CustomFieldsInputs'
export default class EditVehicleJourney extends Component {
constructor(props) {
super(props)
+ this.updateValue = this.updateValue.bind(this)
}
handleSubmit() {
if(actions.validateFields(this.refs) == true) {
- var company;
+ var company = undefined
if(this.props.modal.modalProps.selectedCompany) {
company = this.props.modal.modalProps.selectedCompany
- } else if (typeof this.props.modal.modalProps.vehicleJourney.company === Object) {
+ } else if (typeof this.props.modal.modalProps.vehicleJourney.company === "object") {
company = this.props.modal.modalProps.vehicleJourney.company
- } else {
- company = undefined
}
- this.props.onEditVehicleJourney(this.refs, company)
+ this.props.onEditVehicleJourney(_.assign({}, this.refs, {custom_fields: this.custom_fields}), company)
this.props.onModalClose()
$('#EditVehicleJourneyModal').modal('hide')
}
}
+ updateValue(attribute, e) {
+ this.props.modal.modalProps.vehicleJourney[attribute] = e.target.value
+ actions.resetValidation(e.currentTarget)
+ this.forceUpdate()
+ }
+
+ editMode() {
+ return !this.props.modal.modalProps.info && this.props.editMode
+ }
+
render() {
if(this.props.status.isFetching == true) {
return false
}
if(this.props.status.fetchSuccess == true) {
+ if(this.props.modal.modalProps.vehicleJourney){
+ this.custom_fields = _.assign({}, this.props.modal.modalProps.vehicleJourney.custom_fields)
+ }
return (
<li className='st_action'>
<button
@@ -45,60 +59,60 @@ export default class EditVehicleJourney extends Component {
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>Informations</h4>
+ <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.infos')}</h4>
<span type="button" className="close modal-close" data-dismiss="modal">&times;</span>
</div>
{(this.props.modal.type == 'edit') && (
<form>
<div className='modal-body'>
- <div className='row'>
- <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
- <div className='form-group'>
- <label className='control-label'>Nom de la course</label>
- <input
- type='text'
- ref='published_journey_name'
- className='form-control'
- disabled={!this.props.editMode}
- defaultValue={this.props.modal.modalProps.vehicleJourney.published_journey_name}
- onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
- />
+ <div className='row'>
+ <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
+ <div className='form-group'>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'journey_name')}</label>
+ <input
+ type='text'
+ ref='published_journey_name'
+ className='form-control'
+ disabled={!this.editMode()}
+ value={this.props.modal.modalProps.vehicleJourney.published_journey_name}
+ onChange={(e) => this.updateValue('published_journey_name', e)}
+ />
+ </div>
</div>
- </div>
- <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
- <div className='form-group'>
- <label className='control-label'>Mission</label>
- <input
- type='text'
- className='form-control'
- value={this.props.modal.modalProps.vehicleJourney.journey_pattern.short_id + ' - ' + (this.props.modal.modalProps.vehicleJourney.journey_pattern.name)}
- disabled={true}
- />
+ <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
+ <div className='form-group'>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'journey_pattern')}</label>
+ <input
+ type='text'
+ className='form-control'
+ value={this.props.modal.modalProps.vehicleJourney.journey_pattern.short_id + ' - ' + (this.props.modal.modalProps.vehicleJourney.journey_pattern.name)}
+ disabled={true}
+ />
+ </div>
</div>
</div>
- </div>
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Numéro de train</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'company')}</label>
<input
type='text'
ref='published_journey_identifier'
className='form-control'
- disabled={!this.props.editMode}
- defaultValue={this.props.modal.modalProps.vehicleJourney.published_journey_identifier}
- onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
+ disabled={!this.editMode()}
+ value={this.props.modal.modalProps.vehicleJourney.published_journey_identifier}
+ onChange={(e) => this.updateValue('published_journey_identifier', e)}
/>
</div>
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Transporteur</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'company')}</label>
<CompanySelect2
editModal={this.props.modal.type == "edit"}
- editMode={this.props.editMode}
+ editMode={this.editMode()}
company = {this.props.modal.modalProps.vehicleJourney.company}
onSelect2Company = {(e) => this.props.onSelect2Company(e)}
onUnselect2Company = {() => this.props.onUnselect2Company()}
@@ -110,30 +124,48 @@ export default class EditVehicleJourney extends Component {
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Mode de transport</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'transport_mode')}</label>
<input
type='text'
className='form-control'
- value={window.I18n.fr.enumerize.transport_mode[this.props.modal.modalProps.vehicleJourney.transport_mode]}
+ value={I18n.enumerize('transport_mode', this.props.modal.modalProps.vehicleJourney.transport_mode)}
disabled={true}
/>
</div>
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Sous mode de transport</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'transport_submode')}</label>
<input
type='text'
className='form-control'
- value={window.I18n.fr.enumerize.transport_submode[this.props.modal.modalProps.vehicleJourney.transport_submode]}
+ value={I18n.enumerize('transport_submode', this.props.modal.modalProps.vehicleJourney.transport_submode)}
disabled={true}
/>
</div>
</div>
</div>
+ <div className='form-group'>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'checksum')}</label>
+ <input
+ type='text'
+ ref='checksum'
+ className='form-control'
+ disabled='disabled'
+ defaultValue={this.props.modal.modalProps.vehicleJourney.checksum}
+ />
+ </div>
+ <div className='row'>
+ <CustomFieldsInputs
+ values={this.props.modal.modalProps.vehicleJourney.custom_fields}
+ onUpdate={(code, value) => this.custom_fields[code]["value"] = value}
+ disabled={!this.editMode()}
+ />
+ </div>
</div>
+
{
- this.props.editMode &&
+ this.editMode() &&
<div className='modal-footer'>
<button
className='btn btn-link'
@@ -151,7 +183,7 @@ export default class EditVehicleJourney extends Component {
Valider
</button>
</div>
- }
+ }
</form>
)}
@@ -171,4 +203,4 @@ EditVehicleJourney.propTypes = {
onOpenEditModal: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired,
disabled: PropTypes.bool.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
index de97bc403..880542216 100644
--- a/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../../actions'
import _ from 'lodash'
diff --git a/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js
new file mode 100644
index 000000000..ce9a4cde9
--- /dev/null
+++ b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js
@@ -0,0 +1,153 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import actions from '../../actions'
+import TimetableSelect2 from './select2s/TimetableSelect2'
+
+export default class PurchaseWindowsEditVehicleJourney extends Component {
+ constructor(props) {
+ super(props)
+ this.handleSubmit = this.handleSubmit.bind(this)
+ this.purchaseWindowURL = this.purchaseWindowURL.bind(this)
+ }
+
+ handleSubmit() {
+ this.props.onShoppingWindowsEditVehicleJourney(this.props.modal.modalProps.vehicleJourneys, this.props.modal.modalProps.purchase_windows)
+ this.props.onModalClose()
+ $('#PurchaseWindowsEditVehicleJourneyModal').modal('hide')
+ }
+
+ purchaseWindowURL(tt) {
+ let refURL = window.location.pathname.split('/', 3).join('/')
+ return refURL + '/purchase_windows/' + tt.id
+ }
+
+ render() {
+ if(this.props.status.isFetching == true) {
+ return false
+ }
+ if(this.props.status.fetchSuccess == true) {
+ return (
+ <li className='st_action'>
+ <button
+ type='button'
+ disabled={(actions.getSelected(this.props.vehicleJourneys).length < 1 || this.props.disabled)}
+ data-toggle='modal'
+ data-target='#PurchaseWindowsEditVehicleJourneyModal'
+ onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))}
+ title='Calendriers commerciaux'
+ >
+ <span className='sb sb-purchase_window sb-strong'></span>
+ </button>
+
+ <div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='PurchaseWindowsEditVehicleJourneyModal'>
+ <div className='modal-container'>
+ <div className='modal-dialog'>
+ <div className='modal-content'>
+ <div className='modal-header'>
+ <h4 className='modal-title'>Calendriers commerciaux associés</h4>
+ <span type="button" className="close modal-close" data-dismiss="modal">&times;</span>
+ </div>
+
+ {(this.props.modal.type == 'purchase_windows_edit') && (
+ <form>
+ <div className='modal-body'>
+ <div className='row'>
+ <div className='col-lg-12'>
+ <div className='subform'>
+ <div className='nested-head'>
+ <div className='wrapper'>
+ <div>
+ <div className='form-group'>
+ <label className='control-label'>{this.props.modal.modalProps.purchase_windows.length == 0 ? "Aucun calendrier commercial associé" : "Calendriers commerciaux associés"}</label>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ </div>
+ {this.props.modal.modalProps.purchase_windows.map((tt, i) =>
+ <div className='nested-fields' key={i}>
+ <div className='wrapper'>
+ <div> <a href={this.purchaseWindowURL(tt)} target="_blank">
+ <span className="fa fa-circle mr-xs" style={{color: tt.color}}></span>
+ {tt.name}
+ </a> </div>
+ {
+ this.props.editMode &&
+ <div>
+ <a
+ href='#'
+ title='Supprimer'
+ className='fa fa-trash remove_fields'
+ style={{ height: 'auto', lineHeight: 'normal' }}
+ onClick={(e) => {
+ e.preventDefault()
+ this.props.onDeleteCalendarModal(tt)
+ }}
+ ></a>
+ </div>
+ }
+ </div>
+ </div>
+ )}
+ {
+ this.props.editMode &&
+ <div className='nested-fields'>
+ <div className='wrapper'>
+ <div>
+ <TimetableSelect2
+ onSelect2Timetable={this.props.onSelect2Timetable}
+ chunkURL={'/autocomplete_purchase_windows.json'}
+ searchKey={"name_or_objectid_cont_any"}
+ isFilter={false}
+ />
+ </div>
+ </div>
+ </div>
+ }
+ </div>
+ </div>
+ </div>
+ </div>
+ {
+ this.props.editMode &&
+ <div className='modal-footer'>
+ <button
+ className='btn btn-link'
+ data-dismiss='modal'
+ type='button'
+ onClick={this.props.onModalClose}
+ >
+ Annuler
+ </button>
+ <button
+ className='btn btn-primary'
+ type='button'
+ onClick={this.handleSubmit}
+ >
+ Valider
+ </button>
+ </div>
+ }
+ </form>
+ )}
+
+ </div>
+ </div>
+ </div>
+ </div>
+ </li>
+ )
+ } else {
+ return false
+ }
+ }
+}
+
+PurchaseWindowsEditVehicleJourney.propTypes = {
+ onOpenCalendarsEditModal: PropTypes.func.isRequired,
+ onModalClose: PropTypes.func.isRequired,
+ onShoppingWindowsEditVehicleJourney: PropTypes.func.isRequired,
+ onDeleteCalendarModal: PropTypes.func.isRequired,
+ onSelect2Timetable: PropTypes.func.isRequired,
+ disabled: PropTypes.bool.isRequired
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js
index a54e40502..6574bfa2d 100644
--- a/app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../../actions'
export default class ShiftVehicleJourney extends Component {
diff --git a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js
index 6629135dd..e2fcd27d5 100644
--- a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js
@@ -1,4 +1,5 @@
-import React, { PropTypes, Component } from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import actions from '../../actions'
import TimetableSelect2 from './select2s/TimetableSelect2'
@@ -33,6 +34,7 @@ export default class TimetablesEditVehicleJourney extends Component {
data-toggle='modal'
data-target='#CalendarsEditVehicleJourneyModal'
onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))}
+ title='Calendriers'
>
<span className='fa fa-calendar'></span>
</button>
@@ -65,9 +67,14 @@ export default class TimetablesEditVehicleJourney extends Component {
{this.props.modal.modalProps.timetables.map((tt, i) =>
<div className='nested-fields' key={i}>
<div className='wrapper'>
- <div> <a href={this.timeTableURL(tt)} target="_blank">{tt.comment}</a> </div>
+ <div>
+ <a href={this.timeTableURL(tt)} target="_blank">
+ <span className="fa fa-circle mr-xs" style={{color: tt.color || 'black'}}></span>
+ {tt.comment}
+ </a>
+ </div>
{
- this.props.editMode &&
+ this.props.editMode &&
<div>
<a
href='#'
@@ -85,13 +92,14 @@ export default class TimetablesEditVehicleJourney extends Component {
</div>
)}
{
- this.props.editMode &&
+ this.props.editMode &&
<div className='nested-fields'>
<div className='wrapper'>
<div>
<TimetableSelect2
onSelect2Timetable={this.props.onSelect2Timetable}
chunkURL={'/autocomplete_time_tables.json'}
+ searchKey={"comment_or_objectid_cont_any"}
isFilter={false}
/>
</div>
@@ -103,7 +111,7 @@ export default class TimetablesEditVehicleJourney extends Component {
</div>
</div>
{
- this.props.editMode &&
+ this.props.editMode &&
<div className='modal-footer'>
<button
className='btn btn-link'
@@ -144,4 +152,4 @@ TimetablesEditVehicleJourney.propTypes = {
onDeleteCalendarModal: PropTypes.func.isRequired,
onSelect2Timetable: PropTypes.func.isRequired,
disabled: PropTypes.bool.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js b/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js
new file mode 100644
index 000000000..538bbdbd6
--- /dev/null
+++ b/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js
@@ -0,0 +1,30 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import actions from '../../actions'
+
+export default class VehicleJourneyInfoButton extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+
+ render() {
+ return (
+ <div className='info-button'>
+ <button
+ type='button'
+ data-toggle='modal'
+ data-target='#EditVehicleJourneyModal'
+ onClick={() => this.props.onOpenEditModal(this.props.vehicleJourney)}
+ >
+ <span className='fa fa-info'></span>
+ </button>
+ </div>
+ )
+ }
+}
+
+VehicleJourneyInfoButton.propTypes = {
+ onOpenEditModal: PropTypes.func.isRequired,
+ vehicleJourney: PropTypes.object.isRequired,
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js
index 79ba8f094..5c7f75d99 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js
@@ -1,6 +1,7 @@
import _ from 'lodash'
-import React, { PropTypes, Component } from 'react'
-import Select2 from 'react-select2'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import Select2 from 'react-select2-wrapper'
import actions from '../../../actions'
// get JSON full path
@@ -25,7 +26,7 @@ export default class BSelect4 extends Component {
multiple={false}
ref='company_id'
options={{
- allowClear: this.props.editMode,
+ allowClear: true,
theme: 'bootstrap',
width: '100%',
placeholder: 'Filtrer par transporteur...',
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
index fa847886c..7ab85a1ea 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
@@ -1,6 +1,7 @@
import _ from 'lodash'
-import React, { PropTypes, Component } from 'react'
-import Select2 from 'react-select2'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import Select2 from 'react-select2-wrapper'
import actions from '../../../actions'
// get JSON full path
@@ -11,50 +12,114 @@ let path = window.location.pathname.split('/', 7).join('/')
export default class BSelect4 extends Component {
constructor(props) {
super(props)
+ this.onSelect = this.onSelect.bind(this)
+ }
+
+ useAjax(){
+ return this.props.values == undefined || this.props.values.length == 0
+ }
+
+ value(){
+ let val = undefined
+ if(this.props.isFilter) {
+ val = this.props.filters.query.journeyPattern
+ }
+ else{
+ if(this.props.selection.selectedJPModal){
+ val = this.props.selection.selectedJPModal
+ }
+ }
+ if(this.useAjax()){
+ val = val.published_name
+ }
+ else{
+ if(val){
+ val = val.id
+ }
+ }
+ return val
+ }
+
+ data(){
+ if(!this.useAjax()){
+ let values = [{}]
+ values.push(...this.props.values)
+ return values
+ }
+ if(this.props.isFilter){
+ return [this.props.filters.query.journeyPattern.published_name]
+ }
+
+ return (this.props.selection.selectedJPModal) ? [this.props.selection.selectedJPModal.published_name] : undefined
+ }
+
+ onSelect(e){
+ if(this.useAjax()){
+ this.props.onSelect2JourneyPattern(e)
+ }
+ else{
+ let data = JSON.parse(e.currentTarget.selectedOptions[0].dataset.item)
+
+ this.props.onSelect2JourneyPattern({params:
+ {
+ data: _.assign({}, e.params.data, data)
+ }
+ })
+ }
+ }
+
+ options(){
+ let options = {
+ theme: 'bootstrap',
+ width: '100%',
+ escapeMarkup: function (markup) { return markup; },
+ templateResult: formatRepo,
+ placeholder: 'Filtrer par code, nom ou OID de mission...',
+ language: require('./fr'),
+ allowClear: false,
+ escapeMarkup: function (markup) { return markup; },
+ }
+ if(this.useAjax()){
+ options = _.assign({}, options, {
+ ajax: {
+ url: origin + path + '/journey_patterns_collection.json',
+ dataType: 'json',
+ delay: '500',
+ data: function(params) {
+ return {
+ q: { published_name_or_objectid_or_registration_number_cont: params.term},
+ };
+ },
+ processResults: function(data, params) {
+ return {
+ results: data.map(
+ item => _.assign(
+ {},
+ item,
+ { text: "<strong>" + item.published_name + " - " + item.short_id + "</strong><br/><small>" + item.registration_number + "</small>" }
+ )
+ )
+ };
+ },
+ cache: true
+ },
+ minimumInputLength: 1
+ })
+ }
+ return options
}
render() {
return (
<Select2
- data={(this.props.isFilter) ? [this.props.filters.query.journeyPattern.published_name] : ((this.props.selection.selectedJPModal) ? [this.props.selection.selectedJPModal.published_name] : undefined)}
- value={(this.props.isFilter) ? this.props.filters.query.journeyPattern.published_name : ((this.props.selection.selectedJPModal) ? this.props.selection.selectedJPModal.published_name : undefined) }
- onSelect={(e) => this.props.onSelect2JourneyPattern(e)}
+ data={this.data()}
+ value={this.value()}
+ onSelect={this.onSelect}
multiple={false}
ref='journey_pattern_id'
className={!this.props.isFilter ? "vjCreateSelectJP" : null}
required={!this.props.isFilter}
- options={{
- allowClear: false,
- theme: 'bootstrap',
- placeholder: 'Filtrer par code, nom ou OID de mission...',
- language: require('./fr'),
- width: '100%',
- ajax: {
- url: origin + path + '/journey_patterns_collection.json',
- dataType: 'json',
- delay: '500',
- data: function(params) {
- return {
- q: { published_name_or_objectid_or_registration_number_cont: params.term},
- };
- },
- processResults: function(data, params) {
- return {
- results: data.map(
- item => _.assign(
- {},
- item,
- { text: "<strong>" + item.published_name + " - " + item.short_id + "</strong><br/><small>" + item.registration_number + "</small>" }
- )
- )
- };
- },
- cache: true
- },
- minimumInputLength: 1,
- escapeMarkup: function (markup) { return markup; },
- templateResult: formatRepo
- }}
+ options={this.options()}
/>
)
}
@@ -62,4 +127,4 @@ export default class BSelect4 extends Component {
const formatRepo = (props) => {
if(props.text) return props.text
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
index 19c183839..0339455ca 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
@@ -1,6 +1,7 @@
import _ from 'lodash'
-import React, { PropTypes, Component } from 'react'
-import Select2 from 'react-select2'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import Select2 from 'react-select2-wrapper'
import actions from '../../../actions'
// get JSON full path
@@ -31,12 +32,10 @@ export default class BSelect4 extends Component {
url: origin + path + this.props.chunkURL,
dataType: 'json',
delay: '500',
- data: function(params) {
- return {
- q: {
- comment_or_objectid_cont_any: params.term
- }
- };
+ data: (params) => {
+ let q = {}
+ q[this.props.searchKey] = params.term
+ return {q}
},
processResults: function(data, params) {
return {
@@ -44,7 +43,7 @@ export default class BSelect4 extends Component {
item => _.assign(
{},
item,
- {text: '<strong>' + "<span class='fa fa-circle' style='color:" + (item.color ? item.color : '#4B4B4B') + "'></span> " + item.comment + ' - ' + item.short_id + '</strong><br/><small>' + (item.day_types ? item.day_types.match(/[A-Z]?[a-z]+/g).join(', ') : "") + '</small>'}
+ {text: '<strong>' + "<span class='fa fa-circle' style='color:" + (item.color ? item.color : '#4B4B4B') + "'></span> " + (item.comment || item.name) + ' - ' + item.short_id + '</strong><br/><small>' + (item.day_types ? item.day_types.match(/[A-Z]?[a-z]+/g).join(', ') : "") + '</small>'}
)
)
};
@@ -62,4 +61,4 @@ export default class BSelect4 extends Component {
const formatRepo = (props) => {
if(props.text) return props.text
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js
index b063abeca..ccb4c9595 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js
@@ -1,6 +1,7 @@
import _ from 'lodash'
-import React, { PropTypes, Component } from 'react'
-import Select2 from 'react-select2'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import Select2 from 'react-select2-wrapper'
import actions from '../../../actions'
// get JSON full path
diff --git a/app/javascript/vehicle_journeys/containers/Filters.js b/app/javascript/vehicle_journeys/containers/Filters.js
index bec3527f4..a41c599f7 100644
--- a/app/javascript/vehicle_journeys/containers/Filters.js
+++ b/app/javascript/vehicle_journeys/containers/Filters.js
@@ -5,7 +5,8 @@ import Filters from '../components/Filters'
const mapStateToProps = (state) => {
return {
filters: state.filters,
- pagination: state.pagination
+ pagination: state.pagination,
+ missions: state.missions,
}
}
diff --git a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js
index 18f9e994e..3daf831f8 100644
--- a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js
@@ -17,8 +17,15 @@ const mapDispatchToProps = (dispatch) => {
onEnterEditMode: () => {
dispatch(actions.enterEditMode())
},
+ onExitEditMode: () => {
+ dispatch(actions.cancelSelection())
+ dispatch(actions.exitEditMode())
+ },
onSubmitVehicleJourneys: (next, state) => {
actions.submitVehicleJourneys(dispatch, state, next)
+ },
+ validate: (state) =>{
+ actions.validate(dispatch, state)
}
}
}
diff --git a/app/javascript/vehicle_journeys/containers/VehicleJourneysList.js b/app/javascript/vehicle_journeys/containers/VehicleJourneysList.js
index 38ab9f6d3..76d1c3a78 100644
--- a/app/javascript/vehicle_journeys/containers/VehicleJourneysList.js
+++ b/app/javascript/vehicle_journeys/containers/VehicleJourneysList.js
@@ -6,17 +6,19 @@ const mapStateToProps = (state) => {
return {
editMode: state.editMode,
vehicleJourneys: state.vehicleJourneys,
+ returnVehicleJourneys: state.returnVehicleJourneys,
status: state.status,
filters: state.filters,
- stopPointsList: state.stopPointsList
+ stopPointsList: state.stopPointsList,
+ returnStopPointsList: state.returnStopPointsList
}
}
const mapDispatchToProps = (dispatch) => {
return {
- onLoadFirstPage: (filters) =>{
+ onLoadFirstPage: (filters, routeUrl) =>{
dispatch(actions.fetchingApi())
- actions.fetchVehicleJourneys(dispatch, undefined, undefined, filters.queryString)
+ actions.fetchVehicleJourneys(dispatch, undefined, undefined, filters.queryString, routeUrl)
},
onUpdateTime: (e, subIndex, index, timeUnit, isDeparture, isArrivalsToggled) => {
dispatch(actions.updateTime(e.target.value, subIndex, index, timeUnit, isDeparture, isArrivalsToggled))
diff --git a/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js b/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js
index 5da0bd3e9..d982f5a5f 100644
--- a/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js
@@ -9,6 +9,8 @@ const mapStateToProps = (state, ownProps) => {
vehicleJourneys: state.vehicleJourneys,
status: state.status,
stopPointsList: state.stopPointsList,
+ missions: state.missions,
+ custom_fields: state.custom_fields,
}
}
@@ -28,6 +30,9 @@ const mapDispatchToProps = (dispatch) => {
},
onSelect2Company: (e) => {
dispatch(actions.select2Company(e.params.data))
+ },
+ onUnselect2Company: () => {
+ dispatch(actions.unselect2Company())
}
}
}
diff --git a/app/javascript/vehicle_journeys/containers/tools/PurchaseWindowsEditVehicleJourney.js b/app/javascript/vehicle_journeys/containers/tools/PurchaseWindowsEditVehicleJourney.js
new file mode 100644
index 000000000..3fef44489
--- /dev/null
+++ b/app/javascript/vehicle_journeys/containers/tools/PurchaseWindowsEditVehicleJourney.js
@@ -0,0 +1,38 @@
+import actions from '../../actions'
+import { connect } from 'react-redux'
+import PurchaseWindowsEditVehicleJourneyComponent from '../../components/tools/PurchaseWindowsEditVehicleJourney'
+
+const mapStateToProps = (state, ownProps) => {
+ return {
+ editMode: state.editMode,
+ modal: state.modal,
+ vehicleJourneys: state.vehicleJourneys,
+ status: state.status,
+ disabled: ownProps.disabled
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onModalClose: () =>{
+ dispatch(actions.closeModal())
+ },
+ onOpenCalendarsEditModal: (vehicleJourneys) =>{
+ dispatch(actions.openPurchaseWindowsEditModal(vehicleJourneys))
+ },
+ onDeleteCalendarModal: (timetable) => {
+ dispatch(actions.deletePurchaseWindowsModal(timetable))
+ },
+ onShoppingWindowsEditVehicleJourney: (vehicleJourneys, timetables) =>{
+ dispatch(actions.editVehicleJourneyPurchaseWindows(vehicleJourneys, timetables))
+ },
+ onSelect2Timetable: (e) =>{
+ dispatch(actions.selectPurchaseWindowsModal(e.params.data))
+ dispatch(actions.addSelectedPurchaseWindow())
+ }
+ }
+}
+
+const PurchaseWindowsEditVehicleJourney = connect(mapStateToProps, mapDispatchToProps)(PurchaseWindowsEditVehicleJourneyComponent)
+
+export default PurchaseWindowsEditVehicleJourney
diff --git a/app/javascript/vehicle_journeys/containers/tools/VehicleJourneyInfoButton.js b/app/javascript/vehicle_journeys/containers/tools/VehicleJourneyInfoButton.js
new file mode 100644
index 000000000..19010c312
--- /dev/null
+++ b/app/javascript/vehicle_journeys/containers/tools/VehicleJourneyInfoButton.js
@@ -0,0 +1,20 @@
+import actions from '../../actions'
+import { connect } from 'react-redux'
+import VehicleJourneyInfoButtonComponent from '../../components/tools/VehicleJourneyInfoButton'
+
+const mapStateToProps = (state, ownProps) => {
+ return {
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onOpenEditModal: (vj) =>{
+ dispatch(actions.openInfoModal(vj))
+ },
+ }
+}
+
+const VehicleJourneyInfoButton = connect(mapStateToProps, mapDispatchToProps)(VehicleJourneyInfoButtonComponent)
+
+export default VehicleJourneyInfoButton
diff --git a/app/javascript/vehicle_journeys/reducers/custom_fields.js b/app/javascript/vehicle_journeys/reducers/custom_fields.js
new file mode 100644
index 000000000..482fd91cb
--- /dev/null
+++ b/app/javascript/vehicle_journeys/reducers/custom_fields.js
@@ -0,0 +1,6 @@
+export default function custom_fields(state = [], action) {
+ switch (action.type) {
+ default:
+ return state
+ }
+}
diff --git a/app/javascript/vehicle_journeys/reducers/index.js b/app/javascript/vehicle_journeys/reducers/index.js
index bb24aa185..95ac9c7e1 100644
--- a/app/javascript/vehicle_journeys/reducers/index.js
+++ b/app/javascript/vehicle_journeys/reducers/index.js
@@ -1,20 +1,27 @@
import { combineReducers } from 'redux'
import vehicleJourneys from './vehicleJourneys'
+import returnVehicleJourneys from './returnVehicleJourneys'
import pagination from './pagination'
import modal from './modal'
import status from './status'
import filters from './filters'
import editMode from './editMode'
import stopPointsList from './stopPointsList'
+import missions from './missions'
+import custom_fields from './custom_fields'
const vehicleJourneysApp = combineReducers({
vehicleJourneys,
+ returnVehicleJourneys,
pagination,
modal,
status,
filters,
editMode,
- stopPointsList
+ stopPointsList,
+ returnStopPointsList: stopPointsList,
+ missions,
+ custom_fields
})
export default vehicleJourneysApp
diff --git a/app/javascript/vehicle_journeys/reducers/missions.js b/app/javascript/vehicle_journeys/reducers/missions.js
new file mode 100644
index 000000000..7c1a355c7
--- /dev/null
+++ b/app/javascript/vehicle_journeys/reducers/missions.js
@@ -0,0 +1,6 @@
+export default function missions(state = [], action) {
+ switch (action.type) {
+ default:
+ return state
+ }
+}
diff --git a/app/javascript/vehicle_journeys/reducers/modal.js b/app/javascript/vehicle_journeys/reducers/modal.js
index 57f54a144..bcfc6ea0b 100644
--- a/app/javascript/vehicle_journeys/reducers/modal.js
+++ b/app/javascript/vehicle_journeys/reducers/modal.js
@@ -1,6 +1,6 @@
import _ from 'lodash'
-let vehicleJourneysModal, newModalProps
+let vehicleJourneysModal, newModalProps, vehicleJourney
export default function modal(state = {}, action) {
switch (action.type) {
@@ -37,10 +37,18 @@ export default function modal(state = {}, action) {
},
confirmModal: {}
}
+ case 'INFO_VEHICLEJOURNEY_MODAL':
+ return {
+ type: 'edit',
+ modalProps: {
+ vehicleJourney: action.vehicleJourney,
+ info: true
+ },
+ confirmModal: {}
+ }
case 'EDIT_CALENDARS_VEHICLEJOURNEY_MODAL':
vehicleJourneysModal = JSON.parse(JSON.stringify(action.vehicleJourneys))
let uniqTimetables = []
- let timetable = {}
vehicleJourneysModal.map((vj, i) => {
vj.time_tables.map((tt, j) =>{
if(!(_.find(uniqTimetables, tt))){
@@ -56,15 +64,38 @@ export default function modal(state = {}, action) {
},
confirmModal: {}
}
+ case 'EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL':
+ var vehicleJourneys = JSON.parse(JSON.stringify(action.vehicleJourneys))
+ let uniqPurchaseWindows = []
+ vehicleJourneys.map((vj, i) => {
+ vj.purchase_windows.map((pw, j) =>{
+ if(!(_.find(uniqPurchaseWindows, pw))){
+ uniqPurchaseWindows.push(pw)
+ }
+ })
+ })
+ return {
+ type: 'purchase_windows_edit',
+ modalProps: {
+ vehicleJourneys: vehicleJourneys,
+ purchase_windows: uniqPurchaseWindows
+ },
+ confirmModal: {}
+ }
case 'SELECT_CP_EDIT_MODAL':
- newModalProps = _.assign({}, state.modalProps, {selectedCompany : action.selectedItem})
+ vehicleJourney = _.assign({}, state.modalProps.vehicleJourney, {company: action.selectedItem})
+ newModalProps = _.assign({}, state.modalProps, {vehicleJourney})
return _.assign({}, state, {modalProps: newModalProps})
case 'UNSELECT_CP_EDIT_MODAL':
- newModalProps = _.assign({}, state.modalProps, {selectedCompany : undefined})
+ vehicleJourney = _.assign({}, state.modalProps.vehicleJourney, {company: undefined})
+ newModalProps = _.assign({}, state.modalProps, {vehicleJourney})
return _.assign({}, state, {modalProps: newModalProps})
case 'SELECT_TT_CALENDAR_MODAL':
newModalProps = _.assign({}, state.modalProps, {selectedTimetable : action.selectedItem})
return _.assign({}, state, {modalProps: newModalProps})
+ case 'SELECT_PURCHASE_WINDOW_MODAL':
+ newModalProps = _.assign({}, state.modalProps, {selectedPurchaseWindow : action.selectedItem})
+ return _.assign({}, state, {modalProps: newModalProps})
case 'ADD_SELECTED_TIMETABLE':
if(state.modalProps.selectedTimetable){
newModalProps = JSON.parse(JSON.stringify(state.modalProps))
@@ -73,6 +104,14 @@ export default function modal(state = {}, action) {
}
return _.assign({}, state, {modalProps: newModalProps})
}
+ case 'ADD_SELECTED_PURCHASE_WINDOW':
+ if(state.modalProps.selectedPurchaseWindow){
+ newModalProps = JSON.parse(JSON.stringify(state.modalProps))
+ if (!_.find(newModalProps.purchase_windows, newModalProps.selectedPurchaseWindow)){
+ newModalProps.purchase_windows.push(newModalProps.selectedPurchaseWindow)
+ }
+ return _.assign({}, state, {modalProps: newModalProps})
+ }
case 'DELETE_CALENDAR_MODAL':
newModalProps = JSON.parse(JSON.stringify(state.modalProps))
let timetablesModal = state.modalProps.timetables.slice(0)
@@ -92,19 +131,32 @@ export default function modal(state = {}, action) {
newModalProps.vehicleJourneys = vehicleJourneysModal
newModalProps.timetables = timetablesModal
return _.assign({}, state, {modalProps: newModalProps})
+ case 'DELETE_PURCHASE_WINDOW_MODAL':
+ newModalProps = JSON.parse(JSON.stringify(state.modalProps))
+ let purchase_windows = state.modalProps.purchase_windows.slice(0)
+ purchase_windows.map((tt, i) =>{
+ if(tt == action.purchaseWindow){
+ purchase_windows.splice(i, 1)
+ }
+ })
+ vehicleJourneysModal = state.modalProps.vehicleJourneys.slice(0)
+ vehicleJourneysModal.map((vj) =>{
+ vj.purchase_windows.map((tt, i) =>{
+ if (_.isEqual(tt, action.purchaseWindow)){
+ vj.purchase_windows.splice(i, 1)
+ }
+ })
+ })
+ newModalProps.vehicleJourneys = vehicleJourneysModal
+ newModalProps.purchase_windows = purchase_windows
+ return _.assign({}, state, {modalProps: newModalProps})
case 'CREATE_VEHICLEJOURNEY_MODAL':
let selectedJP = {}
if (window.jpOrigin){
let stopAreas = _.map(window.jpOriginStopPoints, (sa, i) =>{
return _.assign({}, {stop_area_short_description : {id : sa.stop_area_id}})
})
- selectedJP = {
- id: window.jpOrigin.id,
- name: window.jpOrigin.name,
- published_name: window.jpOrigin.published_name,
- objectid: window.jpOrigin.objectid,
- stop_areas: stopAreas
- }
+ selectedJP = _.assign({}, window.jpOrigin, {stop_areas: stopAreas})
}
return {
type: 'create',
@@ -135,4 +187,4 @@ export default function modal(state = {}, action) {
default:
return state
}
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/reducers/returnVehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/returnVehicleJourneys.js
new file mode 100644
index 000000000..db3c71d17
--- /dev/null
+++ b/app/javascript/vehicle_journeys/reducers/returnVehicleJourneys.js
@@ -0,0 +1,11 @@
+import _ from 'lodash'
+import actions from '../actions'
+
+export default function returnVehicleJourneys(state = [], action) {
+ switch (action.type) {
+ case 'RECEIVE_RETURN_VEHICLE_JOURNEYS':
+ return [...action.json]
+ default:
+ return state
+ }
+}
diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
index 136e1b41a..1a15ec46d 100644
--- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
@@ -9,29 +9,68 @@ const vehicleJourney= (state = {}, action, keep) => {
return _.assign({}, state, {selected: false})
case 'ADD_VEHICLEJOURNEY':
let pristineVjasList = []
+ let prevSp = action.stopPointsList[0]
+ let current_time = {
+ hour: 0,
+ minute: 0
+ }
+ if(action.data["start_time.hour"] && action.data["start_time.minute"] && action.selectedJourneyPattern.full_schedule){
+ current_time.hour = parseInt(action.data["start_time.hour"].value)
+ current_time.minute = parseInt(action.data["start_time.minute"].value) || 0
+ }
_.each(action.stopPointsList, (sp) =>{
+ if(action.selectedJourneyPattern.full_schedule && action.selectedJourneyPattern.costs && action.selectedJourneyPattern.costs[prevSp.stop_area_id + "-" + sp.stop_area_id]){
+ let delta = parseInt(action.selectedJourneyPattern.costs[prevSp.stop_area_id + "-" + sp.stop_area_id].time)
+ let delta_hour = parseInt(delta/60)
+ let delta_minute = delta - 60*delta_hour
+ current_time.hour += delta_hour
+ current_time.minute += delta_minute
+ let extra_hours = parseInt(current_time.minute/60)
+ current_time.hour += extra_hours
+ current_time.minute -= extra_hours*60
+ current_time.hour = current_time.hour % 24
+ prevSp = sp
+ }
+ let offsetHours = sp.time_zone_offset / 3600
+ let offsetminutes = sp.time_zone_offset/60 - 60*offsetHours
let newVjas = {
delta: 0,
departure_time:{
- hour: '00',
- minute: '00'
+ hour: (24 + current_time.hour + offsetHours) % 24,
+ minute: current_time.minute + offsetminutes
},
arrival_time:{
- hour: '00',
- minute: '00'
+ hour: (24 + current_time.hour + offsetHours) % 24,
+ minute: current_time.minute + offsetminutes
},
stop_point_objectid: sp.object_id,
stop_area_cityname: sp.city_name,
dummy: true
}
+ if(current_time.hour + offsetHours > 24){
+ newVjas.departure_day_offset = 1
+ newVjas.arrival_day_offset = 1
+ }
+ if(current_time.hour + offsetHours < 0){
+ newVjas.departure_day_offset = -1
+ newVjas.arrival_day_offset = -1
+ }
+
_.each(action.selectedJourneyPattern.stop_areas, (jp) =>{
if (jp.stop_area_short_description.id == sp.id){
newVjas.dummy = false
return
}
})
+
+ if(newVjas.dummy){
+ newVjas.departure_time = {hour: "00", minute: "00"}
+ newVjas.arrival_time = {hour: "00", minute: "00"}
+ }
pristineVjasList.push(newVjas)
+
})
+
return {
company: action.selectedCompany,
journey_pattern: action.selectedJourneyPattern,
@@ -41,11 +80,13 @@ const vehicleJourney= (state = {}, action, keep) => {
short_id: '',
footnotes: [],
time_tables: [],
+ purchase_windows: [],
vehicle_journey_at_stops: pristineVjasList,
selected: false,
deletable: false,
transport_mode: window.transportMode ? window.transportMode : 'undefined',
- transport_submode: window.transportSubmode ? window.transportSubmode : 'undefined'
+ transport_submode: window.transportSubmode ? window.transportSubmode : 'undefined',
+ custom_fields: action.data.custom_fields
}
case 'DUPLICATE_VEHICLEJOURNEY':
case 'SHIFT_VEHICLEJOURNEY':
@@ -79,18 +120,12 @@ const vehicleJourney= (state = {}, action, keep) => {
if (action.isDeparture){
newSchedule.departure_time[action.timeUnit] = actions.pad(action.val, action.timeUnit)
if(!action.isArrivalsToggled)
- newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val, action.timeUnit)
- newSchedule = actions.getDelta(newSchedule)
- if(newSchedule.delta < 0){
- return vjas
- }
+ newSchedule.arrival_time[action.timeUnit] = newSchedule.departure_time[action.timeUnit]
+ newSchedule = actions.adjustSchedule(action, newSchedule)
return _.assign({}, state.vehicle_journey_at_stops[action.subIndex], {arrival_time: newSchedule.arrival_time, departure_time: newSchedule.departure_time, delta: newSchedule.delta})
}else{
newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val, action.timeUnit)
- newSchedule = actions.getDelta(newSchedule)
- if(newSchedule.delta < 0){
- return vjas
- }
+ newSchedule = actions.adjustSchedule(action, newSchedule)
return _.assign({}, state.vehicle_journey_at_stops[action.subIndex], {arrival_time: newSchedule.arrival_time, departure_time: newSchedule.departure_time, delta: newSchedule.delta})
}
}else{
@@ -131,6 +166,7 @@ export default function vehicleJourneys(state = [], action) {
company: action.selectedCompany,
published_journey_name: action.data.published_journey_name.value,
published_journey_identifier: action.data.published_journey_identifier.value,
+ custom_fields: action.data.custom_fields,
})
}else{
return vj
@@ -161,6 +197,21 @@ export default function vehicleJourneys(state = [], action) {
return vj
}
})
+ case 'EDIT_VEHICLEJOURNEYS_PURCHASE_WINDOWS':
+ let newWindows = JSON.parse(JSON.stringify(action.purchase_windows))
+ return state.map((vj,i) =>{
+ if(vj.selected){
+ let updatedVJ = _.assign({}, vj)
+ action.vehicleJourneys.map((vjm, j) =>{
+ if(vj.objectid == vjm.objectid){
+ updatedVJ.purchase_windows = newWindows
+ }
+ })
+ return updatedVJ
+ }else{
+ return vj
+ }
+ })
case 'SHIFT_VEHICLEJOURNEY':
return state.map((vj, i) => {
if (vj.selected){
@@ -222,7 +273,9 @@ export default function vehicleJourneys(state = [], action) {
return vj
}
})
+ case 'DID_VALIDATE_VEHICLE_JOURNEYS':
+ return [...action.vehicleJourneys]
default:
return state
}
-} \ No newline at end of file
+}