From f6f52147fcec3b9283dc2890cfb05b0fb19bff33 Mon Sep 17 00:00:00 2001
From: Zog
Date: Fri, 26 Jan 2018 12:49:23 +0100
Subject: Refs #5741 @2h; Add a map of all routes on a line#show
---
 Gemfile.lock                                      |  22 +--
 app/assets/stylesheets/OpenLayers/custom.sass     |  21 +++
 app/helpers/routes_helper.rb                      |   8 +-
 app/javascript/helpers/routes_map.coffee          | 157 ++++++++++++++++++++++
 app/javascript/packs/referential_lines/show.js    |  10 ++
 app/javascript/packs/routes/show.js               | 123 +----------------
 app/javascript/routes/components/StopPointList.js |   4 +-
 app/views/referential_lines/show.html.slim        |   8 +-
 config/webpack/environment.js                     |   2 +
 config/webpack/loaders/coffee.js                  |   6 +
 package.json                                      |   3 +-
 yarn.lock                                         |  12 +-
 12 files changed, 238 insertions(+), 138 deletions(-)
 create mode 100644 app/javascript/helpers/routes_map.coffee
 create mode 100644 app/javascript/packs/referential_lines/show.js
 create mode 100644 config/webpack/loaders/coffee.js
diff --git a/Gemfile.lock b/Gemfile.lock
index 09ef00f94..f4dfe1bf7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -156,6 +156,7 @@ GEM
       sort_alphabetical (~> 1.0)
     crack (0.4.3)
       safe_yaml (~> 1.0.0)
+    crass (1.0.3)
     cucumber (2.4.0)
       builder (>= 2.1.2)
       cucumber-core (~> 1.5.0)
@@ -265,7 +266,7 @@ GEM
     htmlbeautifier (1.3.1)
     httparty (0.14.0)
       multi_xml (>= 0.5.2)
-    i18n (0.9.0)
+    i18n (0.9.3)
       concurrent-ruby (~> 1.0)
     i18n-tasks (0.9.15)
       activesupport (>= 4.0.2)
@@ -302,7 +303,8 @@ GEM
       thor
       with_env (> 1.0)
       xml-simple
-    loofah (2.0.3)
+    loofah (2.1.1)
+      crass (~> 1.0.2)
       nokogiri (>= 1.5.9)
     mail (2.6.4)
       mime-types (>= 1.16, < 4)
@@ -313,7 +315,7 @@ GEM
     mime-types-data (3.2016.0521)
     mimemagic (0.3.2)
     mini_portile2 (2.3.0)
-    minitest (5.10.3)
+    minitest (5.11.2)
     money (6.10.1)
       i18n (>= 0.6.4, < 1.0)
     multi_json (1.12.1)
@@ -368,7 +370,7 @@ GEM
       rack
     rack-protection (1.5.3)
       rack
-    rack-proxy (0.6.2)
+    rack-proxy (0.6.3)
       rack
     rack-test (0.6.3)
       rack (>= 1.0)
@@ -396,8 +398,8 @@ GEM
       rails-assets-jquery (>= 1.0.0)
     rails-deprecated_sanitizer (1.0.3)
       activesupport (>= 4.2.0.alpha)
-    rails-dom-testing (1.0.8)
-      activesupport (>= 4.2.0.beta, < 5.0)
+    rails-dom-testing (1.0.9)
+      activesupport (>= 4.2.0, < 5.0)
       nokogiri (~> 1.6)
       rails-deprecated_sanitizer (>= 1.0.1)
     rails-erd (1.5.2)
@@ -419,7 +421,7 @@ GEM
       thor (>= 0.18.1, < 2.0)
     rainbow (2.2.2)
       rake
-    rake (12.0.0)
+    rake (12.3.0)
     ransack (1.8.3)
       actionpack (>= 3.0)
       activerecord (>= 3.0)
@@ -541,7 +543,7 @@ GEM
     therubyracer (0.12.3)
       libv8 (~> 3.16.14.15)
       ref
-    thor (0.19.4)
+    thor (0.20.0)
     thread (0.2.2)
     thread_safe (0.3.6)
     tilt (1.4.1)
@@ -553,7 +555,7 @@ GEM
       json (>= 1.8, < 3.0)
       parser (>= 2.3.0.7)
       rainbow (>= 1.99.1, < 3.0)
-    tzinfo (1.2.3)
+    tzinfo (1.2.4)
       thread_safe (~> 0.1)
     uglifier (2.7.2)
       execjs (>= 0.3.0)
@@ -566,7 +568,7 @@ GEM
       addressable (>= 2.3.6)
       crack (>= 0.3.2)
       hashdiff
-    webpacker (3.0.2)
+    webpacker (3.2.1)
       activesupport (>= 4.2)
       rack-proxy (>= 0.6.1)
       railties (>= 4.2)
diff --git a/app/assets/stylesheets/OpenLayers/custom.sass b/app/assets/stylesheets/OpenLayers/custom.sass
index 7a5b4baf1..5a3612f99 100644
--- a/app/assets/stylesheets/OpenLayers/custom.sass
+++ b/app/assets/stylesheets/OpenLayers/custom.sass
@@ -2,6 +2,27 @@
   .list-group-item &
     margin-top: 15px
 
+  .routes-labels
+    padding: 0
+    display: flex
+    justify-content: space-between
+    flex-wrap: wrap
+    margin: 5px -5px
+    li
+      list-style-type: none
+      flex: 1 0 25%
+      border: 1px solid $lightgrey
+      padding: 5px
+      margin: 5px
+      border-radius: 5px
+      cursor: pointer
+      color: $blue
+      white-space: nowrap
+      max-width: 33%
+
+      &:hover
+        background: $orange
+        color: white
 
   .ol-scale-line
     background-color: transparent
diff --git a/app/helpers/routes_helper.rb b/app/helpers/routes_helper.rb
index 4bffa99d4..61714a066 100644
--- a/app/helpers/routes_helper.rb
+++ b/app/helpers/routes_helper.rb
@@ -19,13 +19,15 @@ module RoutesHelper
     css
   end
 
-  def route_json_for_edit(route)
-    route.stop_points.includes(:stop_area).order(:position).map do |stop_point|
+  def route_json_for_edit(route, serialize: true)
+    data = route.stop_points.includes(:stop_area).order(:position).map do |stop_point|
       stop_area_attributes = stop_point.stop_area.attributes.slice("name","city_name", "zip_code", "registration_number", "longitude", "latitude", "area_type", "comment")
       stop_area_attributes["short_name"] = truncate(stop_area_attributes["name"], :length => 30) || ""
       stop_point_attributes = stop_point.attributes.slice("for_boarding","for_alighting")
       stop_area_attributes.merge(stop_point_attributes).merge(stoppoint_id: stop_point.id, stoparea_id: stop_point.stop_area.id).merge(user_objectid: stop_point.stop_area.user_objectid)
-    end.to_json
+    end
+    data = data.to_json if serialize
+    data
   end
 
 end
