Add type champs "Address" plug at the BAN
This commit is contained in:
parent
35a07aec87
commit
23ab25396f
18 changed files with 2804 additions and 13 deletions
|
@ -29,8 +29,7 @@
|
|||
//= require franceconnect
|
||||
//= require bootstrap-wysihtml5
|
||||
//= require bootstrap-wysihtml5/locales/fr-FR
|
||||
|
||||
|
||||
//= require typeahead.bundle
|
||||
|
||||
$(document).on('page:load', scroll_to);
|
||||
$(document).ready(scroll_to);
|
||||
|
|
|
@ -13,6 +13,8 @@ function action_type_de_champs() {
|
|||
|
||||
toggleErrorClass(this, validatePhone(val));
|
||||
});
|
||||
|
||||
address_type_init();
|
||||
}
|
||||
|
||||
function toggleErrorClass(node, boolean) {
|
||||
|
@ -34,4 +36,28 @@ function validateEmail(email) {
|
|||
|
||||
function validateInput(input, regex) {
|
||||
return regex.test(input);
|
||||
}
|
||||
|
||||
function address_type_init() {
|
||||
|
||||
display = 'label';
|
||||
|
||||
var bloodhound = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace(display),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
|
||||
remote: {
|
||||
url: '/ban/search?request=%QUERY',
|
||||
wildcard: '%QUERY'
|
||||
}
|
||||
});
|
||||
bloodhound.initialize();
|
||||
|
||||
$("input[type='address']").typeahead({
|
||||
minLength: 1
|
||||
}, {
|
||||
display: display,
|
||||
source: bloodhound,
|
||||
limit: 5
|
||||
});
|
||||
}
|
|
@ -21,6 +21,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
.type_champ-address {
|
||||
@extend .col-md-6;
|
||||
@extend .col-lg-6;
|
||||
|
||||
input[type='address'] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.type_champ-email {
|
||||
@extend .col-md-4;
|
||||
@extend .col-lg-4;
|
||||
|
|
35
app/assets/stylesheets/typeahead.scss
Normal file
35
app/assets/stylesheets/typeahead.scss
Normal file
|
@ -0,0 +1,35 @@
|
|||
.tt-menu {
|
||||
width: 555px;
|
||||
padding: 8px 0;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
|
||||
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
.tt-suggestion {
|
||||
padding: 3px 20px;
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.twitter-typeahead {
|
||||
width: 555px;
|
||||
}
|
||||
|
||||
.tt-suggestion:hover {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
background-color: #0097cf;
|
||||
}
|
||||
|
||||
.tt-suggestion.tt-cursor {
|
||||
color: #fff;
|
||||
background-color: #0097cf;
|
||||
|
||||
}
|
9
app/controllers/ban/search_controller.rb
Normal file
9
app/controllers/ban/search_controller.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
class Ban::SearchController < ApplicationController
|
||||
def get
|
||||
request = params[:request]
|
||||
|
||||
render json: Carto::Bano::AddressRetriever.new(request).list.inject([]) {
|
||||
|acc, value| acc.push({label: value})
|
||||
}.to_json
|
||||
end
|
||||
end
|
|
@ -7,4 +7,9 @@ class Champ < ActiveRecord::Base
|
|||
def mandatory?
|
||||
mandatory
|
||||
end
|
||||
|
||||
def data_provide
|
||||
return 'datepicker' if type_champ == 'datetime'
|
||||
return 'typeahead' if type_champ == 'address'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
class TypeDeChamp < ActiveRecord::Base
|
||||
enum type_champs: {text: 'text',
|
||||
email: 'email',
|
||||
phone: 'phone',
|
||||
civilite: 'civilite',
|
||||
textarea: 'textarea',
|
||||
datetime: 'datetime',
|
||||
number: 'number',
|
||||
checkbox: 'checkbox'
|
||||
enum type_champs: {
|
||||
text: 'text',
|
||||
textarea: 'textarea',
|
||||
datetime: 'datetime',
|
||||
number: 'number',
|
||||
checkbox: 'checkbox',
|
||||
civilite: 'civilite',
|
||||
email: 'email',
|
||||
phone: 'phone',
|
||||
address: 'address'
|
||||
}
|
||||
|
||||
belongs_to :procedure
|
||||
|
|
|
@ -34,5 +34,5 @@
|
|||
id: "champs_#{champ.id}",
|
||||
value: champ.value,
|
||||
type: champ.type_champ,
|
||||
'data-provide' => ('datepicker' if champ.type_champ == 'datetime'),
|
||||
'data-provide' => champ.data_provide,
|
||||
'data-date-format' => ('dd/mm/yyyy' if champ.type_champ == 'datetime')}
|
|
@ -108,6 +108,10 @@ Rails.application.routes.draw do
|
|||
resources :gestionnaires, only: [:index, :create, :destroy]
|
||||
end
|
||||
|
||||
namespace :ban do
|
||||
get 'search' => 'search#get'
|
||||
end
|
||||
|
||||
get 'backoffice' => 'backoffice#index'
|
||||
|
||||
namespace :backoffice do
|
||||
|
|
36
lib/carto/bano/address_retriever.rb
Normal file
36
lib/carto/bano/address_retriever.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
module Carto
|
||||
module Bano
|
||||
# input : address
|
||||
# output : Array List label address
|
||||
class AddressRetriever
|
||||
def initialize(address)
|
||||
@address = address
|
||||
end
|
||||
|
||||
def list
|
||||
@list ||= convert_driver_result_to_full_address
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def driver
|
||||
@driver ||= Carto::Bano::Driver.new @address, 5
|
||||
end
|
||||
|
||||
def convert_driver_result_to_full_address
|
||||
result = JSON.parse(driver.call)
|
||||
|
||||
if result['features'].size == 0
|
||||
Rails.logger.error "unable to find location for address #{@address}"
|
||||
return []
|
||||
end
|
||||
|
||||
result['features'].inject([]) do |acc, feature|
|
||||
acc.push feature['properties']['label']
|
||||
end
|
||||
rescue TypeError, JSON::ParserError
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,12 +3,15 @@ module Carto
|
|||
# input : string (address)
|
||||
# output : json
|
||||
class Driver
|
||||
def initialize(address)
|
||||
def initialize(address, limit = 1)
|
||||
@address = address
|
||||
@limit = limit
|
||||
end
|
||||
|
||||
def call
|
||||
RestClient.get api_url, params: { q: @address, limit: 1 }
|
||||
RestClient.get api_url, params: { q: @address, limit: @limit }
|
||||
rescue RestClient::ServiceUnavailable
|
||||
nil
|
||||
end
|
||||
|
||||
def api_url
|
||||
|
|
16
spec/controllers/ban/search_controller_spec.rb
Normal file
16
spec/controllers/ban/search_controller_spec.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Ban::SearchController, type: :controller do
|
||||
describe '#GET' do
|
||||
|
||||
let (:request) { '' }
|
||||
|
||||
before do
|
||||
stub_request(:get, "http://api-adresse.data.gouv.fr/search?limit=5&q=").
|
||||
to_return(:status => 200, :body => 'Missing query', :headers => {})
|
||||
get :get, request: request
|
||||
end
|
||||
|
||||
it { expect(response.status).to eq 200 }
|
||||
end
|
||||
end
|
4
spec/factories/champ.rb
Normal file
4
spec/factories/champ.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
FactoryGirl.define do
|
||||
factory :champ do
|
||||
end
|
||||
end
|
44
spec/lib/carto/bano/address_retriever_spec.rb
Normal file
44
spec/lib/carto/bano/address_retriever_spec.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Carto::Bano::AddressRetriever do
|
||||
describe '#list' do
|
||||
let(:request) { 'Paris' }
|
||||
let(:response) { File.open('spec/support/files/ban_address_search.json') }
|
||||
let(:status) { 200 }
|
||||
|
||||
subject { described_class.new(request).list }
|
||||
|
||||
before do
|
||||
stub_request(:get, "http://api-adresse.data.gouv.fr/search?&q=#{request}&limit=5")
|
||||
.to_return(status: status, body: response, headers: {})
|
||||
end
|
||||
|
||||
context 'when address return a list of address' do
|
||||
it { expect(subject.size).to eq 5 }
|
||||
it { is_expected.to be_an_instance_of Array }
|
||||
end
|
||||
|
||||
context 'when address return an empty list' do
|
||||
let(:response) { File.open('spec/support/files/ban_address_search_no_result.json') }
|
||||
|
||||
it { expect(subject.size).to eq 0 }
|
||||
it { is_expected.to be_an_instance_of Array }
|
||||
end
|
||||
|
||||
context 'when BAN is unavailable' do
|
||||
let(:status) { 503 }
|
||||
let(:response) { '' }
|
||||
|
||||
it { expect(subject.size).to eq 0 }
|
||||
it { is_expected.to be_an_instance_of Array }
|
||||
end
|
||||
|
||||
context 'when request is empty' do
|
||||
let(:response) { 'Missing query' }
|
||||
let(:request) { '' }
|
||||
|
||||
it { expect(subject.size).to eq 0 }
|
||||
it { is_expected.to be_an_instance_of Array }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,4 +15,26 @@ describe Champ do
|
|||
it { is_expected.to delegate_method(:type_champ).to(:type_de_champ) }
|
||||
it { is_expected.to delegate_method(:order_place).to(:type_de_champ) }
|
||||
end
|
||||
|
||||
describe 'data_provide' do
|
||||
let(:champ) { create :champ }
|
||||
|
||||
subject { champ.data_provide }
|
||||
|
||||
context 'when type_champ is datetime' do
|
||||
before do
|
||||
champ.type_de_champ = create :type_de_champ, type_champ: 'datetime'
|
||||
end
|
||||
|
||||
it { is_expected.to eq 'datepicker' }
|
||||
end
|
||||
|
||||
context 'when type_champ is address' do
|
||||
before do
|
||||
champ.type_de_champ = create :type_de_champ, type_champ: 'address'
|
||||
end
|
||||
|
||||
it { is_expected.to eq 'typeahead' }
|
||||
end
|
||||
end
|
||||
end
|
117
spec/support/files/ban_address_search.json
Normal file
117
spec/support/files/ban_address_search.json
Normal file
|
@ -0,0 +1,117 @@
|
|||
{
|
||||
"limit": 5,
|
||||
"attribution": "BAN",
|
||||
"version": "draft",
|
||||
"licence": "ODbL 1.0",
|
||||
"query": "Paris",
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
2.3469,
|
||||
48.8589
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"adm_weight": "6",
|
||||
"citycode": "75056",
|
||||
"name": "Paris",
|
||||
"city": "Paris",
|
||||
"postcode": "75000",
|
||||
"context": "75, \u00cele-de-France",
|
||||
"score": 1.0,
|
||||
"label": "Paris",
|
||||
"id": "75056",
|
||||
"type": "city",
|
||||
"population": "2244"
|
||||
},
|
||||
"type": "Feature"
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
4.366801,
|
||||
44.425528
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"citycode": "07330",
|
||||
"postcode": "07150",
|
||||
"name": "Paris",
|
||||
"id": "07330_B095_bd3524",
|
||||
"context": "07, Ard\u00e8che, Rh\u00f4ne-Alpes",
|
||||
"score": 0.8291454545454544,
|
||||
"label": "Paris 07150 Vallon-Pont-d'Arc",
|
||||
"city": "Vallon-Pont-d'Arc",
|
||||
"type": "locality"
|
||||
},
|
||||
"type": "Feature"
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
3.564293,
|
||||
45.766413
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"citycode": "63125",
|
||||
"postcode": "63120",
|
||||
"name": "Paris",
|
||||
"city": "Courpi\u00e8re",
|
||||
"context": "63, Puy-de-D\u00f4me, Auvergne",
|
||||
"score": 0.8255363636363636,
|
||||
"label": "Paris 63120 Courpi\u00e8re",
|
||||
"id": "63125_B221_03549b",
|
||||
"type": "locality"
|
||||
},
|
||||
"type": "Feature"
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
1.550208,
|
||||
44.673592
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"citycode": "46138",
|
||||
"postcode": "46240",
|
||||
"name": "PARIS (Vaillac)",
|
||||
"city": "C\u0153ur de Causse",
|
||||
"context": "46, Lot, Midi-Pyr\u00e9n\u00e9es",
|
||||
"score": 0.824090909090909,
|
||||
"label": "PARIS (Vaillac) 46240 C\u0153ur de Causse",
|
||||
"id": "46138_XXXX_6ee4ec",
|
||||
"type": "street"
|
||||
},
|
||||
"type": "Feature"
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-0.526884,
|
||||
43.762253
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"citycode": "40282",
|
||||
"postcode": "40500",
|
||||
"name": "Paris",
|
||||
"city": "Saint-Sever",
|
||||
"context": "40, Landes, Aquitaine",
|
||||
"score": 0.8236181818181818,
|
||||
"label": "Paris 40500 Saint-Sever",
|
||||
"id": "40282_B237_2364e3",
|
||||
"type": "locality"
|
||||
},
|
||||
"type": "Feature"
|
||||
}
|
||||
]
|
||||
}
|
9
spec/support/files/ban_address_search_no_result.json
Normal file
9
spec/support/files/ban_address_search_no_result.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"limit": 5,
|
||||
"attribution": "BAN",
|
||||
"version": "draft",
|
||||
"licence": "ODbL 1.0",
|
||||
"query": "Paris",
|
||||
"type": "FeatureCollection",
|
||||
"features": []
|
||||
}
|
2451
vendor/assets/javascripts/typeahead.bundle.js
vendored
Normal file
2451
vendor/assets/javascripts/typeahead.bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue