diff options
Diffstat (limited to 'app')
12 files changed, 262 insertions, 38 deletions
diff --git a/app/assets/stylesheets/base/_config.sass b/app/assets/stylesheets/base/_config.sass index ec1c43e7f..2c226357f 100644 --- a/app/assets/stylesheets/base/_config.sass +++ b/app/assets/stylesheets/base/_config.sass @@ -16,7 +16,7 @@ $blue: #007fbb  $darkgrey: #4b4b4b  $grey: #a4a4a4 -$lightgrey: rgba($grey, 0.15) +$lightgrey: lighten($grey, 25)  $green: #70b12b  $red: #da2f36 diff --git a/app/assets/stylesheets/components/_forms.sass b/app/assets/stylesheets/components/_forms.sass index 47faf19b1..5143d2ba4 100644 --- a/app/assets/stylesheets/components/_forms.sass +++ b/app/assets/stylesheets/components/_forms.sass @@ -284,6 +284,7 @@ table, .table    height: $cbx-size    width: $cbx-size    margin: 0 auto +  transition: transform 0.2s, background-color 0.2s    > input[type='checkbox']      &:not(:checked), &:checked diff --git a/app/assets/stylesheets/modules/_jp_collection.sass b/app/assets/stylesheets/modules/_jp_collection.sass index f579cf87b..22edb9599 100644 --- a/app/assets/stylesheets/modules/_jp_collection.sass +++ b/app/assets/stylesheets/modules/_jp_collection.sass @@ -103,6 +103,7 @@    .table-2entries .t2e-item-list      .t2e-item        position: relative +      overflow: hidden        .th .vj_tt          display: inline-block @@ -111,6 +112,116 @@          + .vj_tt            margin-left: 5px +      &.with-costs + +        & > div +          position: relative + +        .has_radio +          margin-right: 150px + +        .costs +          background: $lightgrey +          padding: 5px +          color: white +          position: absolute +          left: 80px +          top: -1px +          transform: translateY(-50%) +          font-size: 0.75em +          transition: background 0.1s +          border: 1px solid white + +          &:hover +            background: $blue +            &:after +              background: $blue +          &:after +            content: "" +            height: 2px +            position: absolute +            left: -30px +            background: $lightgrey +            right: 100% +            top: 50% +            transition: background 0.1s + +          p +            display: block +            border: none +            margin-bottom: 0 +            i +              margin-right: 3px +              width: 12px +            & + p +              position: relative +              z-index: 2 +              padding-right: 0 +              margin: 0 +              border-right: none + +            input +              display: inline-block +              width: 40px +              border: none +              margin-right: 5px +              color: black + +      .edit-mode .costs +        p +          margin-bottom: 5px +          & + p +            margin-bottom: 0 + +        background: $blue +        &:after +          background: $blue + + +      .with-headline + .costs +        top: 25% + +      .deactivated .costs +        display: none + +      $link-size: 10px +      .link +        position: absolute +        left: 40px +        width: 10px +        top: -7px +        bottom: -7px +        background: $blue +        z-index: 3 +        &:after +          content: "" +          width: $link-size +          height: $link-size +          position: absolute +          top: 50% +          bottom: 50% +          margin-top: -$link-size/2 - 3px +          border-top: $link-size/2 solid transparent +          border-left: $link-size/2 solid transparent +          border-right: $link-size/2 solid $blue +          border-bottom: $link-size/2 solid $blue +          transform: rotate(135deg) +          left: 0% +          opacity: 0 +          transition: left 0.2s, opacity 0.2s + +      .activated .link +        &:after +          left: -50% +          opacity: 1 + +      .headlined +        .link +          top: 0 +          &:after +            top: 75% +            margin-top: -$link-size/2 - 1px +        &.has-error          &:before            content: '' diff --git a/app/controllers/journey_patterns_collections_controller.rb b/app/controllers/journey_patterns_collections_controller.rb index 5fe78766c..6b661da0c 100644 --- a/app/controllers/journey_patterns_collections_controller.rb +++ b/app/controllers/journey_patterns_collections_controller.rb @@ -17,35 +17,45 @@ class JourneyPatternsCollectionsController < ChouetteController    alias_method :vehicle_journey, :resource    def show -    @q = route.journey_patterns.search(params[:q]).result(distinct: true).includes(:stop_points) +    @q = route.journey_patterns +    if params[:q].present? +      ids = @q.search(params[:q]).result(distinct: true).pluck(:id) +      @q = @q.where(id: ids) +    end +    @q = @q.includes(:stop_points) +    # @q = route.journey_patterns.search(params[:q]).result().includes(:stop_points)      @ppage = 10      @journey_patterns ||= @q.paginate(page: params[:page], per_page: @ppage).order(:name) - -    @stop_points_list = [] -    route.stop_points.each do |sp| -      @stop_points_list << { -        :id => sp.stop_area.id, -        :route_id => sp.try(:route_id), -        :object_id => sp.try(:objectid), -        :position => sp.try(:position), -        :for_boarding => sp.try(:for_boarding), -        :for_alighting => sp.try(:for_alighting), -        :name => sp.stop_area.try(:name), -        :zip_code => sp.stop_area.try(:zip_code), -        :city_name => sp.stop_area.try(:city_name), -        :comment => sp.stop_area.try(:comment), -        :area_type => sp.stop_area.try(:area_type), -        :registration_number => sp.stop_area.try(:registration_number), -        :nearest_topic_name => sp.stop_area.try(:nearest_topic_name), -        :fare_code => sp.stop_area.try(:fare_code), -        :longitude => sp.stop_area.try(:longitude), -        :latitude => sp.stop_area.try(:latitude), -        :long_lat_type => sp.stop_area.try(:long_lat_type), -        :country_code => sp.stop_area.try(:country_code), -        :street_name => sp.stop_area.try(:street_name) -      } +    respond_to do |format| +      format.json +      format.html do +        @stop_points_list = [] +        route.stop_points.each do |sp| +          @stop_points_list << { +            :id => sp.stop_area.id, +            :route_id => sp.try(:route_id), +            :object_id => sp.try(:objectid), +            :position => sp.try(:position), +            :for_boarding => sp.try(:for_boarding), +            :for_alighting => sp.try(:for_alighting), +            :name => sp.stop_area.try(:name), +            :zip_code => sp.stop_area.try(:zip_code), +            :city_name => sp.stop_area.try(:city_name), +            :comment => sp.stop_area.try(:comment), +            :area_type => sp.stop_area.try(:area_type), +            :registration_number => sp.stop_area.try(:registration_number), +            :nearest_topic_name => sp.stop_area.try(:nearest_topic_name), +            :fare_code => sp.stop_area.try(:fare_code), +            :longitude => sp.stop_area.try(:longitude), +            :latitude => sp.stop_area.try(:latitude), +            :long_lat_type => sp.stop_area.try(:long_lat_type), +            :country_code => sp.stop_area.try(:country_code), +            :street_name => sp.stop_area.try(:street_name) +          } +        end +        @stop_points_list = @stop_points_list.sort_by {|a| a[:position] } +      end      end -    @stop_points_list = @stop_points_list.sort_by {|a| a[:position] }    end    def user_permissions diff --git a/app/javascript/journey_patterns/actions/index.js b/app/javascript/journey_patterns/actions/index.js index 1c2eb68b2..09e2001c1 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,6 +199,7 @@ const actions = {                    }                  })                } +<<<<<<< HEAD                journeyPatterns.push({                  name: val.name,                  object_id: val.object_id, @@ -204,6 +210,14 @@ const actions = {                  stop_points: val.route_short_description.stop_points,                  deletable: false                }) +======= +              journeyPatterns.push( +                _.assign({}, val, { +                  stop_points: val.route_short_description.stop_points, +                  deletable: false +                }) +              ) +>>>>>>> Refs #5455 @6h; Add time and distance between stops in Journey Patterns              }            }            window.currentItemsLength = journeyPatterns.length diff --git a/app/javascript/journey_patterns/components/JourneyPattern.js b/app/javascript/journey_patterns/components/JourneyPattern.js index d4c9816ec..40a6899e2 100644 --- a/app/javascript/journey_patterns/components/JourneyPattern.js +++ b/app/javascript/journey_patterns/components/JourneyPattern.js @@ -5,6 +5,17 @@ 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]: parseInt(e.target.value) +      } +    } +    this.props.onUpdateJourneyPatternCosts(costs)    }    vehicleJourneyURL(jpOid) { @@ -16,16 +27,26 @@ export default class JourneyPattern extends Component{      )    } +  hasFeature(key) { +    return this.props.status.features[key] +  } +    cityNameChecker(sp) {      let bool = false +      if(sp.city_name != this.previousCity){        bool = true        this.previousCity = sp.city_name      } +    return bool +  } + +  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)} @@ -61,9 +82,9 @@ export default class JourneyPattern extends Component{    render() {      this.previousCity = undefined - +    this.previousSpId = undefined      return ( -      <div className={'t2e-item' + (this.props.value.deletable ? ' disabled' : '') + (this.props.value.object_id ? '' : ' to_record') + (this.props.value.errors ? ' has-error': '')}> +      <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' : '')}>          {/* Errors */}          {/* this.props.value.errors ? this.getErrors(this.props.value.errors) : '' */} @@ -112,9 +133,49 @@ 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 = this.previousSpId + "-" + stopPoint.id +              costs = this.props.value.costs[costsKey] || {distance: 0, time: 0} +              time = costs['time'] || 0 +              distance = costs['distance'] || 0 +              if(time < 60){ +                time_in_words = time + " min" +              } +              else{ +                let hours = parseInt(time/60) +                time_in_words = hours + " h " + (time - 60*hours) + " min" +              } +            } +            if(stopPoint.checked){ +              this.previousSpId = stopPoint.id +            } +            let headlined = this.cityNameChecker(stopPoint)              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" 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>{(costs['distance'] || 0) + " km"}</p> +                    <p><i className="fa fa-clock-o"></i>{time_in_words}</p> +                  </div>} +                </div>}                </div>              )            })} @@ -129,4 +190,4 @@ JourneyPattern.propTypes = {    onCheckboxChange: PropTypes.func.isRequired,    onOpenEditModal: PropTypes.func.isRequired,    onDeleteJourneyPattern: PropTypes.func.isRequired -}
\ No newline at end of file +} diff --git a/app/javascript/journey_patterns/components/JourneyPatterns.js b/app/javascript/journey_patterns/components/JourneyPatterns.js index 4b2badabb..69024050f 100644 --- a/app/javascript/journey_patterns/components/JourneyPatterns.js +++ b/app/javascript/journey_patterns/components/JourneyPatterns.js @@ -131,6 +131,7 @@ 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}                        /> @@ -152,4 +153,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/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/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/models/chouette/journey_pattern.rb b/app/models/chouette/journey_pattern.rb index 366fde188..1ddf7c9fb 100644 --- a/app/models/chouette/journey_pattern.rb +++ b/app/models/chouette/journey_pattern.rb @@ -58,14 +58,14 @@ module Chouette        {          name: item['name'],          published_name: item['published_name'], -        registration_number: item['registration_number'] +        registration_number: item['registration_number'], +        costs: item['costs']        }      end      def self.state_create_instance route, item        # Flag new record, so we can unset object_id if transaction rollback        jp = route.journey_patterns.create(state_permited_attributes(item)) -        # FIXME        # DefaultAttributesSupport will trigger some weird validation on after save        # wich will call to valid?, wich will populate errors @@ -146,5 +146,9 @@ module Chouette          vjas.destroy        end      end + +    def costs +      read_attribute(:costs) || {} +    end    end  end diff --git a/app/views/api/v1/journey_patterns/show.rabl b/app/views/api/v1/journey_patterns/show.rabl index 86876f3fb..67d483147 100644 --- a/app/views/api/v1/journey_patterns/show.rabl +++ b/app/views/api/v1/journey_patterns/show.rabl @@ -5,6 +5,10 @@ extends "api/v1/trident_objects/show"    attributes attr, :unless => lambda { |m| m.send( attr).nil?}  end +if has_feature? :costs_in_journey_patterns +  attribute :costs +end +  node(:route_short_description) do |journey_pattern|    partial("api/v1/routes/short_description", :object => journey_pattern.route)  end  | 