diff --git a/app/javascript/helpers/routes_map.coffee b/app/javascript/helpers/routes_map.coffee
new file mode 100644
index 000000000..85def1390
--- /dev/null
+++ b/app/javascript/helpers/routes_map.coffee
@@ -0,0 +1,157 @@
+class RoutesMap
+  constructor: (@target)->
+    @initMap()
+    @area = []
+    @seenStopIds = []
+    @routes = {}
+
+  initMap: ->
+    @map = new ol.Map
+      target: @target,
+      layers:   [ new ol.layer.Tile(source: new ol.source.OSM()) ]
+      controls: [ new ol.control.ScaleLine(), new ol.control.Zoom(), new ol.control.ZoomSlider() ],
+      interactions: ol.interaction.defaults(zoom: true)
+      view: new ol.View()
+
+  addRoutes: (routes)->
+    for route in routes
+      @addRoute route
+
+  addRoute: (route)->
+    geoColPts = []
+    geoColLns = []
+    @routes[route.id] = route if route.id
+    stops = route.stops || route
+    geoColEdges = [
+      new ol.Feature({
+        geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stops[0].longitude), parseFloat(stops[0].latitude)]))
+      }),
+      new ol.Feature({
+        geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stops[stops.length - 1].longitude), parseFloat(stops[stops.length - 1].latitude)]))
+      })
+    ]
+    stops.forEach (stop, i) =>
+      if i < stops.length - 1
+        geoColLns.push new ol.Feature
+          geometry: new ol.geom.LineString([
+            ol.proj.fromLonLat([parseFloat(stops[i].longitude), parseFloat(stops[i].latitude)]),
+            ol.proj.fromLonLat([parseFloat(stops[i + 1].longitude), parseFloat(stops[i + 1].latitude)])
+          ])
+
+      geoColPts.push(new ol.Feature({
+        geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)]))
+      }))
+      unless @seenStopIds.indexOf(stop.stoparea_id) > 0
+        @area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)]
+        @seenStopIds.push stop.stoparea_id
+
+    vectorPtsLayer = new ol.layer.Vector({
+      source: new ol.source.Vector({
+        features: geoColPts
+      }),
+      style: @defaultStyles(),
+      zIndex: 2
+    })
+    route.vectorPtsLayer = vectorPtsLayer if route.id
+    vectorEdgesLayer = new ol.layer.Vector({
+      source: new ol.source.Vector({
+        features: geoColEdges
+      }),
+      style: @edgeStyles(),
+      zIndex: 3
+    })
+    route.vectorEdgesLayer = vectorEdgesLayer if route.id
+    vectorLnsLayer = new ol.layer.Vector({
+      source: new ol.source.Vector({
+        features: geoColLns
+      }),
+      style: [@lineStyle()],
+      zIndex: 1
+    })
+    route.vectorLnsLayer = vectorLnsLayer if route.id
+    @map.addLayer vectorPtsLayer
+    @map.addLayer vectorEdgesLayer
+    @map.addLayer vectorLnsLayer
+
+  lineStyle: (highlighted=false)->
+    new ol.style.Style
+      stroke: new ol.style.Stroke
+        color: if highlighted then "#ed7f00" else '#007fbb'
+        width: 3
+
+  edgeStyles: (highlighted=false)->
+    new ol.style.Style
+      image: new ol.style.Circle
+        radius: 5
+        stroke: new ol.style.Stroke
+          color: if highlighted then "#ed7f00" else '#007fbb'
+          width: 2
+        fill: new ol.style.Fill
+          color: if highlighted then "#ed7f00" else '#007fbb'
+          width: 2
+
+  defaultStyles: (highlighted=false)->
+    new ol.style.Style
+      image: new ol.style.Circle
+        radius: 4
+        stroke: new ol.style.Stroke
+          color: if highlighted then "#ed7f00" else '#007fbb'
+          width: 2
+        fill: new ol.style.Fill
+          color: '#ffffff'
+          width: 2
+
+  addRoutesLabels: ->
+    labelsContainer = $("
")
+    labelsContainer.appendTo $("##{@target}")
+    @vectorPtsLayer = null
+    @vectorEdgesLayer = null
+    @vectorLnsLayer = null
+    Object.keys(@routes).forEach (id)=>
+      route = @routes[id]
+      label = $("#{route.name}")
+      label.appendTo labelsContainer
+      label.mouseleave =>
+        route.vectorPtsLayer.setStyle @defaultStyles(false)
+        route.vectorEdgesLayer.setStyle @edgeStyles(false)
+        route.vectorLnsLayer.setStyle @lineStyle(false)
+        route.vectorPtsLayer.setZIndex 2
+        route.vectorEdgesLayer.setZIndex 3
+        route.vectorLnsLayer.setZIndex 1
+        @fitZoom()
+      label.mouseenter =>
+        route.vectorPtsLayer.setStyle @defaultStyles(true)
+        route.vectorEdgesLayer.setStyle @edgeStyles(true)
+        route.vectorLnsLayer.setStyle @lineStyle(true)
+        route.vectorPtsLayer.setZIndex 11
+        route.vectorEdgesLayer.setZIndex 12
+        route.vectorLnsLayer.setZIndex 10
+        @fitZoom(route)
+
+  fitZoom: (route)->
+    if route
+      area = []
+      route.stops.forEach (stop, i) =>
+        area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)]
+    else
+      area = @area
+    boundaries = ol.extent.applyTransform(
+      ol.extent.boundingExtent(area), ol.proj.getTransform('EPSG:4326', 'EPSG:3857')
+    )
+    @map.getView().fit boundaries, @map.getSize()
+    tooCloseToBounds = false
+    mapBoundaries = @map.getView().calculateExtent @map.getSize()
+    mapWidth = mapBoundaries[2] - mapBoundaries[0]
+    mapHeight = mapBoundaries[3] - mapBoundaries[1]
+    marginSize = 0.1
+    heightMargin = marginSize * mapHeight
+    widthMargin = marginSize * mapWidth
+    tooCloseToBounds = tooCloseToBounds || (boundaries[0] - mapBoundaries[0]) < widthMargin
+    tooCloseToBounds = tooCloseToBounds || (mapBoundaries[2] - boundaries[2]) < widthMargin
+    tooCloseToBounds = tooCloseToBounds || (boundaries[1] - mapBoundaries[1]) < heightMargin
+    tooCloseToBounds = tooCloseToBounds || (mapBoundaries[3] - boundaries[3]) < heightMargin
+    if tooCloseToBounds
+      @map.getView().setZoom(@map.getView().getZoom() - 1)
+
+
+export default RoutesMap
diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js
new file mode 100644
index 000000000..99c5072ef
--- /dev/null
+++ b/app/javascript/packs/referential_lines/show.js
@@ -0,0 +1,10 @@
+import clone from '../../helpers/clone'
+import RoutesMap from '../../helpers/routes_map'
+
+let routes = clone(window, "routes", true)
+routes = JSON.parse(decodeURIComponent(routes))
+
+var map = new RoutesMap('routes_map')
+map.addRoutes(routes)
+map.addRoutesLabels()
+map.fitZoom()
diff --git a/app/javascript/packs/routes/show.js b/app/javascript/packs/routes/show.js
index 71777c379..c20de0800 100644
--- a/app/javascript/packs/routes/show.js
+++ b/app/javascript/packs/routes/show.js
@@ -1,121 +1,8 @@
 import clone from '../../helpers/clone'
+import RoutesMap from '../../helpers/routes_map'
+
 let route = clone(window, "route", true)
 route = JSON.parse(decodeURIComponent(route))
