diff options
Diffstat (limited to 'app/javascript')
24 files changed, 501 insertions, 123 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/packs/vehicle_journeys/index.js b/app/javascript/packs/vehicle_journeys/index.js index 38431af1d..53c5d5417 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,7 +55,7 @@ var initialState = {    },    status: { -    fetchSuccess: true, +    fetchSuccess: false,      isFetching: false    },    vehicleJourneys: [], @@ -99,4 +100,4 @@ render(      <App />    </Provider>,    document.getElementById('vehicle_journeys_wip') -)
\ No newline at end of file +) diff --git a/app/javascript/routes/components/BSelect2.js b/app/javascript/routes/components/BSelect2.js index 340d9df95..0d8d7787f 100644 --- a/app/javascript/routes/components/BSelect2.js +++ b/app/javascript/routes/components/BSelect2.js @@ -96,17 +96,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/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/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js index ddb54d615..40c8006f1 100644 --- a/app/javascript/vehicle_journeys/actions/index.js +++ b/app/javascript/vehicle_journeys/actions/index.js @@ -84,7 +84,8 @@ const actions = {      selectedItem:{        id: selectedTT.id,        comment: selectedTT.comment, -      objectid: selectedTT.objectid +      objectid: selectedTT.objectid, +      color: selectedTT.color      }    }),    addSelectedTimetable: () => ({ @@ -99,6 +100,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'    }), @@ -163,25 +189,17 @@ const actions = {      $(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) +    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', @@ -313,6 +331,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,26 +341,35 @@ 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)) @@ -439,6 +467,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))) @@ -457,10 +499,6 @@ const actions = {          minute: actions.simplePad(newArrivalDT.getUTCMinutes())        }      } -  }, -  escapeWildcardCharacters(search) { -    let newSearch = search.replace(/^_/, "\\_") -    return newSearch.replace(/^%/, "\\%")    }  } diff --git a/app/javascript/vehicle_journeys/components/Filters.js b/app/javascript/vehicle_journeys/components/Filters.js index db6707520..3bc4f7ff7 100644 --- a/app/javascript/vehicle_journeys/components/Filters.js +++ b/app/javascript/vehicle_journeys/components/Filters.js @@ -33,6 +33,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}                  /> @@ -165,4 +166,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/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js index e8c27f92e..8bab5baa9 100644 --- a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js @@ -14,16 +14,27 @@ export default class SaveVehicleJourneys extends Component{          <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> +              <div className="btn-group sticky-actions"> +                <button +                  className={'btn ' + (this.props.editMode ? 'btn-success' : 'btn-default') + (this.props.status.fetchSuccess ? '' : ' disabled')} +                  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> +                {this.props.editMode && <button +                    className='btn btn-default' +                    type='button' +                    onClick={e => { +                      e.preventDefault() +                      this.props.onExitEditMode() +                    }} +                  > Annuler </button> +                } +              </div>              </form>            </div>          </div> @@ -38,5 +49,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/Tools.js b/app/javascript/vehicle_journeys/components/Tools.js index 7621dfc10..d6e04f00e 100644 --- a/app/javascript/vehicle_journeys/components/Tools.js +++ b/app/javascript/vehicle_journeys/components/Tools.js @@ -7,6 +7,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 +18,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,13 +31,16 @@ 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> @@ -45,4 +54,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 8fb4b8a7e..5f6281487 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js @@ -17,12 +17,25 @@ export default class VehicleJourney extends Component {      return bool    } +  hasFeature(key) { +    return this.props.filters.features[key] +  } +    timeTableURL(tt) {      let refURL = window.location.pathname.split('/', 3).join('/')      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='Voir le calendrier'><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='Voir le calendrier commercial'><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '')}}></span></a>      )    } @@ -44,19 +57,33 @@ 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='strong mb-xs'>{this.props.value.objectid ? this.props.value.short_id : '-'}</div> -          <div>{this.props.value.journey_pattern.short_id}</div> +        <div +          className='th' +          onClick={(e) => +            ($(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 != "non renseigné" ? this.props.value.published_journey_name : '-'}</div> +          <div>{this.props.value.journey_pattern.short_id || '-'}</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> +          { 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> +          }            <div className={(this.props.value.deletable ? 'disabled ' : '') + 'checkbox'}>              <input                id={this.props.index} @@ -83,6 +110,7 @@ export default class VehicleJourney extends Component {                        className='form-control'                        disabled={this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}                        readOnly={!this.props.editMode && !vj.dummy} +                      disabled={!this.props.editMode && !vj.dummy}                        onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', false, false)}}                        value={vj.arrival_time['hour']}                        /> @@ -94,6 +122,7 @@ export default class VehicleJourney extends Component {                        className='form-control'                        disabled={this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}                        readOnly={!this.props.editMode && !vj.dummy} +                      disabled={!this.props.editMode && !vj.dummy}                        onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'minute', false, false)}}                        value={vj.arrival_time['minute']}                        /> @@ -114,6 +143,7 @@ export default class VehicleJourney extends Component {                        className='form-control'                        disabled={this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}                        readOnly={!this.props.editMode && !vj.dummy} +                      disabled={!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']}                        /> @@ -125,6 +155,7 @@ export default class VehicleJourney extends Component {                        className='form-control'                        disabled={this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false}                        readOnly={!this.props.editMode && !vj.dummy} +                      disabled={!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']}                        /> @@ -144,4 +175,4 @@ VehicleJourney.propTypes = {    index: PropTypes.number.isRequired,    onUpdateTime: PropTypes.func.isRequired,    onSelectVehicleJourney: PropTypes.func.isRequired -}
\ No newline at end of file +} diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js index 6bce9766b..dc480d6b4 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js @@ -12,6 +12,10 @@ export default class VehicleJourneys extends Component {      this.props.onLoadFirstPage(this.props.filters)    } +  hasFeature(key) { +    return this.props.filters.features[key] +  } +    componentDidUpdate(prevProps, prevState) {      if(this.props.status.isFetching == false){        $('.table-2entries').each(function() { @@ -111,8 +115,10 @@ export default class VehicleJourneys extends Component {                <div className='t2e-head w20'>                  <div className='th'>                    <div className='strong mb-xs'>ID course</div> +                  <div>Nom course</div>                    <div>ID mission</div>                    <div>Calendriers</div> +                  { this.hasFeature('purchase_windows') && <div>Calendriers Commerciaux</div> }                  </div>                  {this.props.stopPointsList.map((sp, i) =>{                    return ( @@ -132,6 +138,7 @@ export default class VehicleJourneys extends Component {                        index={index}                        editMode={this.props.editMode}                        filters={this.props.filters} +                      features={this.props.features}                        onUpdateTime={this.props.onUpdateTime}                        onSelectVehicleJourney={this.props.onSelectVehicleJourney}                        /> @@ -153,4 +160,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 2bffebdf6..cd593cdff 100644 --- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js +++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js @@ -9,7 +9,7 @@ export default class CreateModal extends Component {    }    handleSubmit() { -    if(actions.validateFields(this.refs) == true && this.props.modal.modalProps.selectedJPModal) { +    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.onModalClose()        $('#NewVehicleJourneyModal').modal('hide') @@ -61,7 +61,7 @@ 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)}                                />                              </div> @@ -130,4 +130,4 @@ CreateModal.propTypes = {    onAddVehicleJourney: PropTypes.func.isRequired,    onSelect2JourneyPattern: PropTypes.func.isRequired,    disabled: PropTypes.bool.isRequired -}
\ No newline at end of file +} diff --git a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js index 7d91896eb..f8d6add03 100644 --- a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js @@ -97,6 +97,7 @@ export default class EditVehicleJourney extends Component {                              <div className='form-group'>                                <label className='control-label'>Transporteur</label>                                <CompanySelect2 +                                editModal={this.props.modal.type == "edit"}                                  editMode={this.props.editMode}                                  company = {this.props.modal.modalProps.vehicleJourney.company}                                  onSelect2Company = {(e) => this.props.onSelect2Company(e)} 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..d61c7a34b --- /dev/null +++ b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js @@ -0,0 +1,152 @@ +import React, { PropTypes, Component } from 'react' +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">×</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/TimetablesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js index fef3cdcc9..fdaa5aeed 100644 --- a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js @@ -29,10 +29,11 @@ export default class TimetablesEditVehicleJourney extends Component {          <li className='st_action'>            <button              type='button' -            disabled={(actions.getSelected(this.props.vehicleJourneys).length != 1 || this.props.disabled)} +            disabled={(actions.getSelected(this.props.vehicleJourneys).length < 1 || this.props.disabled)}              data-toggle='modal'              data-target='#CalendarsEditVehicleJourneyModal'              onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))} +            title='Calendriers'            >              <span className='fa fa-calendar'></span>            </button> @@ -56,7 +57,7 @@ export default class TimetablesEditVehicleJourney extends Component {                                  <div className='wrapper'>                                    <div>                                      <div className='form-group'> -                                      <label className='control-label'>Calendriers associés</label> +                                      <label className='control-label'>{this.props.modal.modalProps.timetables.length == 0 ? "Aucun calendrier associé" : "Calendriers associés"}</label>                                      </div>                                    </div>                                    <div></div> @@ -65,9 +66,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 +91,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 +110,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 +151,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/select2s/CompanySelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js index 0697e9141..79ba8f094 100644 --- a/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js +++ b/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js @@ -21,7 +21,7 @@ export default class BSelect4 extends Component {          value={(this.props.company) ? this.props.company.name : undefined}          onSelect={(e) => this.props.onSelect2Company(e) }          onUnselect={() => this.props.onUnselect2Company()} -        disabled={!this.props.editMode} +        disabled={!this.props.editMode && this.props.editModal}          multiple={false}          ref='company_id'          options={{ @@ -36,7 +36,7 @@ export default class BSelect4 extends Component {              delay: '500',              data: function(params) {                return { -                q: { name_cont: actions.escapeWildcardCharacters(params.term)}, +                q: { name_cont: params.term},                };              },              processResults: function(data, params) { diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js index 5b4ae564c..fa847886c 100644 --- a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js +++ b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js @@ -21,6 +21,8 @@ export default class BSelect4 extends Component {          onSelect={(e) => this.props.onSelect2JourneyPattern(e)}          multiple={false}          ref='journey_pattern_id' +        className={!this.props.isFilter ? "vjCreateSelectJP" : null} +        required={!this.props.isFilter}          options={{            allowClear: false,            theme: 'bootstrap', @@ -33,7 +35,7 @@ export default class BSelect4 extends Component {              delay: '500',              data: function(params) {                return { -                q: { published_name_or_objectid_or_registration_number_cont: actions.escapeWildcardCharacters(params.term)}, +                q: { published_name_or_objectid_or_registration_number_cont: params.term},                };              },              processResults: function(data, params) { diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js index a90a9f7b8..eb8651be2 100644 --- a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js +++ b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js @@ -31,12 +31,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: actions.escapeWildcardCharacters(params.term) -                } -              }; +            data: (params) => { +              let q = {} +              q[this.props.searchKey] = params.term +              return {q}              },              processResults: function(data, params) {                return { @@ -44,7 +42,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 +60,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 37628fce0..b063abeca 100644 --- a/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js +++ b/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js @@ -33,7 +33,7 @@ export default class BSelect4b extends Component {              delay: '500',              data: function(params) {                return { -                q: { objectid_cont: actions.escapeWildcardCharacters(params.term)}, +                q: { objectid_cont: params.term},                };              },              processResults: function(data, params) { diff --git a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js index 18f9e994e..f5f879ed8 100644 --- a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js @@ -17,6 +17,10 @@ const mapDispatchToProps = (dispatch) => {      onEnterEditMode: () => {        dispatch(actions.enterEditMode())      }, +    onExitEditMode: () => { +      dispatch(actions.cancelSelection()) +      dispatch(actions.exitEditMode()) +    },      onSubmitVehicleJourneys: (next, state) => {        actions.submitVehicleJourneys(dispatch, state, next)      } 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/reducers/modal.js b/app/javascript/vehicle_journeys/reducers/modal.js index 57f54a144..eae3314e8 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) { @@ -40,7 +40,6 @@ export default function modal(state = {}, action) {      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 +55,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 +95,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,6 +122,25 @@ 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){ @@ -135,4 +184,4 @@ export default function modal(state = {}, action) {      default:        return state    } -}
\ No newline at end of file +} diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js index 775fefdca..d057bf704 100644 --- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js +++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js @@ -38,8 +38,10 @@ const vehicleJourney= (state = {}, action, keep) => {          published_journey_name: action.data.published_journey_name.value,          published_journey_identifier: action.data.published_journey_identifier.value,          objectid: '', +        short_id: '',          footnotes: [],          time_tables: [], +        purchase_windows: [],          vehicle_journey_at_stops: pristineVjasList,          selected: false,          deletable: false, @@ -78,18 +80,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{ @@ -160,6 +156,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){ @@ -224,4 +235,4 @@ export default function vehicleJourneys(state = [], action) {      default:        return state    } -}
\ No newline at end of file +} | 
