diff options
| author | Alban Peignier | 2018-05-10 22:17:03 +0200 | 
|---|---|---|
| committer | GitHub | 2018-05-10 22:17:03 +0200 | 
| commit | 764aa8a93bd3e25a83b3db70892ca06304edaa9c (patch) | |
| tree | b681730cec81ee6b721e8148f3fbcab691c3689b /app | |
| parent | 093599f1c2e75ba2a4e3e9e8a6aa2cf665919886 (diff) | |
| parent | 3364755e26c5a4a54a6de6080bf1177ee03c7183 (diff) | |
| download | chouette-core-764aa8a93bd3e25a83b3db70892ca06304edaa9c.tar.bz2 | |
Merge pull request #555 from af83/6923-consolidated-offer
Display consolidated offer. Fixes #6923 
Diffstat (limited to 'app')
| -rw-r--r-- | app/assets/stylesheets/components/_forms.sass | 8 | ||||
| -rw-r--r-- | app/assets/stylesheets/modules/_vj_collection.sass | 88 | ||||
| -rw-r--r-- | app/controllers/referential_vehicle_journeys_controller.rb | 4 | ||||
| -rw-r--r-- | app/helpers/vehicle_journeys_helper.rb | 12 | ||||
| -rw-r--r-- | app/models/chouette/route.rb | 3 | ||||
| -rw-r--r-- | app/services/referential_consolidated.rb | 124 | ||||
| -rw-r--r-- | app/views/referential_vehicle_journeys/_consolidated.html.slim | 33 | ||||
| -rw-r--r-- | app/views/referential_vehicle_journeys/_consolidated_line.html.slim | 119 | ||||
| -rw-r--r-- | app/views/referential_vehicle_journeys/_filters.html.slim | 14 | ||||
| -rw-r--r-- | app/views/referential_vehicle_journeys/_list.html.slim | 49 | ||||
| -rw-r--r-- | app/views/referential_vehicle_journeys/index.html.slim | 52 | 
11 files changed, 451 insertions, 55 deletions
| diff --git a/app/assets/stylesheets/components/_forms.sass b/app/assets/stylesheets/components/_forms.sass index b13c5fc23..e7aa31fab 100644 --- a/app/assets/stylesheets/components/_forms.sass +++ b/app/assets/stylesheets/components/_forms.sass @@ -507,10 +507,10 @@ table, .table      right: 15px      top: 50%      padding: 0 -    margin-top: -13px      z-index: 1 +    transform: translateY(-50%) -    .btn +    *:not(.btn-group) > .btn        color: $blue        font-weight: 700        background-color: transparent @@ -718,6 +718,10 @@ table, .table      > .form-group:last-child        border-right: none +    @for $i from 1 through 99 +      &.w#{$i} +        display: inline-block +  // Form group date  .form-group.date    .form-inline diff --git a/app/assets/stylesheets/modules/_vj_collection.sass b/app/assets/stylesheets/modules/_vj_collection.sass index 3ff0828ea..0131201f0 100644 --- a/app/assets/stylesheets/modules/_vj_collection.sass +++ b/app/assets/stylesheets/modules/_vj_collection.sass @@ -2,7 +2,7 @@  //  VJ Collection  //  //-----------------// -#vehicle_journeys_wip +#vehicle_journeys_wip, .consolidated-view    .table-2entries      .t2e-head        > .td @@ -218,3 +218,89 @@          // Reset default behaviour          .form-control            border-color: #ccc + + +.consolidated-view +  $highlighted: #d4ba32 +  .line +    & > .head +      font-size: 2em +      text-transform: capitalize +      border-top: 3px solid black +      border-bottom: 3px solid black +      padding-left: 10px +      margin-top: 10px +    .routes +      .route +        background: #F9F9F9 +        & > .head +          &.highlighted +            .pull-right, span.fa +              color: $highlighted !important +          a +            padding: 15px +            color: black +            font-size: 1.2em +            text-transform: capitalize +            display: block +            text-decoration: none +            &:hover +              background-color: #F0F0F0 +            .fa +              color: $red +              transition: transform 0.1s +            &.active .fa +              transform: rotate(180deg) +            .pull-right +              font-size: 0.9em +              text-transform: lowercase +        .vehicle-journeys +          display: block +          overflow: hidden +          transition: height 0.5s, margin-bottom 0.5s +          margin-bottom: 0px +          & > * +            display: inline-block +            & > * +              overflow: hidden +              min-width: 0 +          &.open +            margin-bottom: 40px + +          .highlighted +            background-color: lighten($highlighted, 20%) !important +          .disabled +            background-color: #dedede +            color: #777 +          .t2e-item-list .t2e-item +            .th +              min-width: 100px +              max-width: 150px +              & > div +                text-overflow: ellipsis +                overflow: hidden +                white-space: nowrap +            .td +              text-align: center +              &:hover:after +                position: absolute +                height: 100% +                bottom: 0 +                left: -10000px +                right: -10000px +                content: "" +                background-color: $red +                opacity: 0.1 +                z-index: 10 +              &.headlined:hover:after +                height: 50% + + +  .table-2entries > .t2e-head > .td > div > span::after +    bottom: -6px !important + +  .table.table-2entries .t2e-item-list .t2e-item +    background-color: #F9F9F9 + +  .table.table-2entries .td > div.headlined::before +    border-right: none diff --git a/app/controllers/referential_vehicle_journeys_controller.rb b/app/controllers/referential_vehicle_journeys_controller.rb index 14f7909b9..111d39c2b 100644 --- a/app/controllers/referential_vehicle_journeys_controller.rb +++ b/app/controllers/referential_vehicle_journeys_controller.rb @@ -42,9 +42,9 @@ class ReferentialVehicleJourneysController < ChouetteController      @q = @q.ransack(params[:q])      @vehicle_journeys ||= @q.result      @vehicle_journeys = parse_order @vehicle_journeys -    @vehicle_journeys = @vehicle_journeys.paginate page: params[:page], per_page: params[:per_page] || 10      @all_companies = Chouette::Company.where("id IN (#{@referential.vehicle_journeys.select(:company_id).to_sql})").distinct - +    @consolidated = ReferentialConsolidated.new @vehicle_journeys, params +    @vehicle_journeys = @vehicle_journeys.paginate page: params[:page], per_page: params[:per_page] || 10    end    def parse_order scope diff --git a/app/helpers/vehicle_journeys_helper.rb b/app/helpers/vehicle_journeys_helper.rb index 1cc865c62..4d7eb7002 100644 --- a/app/helpers/vehicle_journeys_helper.rb +++ b/app/helpers/vehicle_journeys_helper.rb @@ -69,4 +69,16 @@ module VehicleJourneysHelper      )    end +  def vehicle_journey_stop_headline prev_sp, sp +    if has_feature?(:long_distance_routes) +      headline = prev_sp && prev_sp.stop_area.country_code +      headline = sp.stop_area.country_code != headline +      headline && sp.stop_area.country_name +    else +      headline = prev_sp && prev_sp.stop_area.city_name +      headline = sp.stop_area.city_name != headline +      headline && sp.stop_area.city_name +    end +  end +  end diff --git a/app/models/chouette/route.rb b/app/models/chouette/route.rb index 7a8d043e0..949b18d6f 100644 --- a/app/models/chouette/route.rb +++ b/app/models/chouette/route.rb @@ -72,6 +72,9 @@ module Chouette        end      end +    has_many :time_tables, :through => :vehicle_journeys +    has_many :purchase_windows, :through => :vehicle_journeys +      accepts_nested_attributes_for :stop_points, :allow_destroy => :true      validates_presence_of :name diff --git a/app/services/referential_consolidated.rb b/app/services/referential_consolidated.rb new file mode 100644 index 000000000..465eab405 --- /dev/null +++ b/app/services/referential_consolidated.rb @@ -0,0 +1,124 @@ +class ReferentialConsolidated +  attr_reader :params + +  def initialize vehicle_journeys, params +    @vehicle_journeys = vehicle_journeys +    @params = params +  end + +  def paginated_lines +    @paginated_lines ||= begin +      line_ids = @vehicle_journeys.joins(route: :line).pluck('lines.id') +      lines = Chouette::Line.where(id: line_ids).order(:name) +      lines.paginate page: params[:page], per_page: params[:per_page] || 10 +    end +  end + +  def lines +    @lines ||= paginated_lines.to_a.map {|l| Line.new(self, l, @vehicle_journeys, params) } +  end + +  def _should_highlight? +    return false unless params[:q].present? +    keys = params[:q].keys - ["stop_areas"] +    params[:q].values_at(*keys).each do |value| +      if value.is_a?(Hash) +        return true if value.values.any?(&:present?) +      elsif value.is_a?(Array) +        return true if value.any?(&:present?) +      else +        if value.present? +          return true +        end +      end +    end +    false +  end + +  def should_highlight? +    if @should_highlight.nil? +      @should_highlight = _should_highlight? +    end +    @should_highlight +  end + +  class Base +    extend Forwardable +    attr_reader :params +    attr_reader :parent +    attr_reader :ar_model + +    def initialize parent, ar_model, vehicle_journeys, params +      @parent = parent +      @ar_model = ar_model +      @all_vehicle_journeys = vehicle_journeys +      @params = params +    end + +    def should_highlight? +      parent.should_highlight? +    end +  end + +  class Line < Base +    delegate name: :ar_model +    delegate id: :ar_model + +    def routes +      @routes ||= begin +        ar_model.routes.order(:name).map {|r| Route.new(self, r, @all_vehicle_journeys, params) } +      end +    end +  end + +  class Route < Base +    def_delegators :ar_model, :name, :id, :time_tables, :purchase_windows, :stop_area_ids + +    def vehicle_journeys +      @vehicle_journeys ||= begin +        ar_model.vehicle_journeys.map {|vj| VehicleJourney.new(self, vj, @all_vehicle_journeys, params) } +      end +    end + +    def highlighted_journeys +      @all_vehicle_journeys.joins(:journey_pattern).where(route_id: self.id) +    end + +    def highlighted_count +      highlighted_journeys.count +    end + +    def highlighted? +      matching_stop_areas = params[:q] && params[:q]["stop_areas"] && (params[:q]["stop_areas"].values & self.stop_area_ids.map(&:to_s)).present? +      (should_highlight? || matching_stop_areas) && highlighted_journeys.exists? +    end + +    def stop_points +      @stop_points ||= ar_model.stop_points.map {|sp| StopPoint.new(self, sp, @all_vehicle_journeys, params) } +    end +  end + +  class VehicleJourney < Base +    def_delegators :ar_model, :id, :published_journey_name, :journey_pattern, :time_tables, :purchase_windows, :vehicle_journey_at_stops, :time_table_ids, :purchase_window_ids, :route + +    def highlighted? +      should_highlight? && @all_vehicle_journeys.where(id: self.id).exists? +    end + +    def has_purchase_window? purchase_window +      purchase_window_ids.include?(purchase_window.id) +    end + +    def has_time_table? time_table +      time_table_ids.include?(time_table.id) +    end +  end + +  class StopPoint < Base +    def_delegators :ar_model, :id, :arrival_time, :departure_time, :name, :stop_area, :stop_area_id + +    def highlighted? +      params[:q] && params[:q]["stop_areas"] && params[:q]["stop_areas"].values.any?{|v| v.to_s == stop_area_id.to_s} +    end +  end +end diff --git a/app/views/referential_vehicle_journeys/_consolidated.html.slim b/app/views/referential_vehicle_journeys/_consolidated.html.slim new file mode 100644 index 000000000..e2de526bc --- /dev/null +++ b/app/views/referential_vehicle_journeys/_consolidated.html.slim @@ -0,0 +1,33 @@ +.row.consolidated-view +  - @consolidated.lines.each do |line| +    = render partial: "consolidated_line", object: line +  .col-md-12 +    = new_pagination @consolidated.paginated_lines, 'pull-right' + +coffee: +  $('a.toggle-timetables').click (e)-> +    e.preventDefault() +    $(e.target).toggleClass 'active' +    $(e.target).parents('.table').find('.detailed-timetables').toggleClass 'hidden' + +  $('a.toggle-purchase-windows').click (e)-> +    e.preventDefault() +    $(e.target).toggleClass 'active' +    $(e.target).parents('.table').find('.detailed-purchase-windows').toggleClass 'hidden' + +  $('.route').find('.vehicle-journeys').each (i, e)-> +    $e = $(e) +    $e.removeClass 'hidden' +    e.setAttribute 'data-original-height', $e.height() +    $e.height 0 + +  $('a.toggle-route').click (e)-> +    e.preventDefault() +    $(e.currentTarget).toggleClass 'active' +    tab = $(e.currentTarget).parents('.route').find('.vehicle-journeys') +    if tab.hasClass 'open' +      tab.removeClass 'open' +      tab.height 0 +    else +      tab.addClass 'open' +      tab.height tab.attr('data-original-height') diff --git a/app/views/referential_vehicle_journeys/_consolidated_line.html.slim b/app/views/referential_vehicle_journeys/_consolidated_line.html.slim new file mode 100644 index 000000000..d4c756d38 --- /dev/null +++ b/app/views/referential_vehicle_journeys/_consolidated_line.html.slim @@ -0,0 +1,119 @@ +.line.col-md-12 +  .head +    span +      = Chouette::Line.ts +      |   +    strong= consolidated_line.name +  .routes +    - consolidated_line.routes.each do |route| +      .route +        .head class="#{route.highlighted? ? 'highlighted' : ''}" +          = link_to '#', class: 'toggle-route' do +            span.sb.sb-route +            |   +            = Chouette::Route.ts +            |   +            strong= route.name +            .pull-right +              = route.highlighted_count +              |   +              = Chouette::VehicleJourney.t +              |   +              span.fa.fa-angle-up +        .table.table-2entries.vehicle-journeys.hidden +          .t2e-head.w20 +            .th +              div +                strong= Chouette::VehicleJourney.tmf(:id) +              div= Chouette::VehicleJourney.tmf(:name) +              div= Chouette::VehicleJourney.tmf(:journey_pattern_id) +              div +                = link_to '#', class: 'toggle-purchase-windows detailed-timetables-bt' do +                  span.fa.fa-angle-up +                  = Chouette::PurchaseWindow.t +              .detailed-purchase-windows.hidden +                - route.purchase_windows.uniq.each do |tt| +                  div +                    p +                      = link_to [@referential, tt] do +                        span.fa.fa-calendar style={color: (tt.color ? tt.color : '#4B4B4B')} +                        |   +                        = tt.name + +                    p= tt.bounding_dates.split(' ').join(' > ') +              div +                = link_to '#', class: 'toggle-timetables detailed-timetables-bt' do +                  span.fa.fa-angle-up +                  = Chouette::TimeTable.t + +              .detailed-timetables.hidden +                - route.time_tables.uniq.each do |tt| +                  div +                    p +                      = link_to [@referential, tt] do +                        span.fa.fa-calendar style={color: (tt.color ? tt.color : '#4B4B4B')} +                        |   +                        = tt.display_day_types + +                    p= tt.bounding_dates.split(' ').join(' > ') +            - prev_sp = nil +            - route.stop_points.each do |sp| +              ruby: +                headline = vehicle_journey_stop_headline prev_sp, sp +                prev_sp = sp +              .td class="#{sp.highlighted? ? 'highlighted' : ''}" +                div title="#{sp.stop_area.city_name ? "#{sp.stop_area.city_name} (#{sp.stop_area.zip_code})" : ''}" data-headline=headline class=(headline.present? ? 'headlined' : '') +                  span +                    = sp.name +                    - if sp.stop_area.time_zone_formatted_offset +                      span.small +                       |   +                       = "(#{sp.stop_area.time_zone_formatted_offset})" +          .t2e-item-list.w80 +            div +              - route.vehicle_journeys.each do |journey| +                .t2e-item class="#{journey.highlighted? ? 'highlighted' : ''}" +                  .th +                    div +                      strong= link_to journey.id, [@referential, journey.route.line, journey.route, :vehicle_journeys] +                    div +                      = link_to journey.published_journey_name, [@referential, journey.route.line, journey.route, :vehicle_journeys], title: journey.published_journey_name +                    div= journey.journey_pattern.get_objectid.short_id +                    div +                      - journey.purchase_windows[0..3].each do |tt| +                        span.vj_tt +                          = link_to [@referential, tt], target: :blank do +                            span.fa.fa-calendar style="color: #{tt.color ? tt.color : '#4B4B4B'}" +                      - if journey.purchase_windows.size > 3 +                        span.vj_tt = "+ #{journey.purchase_windows.size - 3}" +                    .detailed-purchase-windows.hidden +                      - route.purchase_windows.uniq.each do |tt| +                        div class=(journey.has_purchase_window?(tt) ? 'active' : 'inactive') +                    div +                      - journey.time_tables[0..3].each do |tt| +                        span.vj_tt +                          = link_to [@referential, tt], target: :blank do +                            span.fa.fa-calendar style="color: #{tt.color ? tt.color : '#4B4B4B'}" +                      - if journey.time_tables.size > 3 +                        span.vj_tt = "+ #{journey.time_tables.size - 3}" +                    .detailed-timetables.hidden +                      - route.time_tables.uniq.each do |tt| +                        div class=(journey.has_time_table?(tt) ? 'active' : 'inactive') + +                  - prev_sp = nil +                  - route.stop_points.each do |sp| +                    ruby: +                      headline = vehicle_journey_stop_headline prev_sp, sp +                      prev_sp = sp +                      vjas = journey.vehicle_journey_at_stops.where(stop_point_id: sp.id).last +                    .td class="#{vjas && sp.highlighted? ? 'highlighted' : ''} #{vjas.nil? ? 'disabled' : ''} #{headline.present? ? 'headlined' : ''}" +                      div title="#{sp.stop_area.city_name ? "#{sp.stop_area.city_name} (#{sp.stop_area.zip_code})" : ''}" data-headline=headline class=(headline.present? ? 'headlined' : '') +                        - if vjas.present? +                          - if vjas.departure_time == vjas.arrival_time +                            = vjas.departure_time.l(format: "%H:%M") +                          - else +                            = vjas.arrival_time.l(format: "%H:%M") +                            |  -  +                            = vjas.departure_time.l(format: "%H:%M") +                        - else +                          | 00:00 diff --git a/app/views/referential_vehicle_journeys/_filters.html.slim b/app/views/referential_vehicle_journeys/_filters.html.slim index a6e289b97..31053c5ba 100644 --- a/app/views/referential_vehicle_journeys/_filters.html.slim +++ b/app/views/referential_vehicle_journeys/_filters.html.slim @@ -1,10 +1,20 @@  = search_form_for @q, url: referential_vehicle_journeys_path(@referential), html: {method: :get}, class: 'form form-filter' do |f| -  .ffg-row +  input type="hidden" name="display" value=params[:display] +  .ffg-row.w85      .input-group.search_bar        = f.search_field :published_journey_name_or_objectid_cont, placeholder: t('.published_journey_name_or_objectid'), class: 'form-control'        span.input-group-btn          button.btn.btn-default#search-btn type='submit'            span.fa.fa-search +  .ffg-row.w15 +    - if has_feature?(:consolidated_offers) +      .form-group +        .btn-group +          = link_to referential_vehicle_journeys_path(@referential, q: params[:q], display: :list), class: 'btn btn-default ' + (params[:display] != "consolidated" ? 'active' : '') do +            span.fa.fa-align-justify +          = link_to referential_vehicle_journeys_path(@referential, q: params[:q], display: :consolidated), class: 'btn btn-default ' + (params[:display] == "consolidated" ? 'active' : '') do +            span.fa.fa-th-large +    .ffg-row      .form-group.per-page-select        = I18n.t("simple_form.per_page") @@ -73,5 +83,5 @@    .actions -    = link_to t('actions.erase'), referential_vehicle_journeys_path(@referential), class: 'btn btn-link' +    = link_to t('actions.erase'), referential_vehicle_journeys_path(@referential, display: params[:display]), class: 'btn btn-link'      = f.submit t('actions.filter'), class: 'btn btn-default' diff --git a/app/views/referential_vehicle_journeys/_list.html.slim b/app/views/referential_vehicle_journeys/_list.html.slim new file mode 100644 index 000000000..74f8238f8 --- /dev/null +++ b/app/views/referential_vehicle_journeys/_list.html.slim @@ -0,0 +1,49 @@ +.row +  .col-lg-12 +    .select_table +      = table_builder_2 @vehicle_journeys, +        [ \ +          TableBuilderHelper::Column.new( \ +            name: t('objectid'), \ +            attribute: Proc.new { |n| n.get_objectid.short_id }, \ +            sortable: false \ +          ), \ +          TableBuilderHelper::Column.new( \ +            key: :published_journey_name, \ +            attribute: 'published_journey_name', \ +            link_to: lambda do |vehicle_journey| \ +              vehicle_journey.published_journey_name ? referential_line_route_vehicle_journeys_path(@referential, vehicle_journey.route.line, vehicle_journey.route) : '' \ +            end, \ +            sortable: true \ +          ), \ +          TableBuilderHelper::Column.new( \ +            key: :line, \ +            attribute: Proc.new {|v| v.route.line.name}, \ +            sortable: true \ +          ), \ +          TableBuilderHelper::Column.new( \ +            key: :route, \ +            attribute: Proc.new {|v| v.route.name}, \ +            sortable: true \ +          ), \ +          TableBuilderHelper::Column.new( \ +            key: :departure_time, \ +            attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure_local }, \ +            sortable: true \ +          ), \ +          [@starting_stop, @ending_stop].compact.map{|stop| \ +            TableBuilderHelper::Column.new( \ +              attribute: Proc.new {|v| v.vehicle_journey_at_stops.where("stop_points.stop_area_id" => stop.id).last&.arrival_local }, \ +              sortable: false, \ +              name: stop.name \ +            )\ +          }, \ +          TableBuilderHelper::Column.new( \ +            key: :arrival_time, \ +            attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival_local }, \ +            sortable: true, \ +          ), \ +        ].flatten.compact, +        cls: 'table has-filter has-search' + +    = new_pagination @vehicle_journeys, 'pull-right' diff --git a/app/views/referential_vehicle_journeys/index.html.slim b/app/views/referential_vehicle_journeys/index.html.slim index 00f63cb65..d1d1dae07 100644 --- a/app/views/referential_vehicle_journeys/index.html.slim +++ b/app/views/referential_vehicle_journeys/index.html.slim @@ -9,55 +9,11 @@            = render 'filters'      - if @vehicle_journeys.present? -      .row -        .col-lg-12 -          .select_table -            = table_builder_2 @vehicle_journeys, -              [ \ -                TableBuilderHelper::Column.new( \ -                  name: t('objectid'), \ -                  attribute: Proc.new { |n| n.get_objectid.short_id }, \ -                  sortable: false \ -                ), \ -                TableBuilderHelper::Column.new( \ -                  key: :published_journey_name, \ -                  attribute: 'published_journey_name', \ -                  link_to: lambda do |vehicle_journey| \ -                    vehicle_journey.published_journey_name ? referential_line_route_vehicle_journeys_path(@referential, vehicle_journey.route.line, vehicle_journey.route) : '' \ -                  end, \ -                  sortable: true \ -                ), \ -                TableBuilderHelper::Column.new( \ -                  key: :line, \ -                  attribute: Proc.new {|v| v.route.line.name}, \ -                  sortable: true \ -                ), \ -                TableBuilderHelper::Column.new( \ -                  key: :route, \ -                  attribute: Proc.new {|v| v.route.name}, \ -                  sortable: true \ -                ), \ -                TableBuilderHelper::Column.new( \ -                  key: :departure_time, \ -                  attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure_local }, \ -                  sortable: true \ -                ), \ -                [@starting_stop, @ending_stop].compact.map{|stop| \ -                  TableBuilderHelper::Column.new( \ -                    attribute: Proc.new {|v| v.vehicle_journey_at_stops.where("stop_points.stop_area_id" => stop.id).last&.arrival_local }, \ -                    sortable: false, \ -                    name: stop.name \ -                  )\ -                }, \ -                TableBuilderHelper::Column.new( \ -                  key: :arrival_time, \ -                  attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival_local }, \ -                  sortable: true, \ -                ), \ -              ].flatten.compact, -              cls: 'table has-filter has-search' +      - if params[:display] == "consolidated" && has_feature?(:consolidated_offers) +        = render partial: "consolidated" +      - else +        = render partial: "list" -          = new_pagination @vehicle_journeys, 'pull-right'      - unless @vehicle_journeys.any?        .row.mt-xs | 