-
-const geoColPts = []
-const geoColLns = []
-const area = []
-const geoColEdges = [
-  new ol.Feature({
-    geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(route[0].longitude), parseFloat(route[0].latitude)]))
-  }),
-  new ol.Feature({
-    geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(route[route.length - 1].longitude), parseFloat(route[route.length - 1].latitude)]))
-  })
-]
-route.forEach(function (stop, i) {
-  if (i < route.length - 1) {
-    geoColLns.push(new ol.Feature({
-      geometry: new ol.geom.LineString([
-        ol.proj.fromLonLat([parseFloat(route[i].longitude), parseFloat(route[i].latitude)]),
-        ol.proj.fromLonLat([parseFloat(route[i + 1].longitude), parseFloat(route[i + 1].latitude)])
-      ])
-    }))
-  }
-  geoColPts.push(new ol.Feature({
-    geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)]))
-  }))
-  area.push([parseFloat(stop.longitude), parseFloat(stop.latitude)])
-})
-var edgeStyles = new ol.style.Style({
-  image: new ol.style.Circle(({
-    radius: 5,
-    stroke: new ol.style.Stroke({
-      color: '#007fbb',
-      width: 2
-    }),
-    fill: new ol.style.Fill({
-      color: '#007fbb',
-      width: 2
-    })
-  }))
-})
-var defaultStyles = new ol.style.Style({
-  image: new ol.style.Circle(({
-    radius: 4,
-    stroke: new ol.style.Stroke({
-      color: '#007fbb',
-      width: 2
-    }),
-    fill: new ol.style.Fill({
-      color: '#ffffff',
-      width: 2
-    })
-  }))
-})
-var lineStyle = new ol.style.Style({
-  stroke: new ol.style.Stroke({
-    color: '#007fbb',
-    width: 3
-  })
-})
-
-var vectorPtsLayer = new ol.layer.Vector({
-  source: new ol.source.Vector({
-    features: geoColPts
-  }),
-  style: defaultStyles,
-  zIndex: 2
-})
-var vectorEdgesLayer = new ol.layer.Vector({
-  source: new ol.source.Vector({
-    features: geoColEdges
-  }),
-  style: edgeStyles,
-  zIndex: 3
-})
-var vectorLnsLayer = new ol.layer.Vector({
-  source: new ol.source.Vector({
-    features: geoColLns
-  }),
-  style: [lineStyle],
-  zIndex: 1
-})
-
-var map = new ol.Map({
-  target: 'route_map',
-  layers: [
-    new ol.layer.Tile({
-      source: new ol.source.OSM()
-    }),
-    vectorPtsLayer,
-    vectorEdgesLayer,
-    vectorLnsLayer
-  ],
-  controls: [new ol.control.ScaleLine(), new ol.control.Zoom(), new ol.control.ZoomSlider()],
-  interactions: ol.interaction.defaults({
-    zoom: true
-  }),
-  view: new ol.View({
-    center: ol.proj.fromLonLat([parseFloat(route[0].longitude), parseFloat(route[0].latitude)]),
-    zoom: 13
-  })
-});
-const boundaries = ol.extent.applyTransform(
-  ol.extent.boundingExtent(area), ol.proj.getTransform('EPSG:4326', 'EPSG:3857')
-)
-map.getView().fit(boundaries, map.getSize());
-let tooCloseToBounds = false
-const mapBoundaries = map.getView().calculateExtent(map.getSize())
-const mapWidth = mapBoundaries[2] - mapBoundaries[0]
-const mapHeight = mapBoundaries[3] - mapBoundaries[1]
-const marginSize = 0.1
-const heightMargin = marginSize * mapHeight
-const widthMargin = marginSize * mapWidth
-tooCloseToBounds = tooCloseToBounds || (boundaries[0] - mapBoundaries[0]) < widthMargin
-tooCloseToBounds = tooCloseToBounds || (mapBoundaries[2] - boundaries[2]) < widthMargin
-tooCloseToBounds = tooCloseToBounds || (boundaries[1] - mapBoundaries[1]) < heightMargin
-tooCloseToBounds = tooCloseToBounds || (mapBoundaries[3] - boundaries[3]) < heightMargin
-if(tooCloseToBounds){
-  map.getView().setZoom(map.getView().getZoom() - 1)
-}
+var map = new RoutesMap('route_map')
+map.addRoute(route)
+map.fitZoom()
diff --git a/app/javascript/routes/components/StopPointList.js b/app/javascript/routes/components/StopPointList.js
index 43a027084..b39fa0c9c 100644
--- a/app/javascript/routes/components/StopPointList.js
+++ b/app/javascript/routes/components/StopPointList.js
@@ -56,7 +56,7 @@ export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick
   )
 }
 
-StopPointList.PropTypes = {
+StopPointList.propTypes = {
   stopPoints: PropTypes.array.isRequired,
   onDeleteClick: PropTypes.func.isRequired,
   onMoveUpClick: PropTypes.func.isRequired,
@@ -68,4 +68,4 @@ StopPointList.PropTypes = {
 
 StopPointList.contextTypes = {
   I18n: PropTypes.object
-}
\ No newline at end of file
+}
diff --git a/app/views/referential_lines/show.html.slim b/app/views/referential_lines/show.html.slim
index 02d605d8c..5ea0e31bb 100644
--- a/app/views/referential_lines/show.html.slim
+++ b/app/views/referential_lines/show.html.slim
@@ -17,7 +17,8 @@
              @line.human_attribute_name(:transport_submode) => (@line.transport_submode.present? ? t("enumerize.transport_submode.#{@line.transport_submode}") : '-'),
              @line.human_attribute_name(:url) => (@line.url ? @line.url : '-'),
              @line.human_attribute_name(:seasonal) => (@line.seasonal? ? t('true') : t('false')),}
-
+      .col-lg-6.col-md-6.col-sm-12.col-xs-12
+        #routes_map.map.mb-lg
     .row
       .col-lg-12
         .h3 = t('lines.show.routes.title')
@@ -79,3 +80,8 @@
           .row.mt-xs
             .col-lg-12
               = replacement_msg t('routes.search_no_results')
+
+= javascript_tag do
+  | window.routes = "#{URI.escape(@routes.map{|r| {name: r.name, id: r.id, stops: route_json_for_edit(r, serialize: false)}}.to_json)}"
+
+= javascript_pack_tag 'referential_lines/show.js'
diff --git a/config/webpack/environment.js b/config/webpack/environment.js
index e7c879fb9..688bcbe8e 100644
--- a/config/webpack/environment.js
+++ b/config/webpack/environment.js
@@ -1,4 +1,5 @@
 const { environment } = require('@rails/webpacker')
+const coffee =  require('./loaders/coffee')
 const CleanWebpackPlugin = require('clean-webpack-plugin')
 
 let pathsToClean = [
@@ -24,4 +25,5 @@ environment.plugins.set(
 //   jquery: "jquery/src/jquery",
 // }
 
+environment.loaders.append('coffee', coffee)
 module.exports = environment
diff --git a/config/webpack/loaders/coffee.js b/config/webpack/loaders/coffee.js
new file mode 100644
index 000000000..4666716dc
--- /dev/null
+++ b/config/webpack/loaders/coffee.js
@@ -0,0 +1,6 @@
+module.exports = {
+  test: /\.coffee(\.erb)?$/,
+  use: [{
+    loader: 'coffee-loader'
+  }]
+}
diff --git a/package.json b/package.json
index 80ca22f83..802a2eef7 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,8 @@
     "babel-preset-react": "6.24.1",
     "babelify": "8.0.0",
     "bootstrap": "3",
-    "coffeescript": "2.1.0",
+    "coffee-loader": "^0.9.0",
+    "coffeescript": "1.12.7",
     "jquery": "3.2.1",
     "lodash": "4.17.4",
     "promise-polyfill": "7.0.0",
diff --git a/yarn.lock b/yarn.lock
index e95ee9a63..d17ae1d52 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1404,13 +1404,19 @@ code-point-at@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
 
+coffee-loader@^0.9.0:
+  version "0.9.0"
+  resolved "https://registry.yarnpkg.com/coffee-loader/-/coffee-loader-0.9.0.tgz#6deabd336062ddc6d773da4dfd16367fc7107bd6"
+  dependencies:
+    loader-utils "^1.0.2"
+
 coffee-script@~1.10.0:
   version "1.10.0"
   resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.10.0.tgz#12938bcf9be1948fa006f92e0c4c9e81705108c0"
 
-coffeescript@2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-2.1.0.tgz#8cb7ce12021ab9f84d8c524f54edbd6141374606"
+coffeescript@1.12.7:
+  version "1.12.7"
+  resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.12.7.tgz#e57ee4c4867cf7f606bfc4a0f2d550c0981ddd27"
 
 color-convert@^1.3.0, color-convert@^1.8.2, color-convert@^1.9.0:
   version "1.9.0"
-- 
cgit v1.2.3
From c1da45b2f561ab7ec8d2785bb53f25218e471ce2 Mon Sep 17 00:00:00 2001
From: Zog
Date: Fri, 26 Jan 2018 10:34:51 +0100
Subject: Remove 'rspec-snaphost' to check if it causes segfaults on travis
---
 Gemfile      | 1 -
 Gemfile.lock | 7 -------
 2 files changed, 8 deletions(-)
diff --git a/Gemfile b/Gemfile
index f22b718c3..c378820b3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -174,7 +174,6 @@ group :test do
   gem 'simplecov-rcov', :require => false
   gem 'htmlbeautifier'
   gem 'timecop'
-  gem 'rspec-snapshot'
 end
 
 group :test, :development, :dev do
diff --git a/Gemfile.lock b/Gemfile.lock
index f4dfe1bf7..ba86a911f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -444,10 +444,6 @@ GEM
     roo (2.7.1)
       nokogiri (~> 1)
       rubyzip (~> 1.1, < 2.0.0)
-    rspec (3.5.0)
-      rspec-core (~> 3.5.0)
-      rspec-expectations (~> 3.5.0)
-      rspec-mocks (~> 3.5.0)
     rspec-core (3.5.4)
       rspec-support (~> 3.5.0)
     rspec-expectations (3.5.0)
@@ -464,8 +460,6 @@ GEM
       rspec-expectations (~> 3.5.0)
       rspec-mocks (~> 3.5.0)
       rspec-support (~> 3.5.0)
-    rspec-snapshot (0.1.1)
-      rspec (> 3.0.0)
     rspec-support (3.5.0)
     ruby-graphviz (1.2.3)
     rubycas-client (2.3.9)
@@ -682,7 +676,6 @@ DEPENDENCIES
   rgeo (~> 0.5.2)
   roo
   rspec-rails (~> 3.5.0)
-  rspec-snapshot
   rubyzip
   sass-rails (~> 4.0.3)
   sawyer (~> 0.6.0)
-- 
cgit v1.2.3
From 22c38fb750843f0c74996175a6bd17a1f20a943c Mon Sep 17 00:00:00 2001
From: Zog
Date: Fri, 26 Jan 2018 16:17:22 +0100
Subject: Refs #5750 @1h; Add a "kind" attribute to StopAreas
This determines if the StopArea is commercial or not
The useless fields are hidden in the form for the non-commercials ones
---
 app/assets/stylesheets/components/_forms.sass      |  8 ++++++-
 app/javascript/helpers/master_slave.coffee         | 18 ++++++++++++++++
 app/javascript/packs/stop_areas/new.js             |  3 +++
 app/models/chouette/area_type.rb                   | 25 ++++++++++++++++------
 app/models/chouette/stop_area.rb                   |  9 ++++++++
 app/views/stop_areas/_form.html.slim               | 10 +++++++--
 app/views/stop_areas/show.html.slim                |  8 +++----
 config/locales/area_types.en.yml                   |  6 ++++++
 config/locales/area_types.fr.yml                   |  6 ++++++
 .../20180126134944_add_kind_to_stop_areas.rb       |  5 +++++
 db/schema.rb                                       |  9 ++++++--
 spec/models/chouette/area_type_spec.rb             |  4 +++-
 12 files changed, 94 insertions(+), 17 deletions(-)
 create mode 100644 app/javascript/helpers/master_slave.coffee
 create mode 100644 app/javascript/packs/stop_areas/new.js
 create mode 100644 db/migrate/20180126134944_add_kind_to_stop_areas.rb
diff --git a/app/assets/stylesheets/components/_forms.sass b/app/assets/stylesheets/components/_forms.sass
index b7f720963..214795b8b 100644
--- a/app/assets/stylesheets/components/_forms.sass
+++ b/app/assets/stylesheets/components/_forms.sass
@@ -85,9 +85,15 @@ input
 
 // BS horizontal form label positionning fix
 .form-horizontal
+  input[type="radio"].form-control
+    height: auto
+    width: auto
   .form-group
     position: relative
-
+    .radio-inline
+      padding-top: 4px
+      &:first-child
+        padding-left: 0
     > .control-label
       &[class*='col-sm-']
         float: none
diff --git a/app/javascript/helpers/master_slave.coffee b/app/javascript/helpers/master_slave.coffee
new file mode 100644
index 000000000..11f6bca7e
--- /dev/null
+++ b/app/javascript/helpers/master_slave.coffee
@@ -0,0 +1,18 @@
+class MasterSlave
+  constructor: (selector)->
+    $(selector).find('[data-master]').each (i, slave)->
+      $slave = $(slave)
+      master = $($slave.data().master)
+      console.log $slave.data().master
+      console.log master
+      toggle = ->
+        val = master.filter(":checked").val() if master.filter("[type=radio]").length > 0
+        val ||= master.val()
+        selected = val == $slave.data().value
+        $slave.toggle selected
+        $slave.find("input, select").attr "disabled", !selected
+      master.change toggle
+      toggle()
+      # $slave.toggle master.val() == $slave.data().value
+
+export default MasterSlave
diff --git a/app/javascript/packs/stop_areas/new.js b/app/javascript/packs/stop_areas/new.js
new file mode 100644
index 000000000..ffe702cdb
--- /dev/null
+++ b/app/javascript/packs/stop_areas/new.js
@@ -0,0 +1,3 @@
+import MasterSlave from "../../helpers/master_slave"
+
+new MasterSlave("form")
diff --git a/app/models/chouette/area_type.rb b/app/models/chouette/area_type.rb
index 4703ea646..e17d2ee8d 100644
--- a/app/models/chouette/area_type.rb
+++ b/app/models/chouette/area_type.rb
@@ -1,13 +1,22 @@
 class Chouette::AreaType
   include Comparable
 
-  ALL = %i(zdep zder zdlp zdlr lda gdl).freeze
+  COMMERCIAL = %i(zdep zder zdlp zdlr lda gdl).freeze
+  NON_COMMERCIAL = %i(deposit border service_area relief other).freeze
+  ALL = COMMERCIAL + NON_COMMERCIAL
 
+  @@commercial = COMMERCIAL
+  @@non_commercial = NON_COMMERCIAL
   @@all = ALL
-  mattr_accessor :all
+  mattr_accessor :all, :commercial, :non_commercial
 
-  def self.all=(values)
-    @@all = ALL & values
+  def self.commercial=(values)
+    @@commercial = COMMERCIAL & values
+    reset_caches!
+  end
+
+  def self.non_commercial=(values)
+    @@non_commercial = NON_COMMERCIAL & values
     reset_caches!
   end
 
@@ -20,12 +29,14 @@ class Chouette::AreaType
   end
 
   def self.reset_caches!
+    @@all = @@commercial + @@non_commercial
     @@instances = {}
-    @@options = nil
+    @@options = {}
   end
 
-  def self.options
-    @@options ||= all.map { |c| find(c) }.map { |t| [ t.label, t.code ] }
+  def self.options(kind=:all)
+    @@options ||= {}
+    @@options[kind] ||= self.send(kind).map { |c| find(c) }.map { |t| [ t.label, t.code ] }
   end
 
   attr_reader :code
diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb
index ea1855ea8..d270a8696 100644
--- a/app/models/chouette/stop_area.rb
+++ b/app/models/chouette/stop_area.rb
@@ -10,6 +10,7 @@ module Chouette
 
     extend Enumerize
     enumerize :area_type, in: Chouette::AreaType::ALL
+    enumerize :kind, in: %i(commercial non_commercial)
 
     with_options dependent: :destroy do |assoc|
       assoc.has_many :stop_points
@@ -96,6 +97,10 @@ module Chouette
       end
     end
 
+    def local_id
+      id.to_s
+    end
+
     def children_in_depth
       return [] if self.children.empty?
 
@@ -374,5 +379,9 @@ module Chouette
       return nil unless time_zone.present?
       ActiveSupport::TimeZone[time_zone]&.formatted_offset
     end
+
+    def commercial?
+      kind == "commercial"
+    end
   end
 end
diff --git a/app/views/stop_areas/_form.html.slim b/app/views/stop_areas/_form.html.slim
index b2322f73a..699381d50 100644
--- a/app/views/stop_areas/_form.html.slim
+++ b/app/views/stop_areas/_form.html.slim
@@ -7,9 +7,13 @@
         = f.input :id, as: :hidden
         = f.input :name, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.name")}
 
-        = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}}
+        = f.input :kind, as: :radio_buttons, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, item_class: "fooo"
 
-        = f.input :area_type, as: :select, :input_html => {:disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options, :include_blank => false
+        .slave data-master="[name='stop_area[kind]']" data-value="commercial"
+          = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}}
+        - %i(commercial non_commercial).each do |kind|
+          .slave data-master="[name='stop_area[kind]']" data-value=kind
+            = f.input :area_type, as: :select, :input_html => {:disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options(kind), :include_blank => false
 
         .location_info
           h3 = t("stop_areas.stop_area.localisation")
@@ -49,3 +53,5 @@
   .separator
 
   = f.button :submit, t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'stop_area_form'
+
+= javascript_pack_tag "stop_areas/new"
diff --git a/app/views/stop_areas/show.html.slim b/app/views/stop_areas/show.html.slim
index b5ec8ac00..b0896c1e0 100644
--- a/app/views/stop_areas/show.html.slim
+++ b/app/views/stop_areas/show.html.slim
@@ -6,11 +6,11 @@
   .container-fluid
     .row
       .col-lg-6.col-md-6.col-sm-12.col-xs-12
-        - attributes = { t('id_reflex') => @stop_area.get_objectid.short_id,
-            @stop_area.human_attribute_name(:parent) => @stop_area.parent ? link_to(@stop_area.parent.name, stop_area_referential_stop_area_path(@stop_area_referential, @stop_area.parent)) : "-",
-            @stop_area.human_attribute_name(:stop_area_type) => Chouette::AreaType.find(@stop_area.area_type).try(:label),
+        - attributes = { t('id_reflex') => @stop_area.get_objectid.short_id }
+        - attributes.merge!({ @stop_area.human_attribute_name(:parent) => @stop_area.parent ? link_to(@stop_area.parent.name, stop_area_referential_stop_area_path(@stop_area_referential, @stop_area.parent)) : "-" }) if @stop_area.commercial?
+        - attributes.merge!({ @stop_area.human_attribute_name(:stop_area_type) => Chouette::AreaType.find(@stop_area.area_type).try(:label),
             @stop_area.human_attribute_name(:registration_number) => @stop_area.registration_number,
-            }
+            })
         - attributes.merge!(@stop_area.human_attribute_name(:waiting_time) => @stop_area.waiting_time_text) if has_feature?(:stop_area_waiting_time)
         - attributes.merge!({ "Coordonnées" => geo_data(@stop_area, @stop_area_referential),
             @stop_area.human_attribute_name(:zip_code) => @stop_area.zip_code,
diff --git a/config/locales/area_types.en.yml b/config/locales/area_types.en.yml
index 34ec3243d..5d23a6665 100644
--- a/config/locales/area_types.en.yml
+++ b/config/locales/area_types.en.yml
@@ -6,3 +6,9 @@ en:
       zdlp: ZDLp
       zdlr: ZDLr
       lda: LDA
+      gdl: GDL
+      deposit: Deposit
+      border: Border
+      service_area: Service Area
+      relief: Relief point
+      other: Other
diff --git a/config/locales/area_types.fr.yml b/config/locales/area_types.fr.yml
index fd4e1e741..bb249c235 100644
--- a/config/locales/area_types.fr.yml
+++ b/config/locales/area_types.fr.yml
@@ -6,3 +6,9 @@ fr:
       zdlp: ZDLp
       zdlr: ZDLr
       lda: LDA
+      gdl: GDL
+      deposit: Dépôt
+      border: Frontière
+      service_area: Aire de service / Pause
+      relief: Point de releve
+      other: Autre
diff --git a/db/migrate/20180126134944_add_kind_to_stop_areas.rb b/db/migrate/20180126134944_add_kind_to_stop_areas.rb
new file mode 100644
index 000000000..3a4f0a0c8
--- /dev/null
+++ b/db/migrate/20180126134944_add_kind_to_stop_areas.rb
@@ -0,0 +1,5 @@
+class AddKindToStopAreas < ActiveRecord::Migration
+  def change
+    add_column :stop_areas, :kind, :string
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 2c5520110..b2063539b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,13 +11,14 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20180111200406) do
+ActiveRecord::Schema.define(version: 20180126134944) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
-  enable_extension "postgis"
   enable_extension "hstore"
+  enable_extension "postgis"
   enable_extension "unaccent"
+  enable_extension "objectid"
 
   create_table "access_links", id: :bigserial, force: :cascade do |t|
     t.integer  "access_point_id",                        limit: 8
@@ -90,6 +91,8 @@ ActiveRecord::Schema.define(version: 20180111200406) do
     t.integer   "organisation_id", limit: 8
     t.datetime  "created_at"
     t.datetime  "updated_at"
+    t.integer   "int_day_types"
+    t.date      "excluded_dates",                            array: true
   end
 
   add_index "calendars", ["organisation_id"], name: "index_calendars_on_organisation_id", using: :btree
@@ -115,6 +118,7 @@ ActiveRecord::Schema.define(version: 20180111200406) do
     t.datetime "updated_at"
     t.date     "end_date"
     t.string   "date_type"
+    t.string   "mode"
   end
 
   add_index "clean_ups", ["referential_id"], name: "index_clean_ups_on_referential_id", using: :btree
@@ -786,6 +790,7 @@ ActiveRecord::Schema.define(version: 20180111200406) do
     t.datetime "updated_at"
     t.string   "stif_type"
     t.integer  "waiting_time"
+    t.string   "kind"
   end
 
   add_index "stop_areas", ["name"], name: "index_stop_areas_on_name", using: :btree
diff --git a/spec/models/chouette/area_type_spec.rb b/spec/models/chouette/area_type_spec.rb
index 67d218df8..28325dd0a 100644
--- a/spec/models/chouette/area_type_spec.rb
+++ b/spec/models/chouette/area_type_spec.rb
@@ -4,7 +4,9 @@ RSpec.describe Chouette::AreaType do
 
   describe "::ALL" do
     it "includes all supported types" do
-      expect(Chouette::AreaType::ALL).to match_array( %i(zdep zder zdlp zdlr lda gdl) )
+      expect(Chouette::AreaType::ALL).to match_array( %i(zdep zder zdlp zdlr lda gdl deposit border service_area relief other) )
+      expect(Chouette::AreaType::COMMERCIAL).to match_array( %i(zdep zder zdlp zdlr lda gdl) )
+      expect(Chouette::AreaType::NON_COMMERCIAL).to match_array( %i( deposit border service_area relief other) )
     end
   end
 
-- 
cgit v1.2.3
From 05bc96db48a0a84fd2c50e457dc767f88950a9b4 Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 29 Jan 2018 08:45:02 +0100
Subject: Refs #5750 @1h; Manage non-commercial StopAreas
- Add a `kind` attribute
- Hide irrelevant fields in the form
---
 app/assets/stylesheets/modules/_vj_collection.sass  |  3 +++
 app/controllers/stop_areas_controller.rb            |  1 +
 app/controllers/vehicle_journeys_controller.rb      |  2 ++
 app/javascript/helpers/master_slave.coffee          |  8 ++++----
 app/javascript/helpers/stop_area_header_manager.js  |  4 +++-
 app/models/chouette/stop_area.rb                    |  8 ++++++++
 app/policies/stop_area_policy.rb                    |  2 +-
 app/views/stop_areas/_form.html.slim                |  6 +++---
 config/locales/stop_areas.fr.yml                    |  2 ++
 db/migrate/20180126134944_add_kind_to_stop_areas.rb |  1 +
 spec/models/chouette/stop_area_spec.rb              | 10 ++++++++++
 11 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/app/assets/stylesheets/modules/_vj_collection.sass b/app/assets/stylesheets/modules/_vj_collection.sass
index 56769e52b..81c1fe43e 100644
--- a/app/assets/stylesheets/modules/_vj_collection.sass
+++ b/app/assets/stylesheets/modules/_vj_collection.sass
@@ -9,6 +9,9 @@
         position: relative
         padding-left: 25px
 
+        .fa
+          margin-left: 5px
+
         > .headlined
           &:before
             margin-left: -25px
diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb
index 79ffea72e..8e9df7157 100644
--- a/app/controllers/stop_areas_controller.rb
+++ b/app/controllers/stop_areas_controller.rb
@@ -203,6 +203,7 @@ class StopAreasController < ChouetteController
       :url,
       :waiting_time,
       :zip_code,
+      :kind,
     )
   end
 
diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb
index c1762c13e..ed6ba6ed1 100644
--- a/app/controllers/vehicle_journeys_controller.rb
+++ b/app/controllers/vehicle_journeys_controller.rb
@@ -66,6 +66,8 @@ class VehicleJourneysController < ChouetteController
             :city_name => sp.stop_area.try(:city_name),
             :comment => sp.stop_area.try(:comment),
             :area_type => sp.stop_area.try(:area_type),
+            :area_type_i18n => I18n.t(sp.stop_area.try(:area_type), scope: 'area_types.label'),
+            :area_kind => sp.stop_area.try(:kind),
             :stop_area_id => sp.stop_area_id,
             :registration_number => sp.stop_area.try(:registration_number),
             :nearest_topic_name => sp.stop_area.try(:nearest_topic_name),
diff --git a/app/javascript/helpers/master_slave.coffee b/app/javascript/helpers/master_slave.coffee
index 11f6bca7e..4866a55e3 100644
--- a/app/javascript/helpers/master_slave.coffee
+++ b/app/javascript/helpers/master_slave.coffee
@@ -3,16 +3,16 @@ class MasterSlave
     $(selector).find('[data-master]').each (i, slave)->
       $slave = $(slave)
       master = $($slave.data().master)
-      console.log $slave.data().master
-      console.log master
+      console.log $slave
+      console.log $slave.find("input:disabled, select:disabled")
+      $slave.find("input:disabled, select:disabled").attr "data-slave-force-disabled", "true"
       toggle = ->
         val = master.filter(":checked").val() if master.filter("[type=radio]").length > 0
         val ||= master.val()
         selected = val == $slave.data().value
         $slave.toggle selected
-        $slave.find("input, select").attr "disabled", !selected
+        $slave.find("input, select").filter(":not([data-slave-force-disabled])").attr "disabled", !selected
       master.change toggle
       toggle()
-      # $slave.toggle master.val() == $slave.data().value
 
 export default MasterSlave
diff --git a/app/javascript/helpers/stop_area_header_manager.js b/app/javascript/helpers/stop_area_header_manager.js
index c9f397dee..2c820caf9 100644
--- a/app/javascript/helpers/stop_area_header_manager.js
+++ b/app/javascript/helpers/stop_area_header_manager.js
@@ -19,7 +19,7 @@ export default class StopAreaHeaderManager {
       
         
           
@@ -27,6 +27,8 @@ export default class StopAreaHeaderManager {
             {sp.time_zone_formatted_offset && 
                ({sp.time_zone_formatted_offset})
             }
+            {sp.area_kind == 'non_commercial' && 
+            }
           
         
       
diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb
index d270a8696..75a4a34bb 100644
--- a/app/models/chouette/stop_area.rb
+++ b/app/models/chouette/stop_area.rb
@@ -32,6 +32,7 @@ module Chouette
 
     validates_format_of :registration_number, :with => %r{\A[\d\w_\-]+\Z}, :allow_blank => true
     validates_presence_of :name
+    validates_presence_of :kind
     validates_presence_of :latitude, :if => :longitude
     validates_presence_of :longitude, :if => :latitude
     validates_numericality_of :latitude, :less_than_or_equal_to => 90, :greater_than_or_equal_to => -90, :allow_nil => true
@@ -42,6 +43,7 @@ module Chouette
 
     validates_numericality_of :waiting_time, greater_than_or_equal_to: 0, only_integer: true, if: :waiting_time
     validate :parent_area_type_must_be_greater
+    validate :area_type_of_right_kind
 
     def self.nullable_attributes
       [:registration_number, :street_name, :country_code, :fare_code,
@@ -57,6 +59,12 @@ module Chouette
       end
     end
 
+    def area_type_of_right_kind
+      unless Chouette::AreaType.send(self.kind).include?(self.area_type)
+        errors.add(:area_type, I18n.t('stop_areas.errors.incorrect_kind_area_type'))
+      end
+    end
+
     after_update :clean_invalid_access_links
     before_save :coordinates_to_lat_lng
 
diff --git a/app/policies/stop_area_policy.rb b/app/policies/stop_area_policy.rb
index 6db48b702..fd73b7092 100644
--- a/app/policies/stop_area_policy.rb
+++ b/app/policies/stop_area_policy.rb
@@ -3,7 +3,7 @@ class StopAreaPolicy < ApplicationPolicy
     def search_scope scope_name
       scope = resolve
       if scope_name&.to_s == "route_editor"
-        scope = scope.where(area_type: 'zdep') unless user.organisation.has_feature?("route_stop_areas_all_types")
+        scope = scope.where("kind = ? OR area_type = ?", :non_commercial, 'zdep') unless user.organisation.has_feature?("route_stop_areas_all_types")
       end
       scope
     end
diff --git a/app/views/stop_areas/_form.html.slim b/app/views/stop_areas/_form.html.slim
index 699381d50..6b75209b4 100644
--- a/app/views/stop_areas/_form.html.slim
+++ b/app/views/stop_areas/_form.html.slim
@@ -7,13 +7,13 @@
         = f.input :id, as: :hidden
         = f.input :name, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.name")}
 
-        = f.input :kind, as: :radio_buttons, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, item_class: "fooo"
+        = f.input :kind, as: :radio_buttons, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, item_class: "fooo", disabled: !@stop_area.new_record?
 
         .slave data-master="[name='stop_area[kind]']" data-value="commercial"
           = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}}
-        - %i(commercial non_commercial).each do |kind|
+        - %i(non_commercial commercial).each do |kind|
           .slave data-master="[name='stop_area[kind]']" data-value=kind
-            = f.input :area_type, as: :select, :input_html => {:disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options(kind), :include_blank => false
+            = f.input :area_type, as: :select, :input_html => {id: kind, :disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options(kind), :include_blank => false, disabled: !@stop_area.new_record?
 
         .location_info
           h3 = t("stop_areas.stop_area.localisation")
diff --git a/config/locales/stop_areas.fr.yml b/config/locales/stop_areas.fr.yml
index 0095bbe6d..283000960 100644
--- a/config/locales/stop_areas.fr.yml
+++ b/config/locales/stop_areas.fr.yml
@@ -5,6 +5,7 @@ fr:
     errors:
       empty: Aucun stop_area_id
       parent_area_type: ne peut être de type %{area_type}
+      incorrect_kind_area_type: Ce type d'arrêt est invalide pour cette catégorie
     default_geometry_success: "%{count} arrêts édités"
     stop_area:
       no_position: "Pas de position"
@@ -97,6 +98,7 @@ fr:
     attributes:
       stop_area:
         name: "Nom"
+        kind: "Catégorie"
         registration_number: "Numéro d'enregistrement"
         published_name: "Nom public"
         deleted: "Supprimé"
diff --git a/db/migrate/20180126134944_add_kind_to_stop_areas.rb b/db/migrate/20180126134944_add_kind_to_stop_areas.rb
index 3a4f0a0c8..7da227cd9 100644
--- a/db/migrate/20180126134944_add_kind_to_stop_areas.rb
+++ b/db/migrate/20180126134944_add_kind_to_stop_areas.rb
@@ -1,5 +1,6 @@
 class AddKindToStopAreas < ActiveRecord::Migration
   def change
     add_column :stop_areas, :kind, :string
+    Chouette::StopArea.update_all kind: :commmercial
   end
 end
diff --git a/spec/models/chouette/stop_area_spec.rb b/spec/models/chouette/stop_area_spec.rb
index a90e5d816..32ee5a3a6 100644
--- a/spec/models/chouette/stop_area_spec.rb
+++ b/spec/models/chouette/stop_area_spec.rb
@@ -10,10 +10,20 @@ describe Chouette::StopArea, :type => :model do
 
   it { should belong_to(:stop_area_referential) }
   it { should validate_presence_of :name }
+  it { should validate_presence_of :kind }
   it { should validate_numericality_of :latitude }
   it { should validate_numericality_of :longitude }
   it { is_expected.to be_versioned }
 
+  describe "#area_type" do
+    it "should validate the value is correct regarding to the kind" do
+      expect(build(:stop_area, kind: :commercial, area_type: :gdl)).to be_valid
+      expect(build(:stop_area, kind: :non_commercial, area_type: :relief)).to be_valid
+      expect(build(:stop_area, kind: :commercial, area_type: :relief)).to_not be_valid
+      expect(build(:stop_area, kind: :non_commercial, area_type: :gdl)).to_not be_valid
+    end
+  end
+
   # describe ".latitude" do
   #   it "should accept -90 value" do
   #     subject = create :stop_area, :area_type => "BoardingPosition"
-- 
cgit v1.2.3
From ddd83906ce4fab3d6dce0c404ec39c3b500ba96f Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 29 Jan 2018 10:32:05 +0100
Subject: Refs #5750; Add a validation on VehicleJourneys
Ensure a time is set for all non-commercial stops
---
 app/assets/stylesheets/modules/_vj_collection.sass |  3 ++
 app/javascript/vehicle_journeys/actions/index.js   | 26 ++++++++++++++
 .../components/SaveVehicleJourneys.js              |  2 +-
 .../vehicle_journeys/components/VehicleJourney.js  |  3 ++
 .../vehicle_journeys/components/VehicleJourneys.js |  2 +-
 .../containers/SaveVehicleJourneys.js              |  3 ++
 .../vehicle_journeys/reducers/vehicleJourneys.js   |  2 ++
 app/views/vehicle_journeys/show.rabl               |  1 +
 spec/javascript/vehicle_journeys/actions_spec.js   | 41 ++++++++++++++++++++++
 9 files changed, 81 insertions(+), 2 deletions(-)
diff --git a/app/assets/stylesheets/modules/_vj_collection.sass b/app/assets/stylesheets/modules/_vj_collection.sass
index 81c1fe43e..d99c67bd7 100644
--- a/app/assets/stylesheets/modules/_vj_collection.sass
+++ b/app/assets/stylesheets/modules/_vj_collection.sass
@@ -116,6 +116,9 @@
           margin-left: 5px
 
       &.has-error
+        .errors
+          color: $red
+          font-size: 0.8em
         &:before
           content: ''
           position: absolute
diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js
index 2675328e3..b01158212 100644
--- a/app/javascript/vehicle_journeys/actions/index.js
+++ b/app/javascript/vehicle_journeys/actions/index.js
@@ -380,6 +380,32 @@ const actions = {
         }
       })
   },
+
+  validate : (dispatch, vehicleJourneys, next) => {
+    let valid = true
+    let vj, vjas
+    for (vj of vehicleJourneys){
+      vj.errors = false
+      for(vjas of vj.vehicle_journey_at_stops){
+        vjas.errors = null
+        if (vjas.area_kind == "non_commercial" && parseInt(vjas.departure_time.hour) == 0 && parseInt(vjas.departure_time.minute) == 0){
+          vjas.errors = "Champ requis"
+          vj.errors = true
+          valid = false
+        }
+      }
+    }
+    dispatch(actions.didValidateVehicleJourneys(vehicleJourneys))
+    if(valid){
+      actions.submitVehicleJourneys(dispatch, vehicleJourneys, next)
+    }
+  },
+
+  didValidateVehicleJourneys : (vehicleJourneys) => ({
+    type: 'DID_VALIDATE_VEHICLE_JOURNEYS',
+    vehicleJourneys
+  }),
+
   submitVehicleJourneys : (dispatch, state, next) => {
     dispatch(actions.fetchingApi())
     let urlJSON = window.location.pathname + "_collection.json"
diff --git a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js
index 6e94b04a3..fb921df9c 100644
--- a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js
@@ -13,7 +13,7 @@ export default class SaveVehicleJourneys extends SaveButton{
   }
 
   submitForm(){
-    this.props.onSubmitVehicleJourneys(this.props.dispatch, this.props.vehicleJourneys)
+    this.props.validate(this.props.vehicleJourneys, this.props.dispatch)
   }
 }
 
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js
index d240757a3..2b5783dda 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js
@@ -153,6 +153,9 @@ export default class VehicleJourney extends Component {
                       />
                   
                 
+                {vj.errors && 
+                  {vj.errors}
+                
}
             
           
         )}
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
index b188962c2..256ca81f9 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
@@ -89,7 +89,7 @@ export default class VehicleJourneys extends Component {
               
             )}
 
-            { _.some(this.props.vehicleJourneys, 'errors') && (
+            { this.props.vehicleJourneys.errors && this.props.vehicleJourneys.errors.length && _.some(this.props.vehicleJourneys, 'errors') && (
               
                 Erreur : 
                 {this.props.vehicleJourneys.map((vj, index) =>
diff --git a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js
index f5f879ed8..3daf831f8 100644
--- a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js
@@ -23,6 +23,9 @@ const mapDispatchToProps = (dispatch) => {
     },
     onSubmitVehicleJourneys: (next, state) => {
       actions.submitVehicleJourneys(dispatch, state, next)
+    },
+    validate: (state) =>{
+      actions.validate(dispatch, state)
     }
   }
 }
diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
index ae45993a8..1a15ec46d 100644
--- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
@@ -273,6 +273,8 @@ export default function vehicleJourneys(state = [], action) {
           return vj
         }
       })
+    case 'DID_VALIDATE_VEHICLE_JOURNEYS':
+      return [...action.vehicleJourneys]
     default:
       return state
   }
diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl
index fc65e6cb6..dca0866b3 100644
--- a/app/views/vehicle_journeys/show.rabl
+++ b/app/views/vehicle_journeys/show.rabl
@@ -45,6 +45,7 @@ child(:vehicle_journey_at_stops_matrix, :object_root => false) do |vehicle_stops
     end
 
     node(:dummy) { vehicle_stop.dummy }
+    node(:area_kind) { vehicle_stop.stop_point.stop_area.kind }
 
     node(:stop_area_object_id) do
       vehicle_stop.stop_point.stop_area.objectid
diff --git a/spec/javascript/vehicle_journeys/actions_spec.js b/spec/javascript/vehicle_journeys/actions_spec.js
index 9515b57f2..d486c9af8 100644
--- a/spec/javascript/vehicle_journeys/actions_spec.js
+++ b/spec/javascript/vehicle_journeys/actions_spec.js
@@ -37,6 +37,47 @@ describe('when clicking on add button', () => {
     expect(actions.openCreateModal()).toEqual(expectedAction)
   })
 })
+describe('when validating the form', () => {
+  it('should check that non-commercial stops have passing time', () => {
+    let state = [{
+      vehicle_journey_at_stops: [{
+        area_kind: "non_commercial",
+        departure_time: {
+          hour: "00",
+          minute: "00"
+        }
+      }]
+    }]
+
+    expect(actions.validate(dispatch, state)).toEqual(false)
+
+    state = [{
+      vehicle_journey_at_stops: [{
+        area_kind: "non_commercial",
+        departure_time: {
+          hour: "00",
+          minute: "01"
+        }
+      }]
+    }]
+
+    expect(actions.validate(dispatch, state)).toEqual(true)
+  })
+
+  it('should not check that commercial stops', () => {
+    let state = [{
+      vehicle_journey_at_stops: [{
+        area_kind: "commercial",
+        departure_time: {
+          hour: "00",
+          minute: "00"
+        }
+      }]
+    }]
+
+    expect(actions.validate(dispatch, state)).toEqual(true)
+  })
+})
 describe('when using select2 to pick a journey pattern', () => {
   it('should create an action to select a journey pattern inside modal', () => {
     let selectedJP = {
-- 
cgit v1.2.3
From 0101f0ca0a7354420118b0470532f804674edc34 Mon Sep 17 00:00:00 2001
From: Zog
Date: Wed, 31 Jan 2018 10:46:02 +0100
Subject: Refs #5750; Fix validation
---
 app/controllers/stop_areas_controller.rb            | 2 +-
 app/models/chouette/stop_area.rb                    | 3 ++-
 app/views/stop_areas/_form.html.slim                | 3 +--
 db/migrate/20180126134944_add_kind_to_stop_areas.rb | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb
index 8e9df7157..8d424b8d1 100644
--- a/app/controllers/stop_areas_controller.rb
+++ b/app/controllers/stop_areas_controller.rb
@@ -97,7 +97,7 @@ class StopAreasController < ChouetteController
     edit! do
       stop_area.position ||= stop_area.default_position
       map.editable = true
-   end
+    end
   end
 
   def destroy
diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb
index 75a4a34bb..ad42d54ae 100644
--- a/app/models/chouette/stop_area.rb
+++ b/app/models/chouette/stop_area.rb
@@ -60,7 +60,8 @@ module Chouette
     end
 
     def area_type_of_right_kind
-      unless Chouette::AreaType.send(self.kind).include?(self.area_type)
+
+      unless Chouette::AreaType.send(self.kind).map(&:to_s).include?(self.area_type)
         errors.add(:area_type, I18n.t('stop_areas.errors.incorrect_kind_area_type'))
       end
     end
diff --git a/app/views/stop_areas/_form.html.slim b/app/views/stop_areas/_form.html.slim
index 6b75209b4..aa156f7bd 100644
--- a/app/views/stop_areas/_form.html.slim
+++ b/app/views/stop_areas/_form.html.slim
@@ -6,8 +6,7 @@
         /= @map.to_html
         = f.input :id, as: :hidden
         = f.input :name, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.name")}
-
-        = f.input :kind, as: :radio_buttons, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, item_class: "fooo", disabled: !@stop_area.new_record?
+        = f.input :kind, as: :radio_buttons, checked: @stop_area.kind, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, disabled: !@stop_area.new_record?
 
         .slave data-master="[name='stop_area[kind]']" data-value="commercial"
           = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}}
diff --git a/db/migrate/20180126134944_add_kind_to_stop_areas.rb b/db/migrate/20180126134944_add_kind_to_stop_areas.rb
index 7da227cd9..08f54a6c5 100644
--- a/db/migrate/20180126134944_add_kind_to_stop_areas.rb
+++ b/db/migrate/20180126134944_add_kind_to_stop_areas.rb
@@ -1,6 +1,6 @@
 class AddKindToStopAreas < ActiveRecord::Migration
   def change
     add_column :stop_areas, :kind, :string
-    Chouette::StopArea.update_all kind: :commmercial
+    Chouette::StopArea.where.not(kind: :non_commercial).update_all kind: :commercial
   end
 end
-- 
cgit v1.2.3
From bb62bc2028f142e953035680b2483ee6029711ae Mon Sep 17 00:00:00 2001
From: Zog
Date: Wed, 31 Jan 2018 11:14:23 +0100
Subject: Disable immature feature
---
 app/javascript/packs/referential_lines/show.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js
index 99c5072ef..542188018 100644
--- a/app/javascript/packs/referential_lines/show.js
+++ b/app/javascript/packs/referential_lines/show.js
@@ -6,5 +6,5 @@ routes = JSON.parse(decodeURIComponent(routes))
 
 var map = new RoutesMap('routes_map')
 map.addRoutes(routes)
-map.addRoutesLabels()
+// map.addRoutesLabels()
 map.fitZoom()
-- 
cgit v1.2.3
From c463c3a950246c4c2660ce7df1c1ea8f2acbe578 Mon Sep 17 00:00:00 2001
From: Zog
Date: Wed, 31 Jan 2018 11:17:02 +0100
Subject: Refs #5750; Remove useless validation
---
 app/javascript/vehicle_journeys/actions/index.js | 17 +----------------
 1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js
index b01158212..4a4ec371d 100644
--- a/app/javascript/vehicle_journeys/actions/index.js
+++ b/app/javascript/vehicle_journeys/actions/index.js
@@ -382,23 +382,8 @@ const actions = {
   },
 
   validate : (dispatch, vehicleJourneys, next) => {
-    let valid = true
-    let vj, vjas
-    for (vj of vehicleJourneys){
-      vj.errors = false
-      for(vjas of vj.vehicle_journey_at_stops){
-        vjas.errors = null
-        if (vjas.area_kind == "non_commercial" && parseInt(vjas.departure_time.hour) == 0 && parseInt(vjas.departure_time.minute) == 0){
-          vjas.errors = "Champ requis"
-          vj.errors = true
-          valid = false
-        }
-      }
-    }
     dispatch(actions.didValidateVehicleJourneys(vehicleJourneys))
-    if(valid){
-      actions.submitVehicleJourneys(dispatch, vehicleJourneys, next)
-    }
+    actions.submitVehicleJourneys(dispatch, vehicleJourneys, next)
   },
 
   didValidateVehicleJourneys : (vehicleJourneys) => ({
-- 
cgit v1.2.3