From 28b739feb955d11fee6fed243d99a9735f7b324b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Gaya?= <sebastien.gaya@gmail.com>
Date: Mon, 24 Oct 2022 12:03:19 +0200
Subject: [PATCH] create orga from extranet

---
 Gemfile                                       |  2 ++
 Gemfile.lock                                  |  6 ++++++
 app/assets/javascripts/application.js         |  1 +
 app/assets/javascripts/extranet.js            | 16 ++++++++++++++
 .../javascripts/extranet/experiences.js       | 18 ++++++++++++++++
 .../_default/components/_autocomplete.sass    | 12 +++++++++++
 .../extranet/experiences_controller.rb        |  2 +-
 .../extranet/organizations_controller.rb      |  4 ++--
 app/models/university/organization.rb         |  8 +++++++
 app/models/university/person/experience.rb    | 21 +++++++++++++++++++
 app/views/extranet/experiences/_form.html.erb | 17 ++++++++++++---
 .../extranet/layouts/application.html.erb     |  2 +-
 .../organizations/search.json.jbuilder        |  7 +++----
 config/locales/extranet/fr.yml                |  1 +
 14 files changed, 106 insertions(+), 11 deletions(-)
 create mode 100644 app/assets/javascripts/extranet.js
 create mode 100644 app/assets/javascripts/extranet/experiences.js
 create mode 100644 app/assets/stylesheets/extranet/_default/components/_autocomplete.sass

diff --git a/Gemfile b/Gemfile
index 11caafd9a..a17a1b4fe 100644
--- a/Gemfile
+++ b/Gemfile
@@ -30,6 +30,7 @@ gem 'hash_dot'
 gem 'image_processing'
 gem 'jbuilder'
 gem 'jquery-rails'
+gem "jquery-ui-rails", "~> 6.0.1"
 gem 'kamifusen'#, path: '../kamifusen'
 gem 'kaminari'
 gem 'mini_magick'
@@ -39,6 +40,7 @@ gem 'omniauth-saml', '~> 2.0'
 gem 'pg', '~> 1.1'
 gem 'puma'
 gem 'rails', '~> 6.1'
+gem "rails-autocomplete", "~> 2.0"
 gem 'rails-i18n'
 gem 'roo', "~> 2.9"
 gem 'sanitize'
diff --git a/Gemfile.lock b/Gemfile.lock
index 2de186e65..cacb477a9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -237,6 +237,8 @@ GEM
       rails-dom-testing (>= 1, < 3)
       railties (>= 4.2.0)
       thor (>= 0.14, < 2.0)
+    jquery-ui-rails (6.0.1)
+      railties (>= 3.2.16)
     js_cookie_rails (2.2.0)
       railties (>= 3.1)
     json (2.6.2)
@@ -351,6 +353,8 @@ GEM
       bundler (>= 1.15.0)
       railties (= 6.1.7)
       sprockets-rails (>= 2.0.0)
+    rails-autocomplete (2.0.1)
+      rails (>= 4.0)
     rails-dom-testing (2.0.3)
       activesupport (>= 4.2.0)
       nokogiri (>= 1.6)
@@ -516,6 +520,7 @@ DEPENDENCIES
   image_processing
   jbuilder
   jquery-rails
+  jquery-ui-rails (~> 6.0.1)
   kamifusen
   kaminari
   listen (~> 3.3)
@@ -527,6 +532,7 @@ DEPENDENCIES
   puma
   rack-mini-profiler (~> 2.0)
   rails (~> 6.1)
+  rails-autocomplete (~> 2.0)
   rails-i18n
   roo (~> 2.9)
   sanitize
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 3dba7831c..19545a0bc 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -9,6 +9,7 @@
 //= require simple_form_bs5_file_input
 //= require summernote/summernote-bs5
 //= require gdpr/cookie_consent
+//= require autocomplete-rails
 //= require_tree ./application/plugins
 //= require_self
 
diff --git a/app/assets/javascripts/extranet.js b/app/assets/javascripts/extranet.js
new file mode 100644
index 000000000..ca7451c78
--- /dev/null
+++ b/app/assets/javascripts/extranet.js
@@ -0,0 +1,16 @@
+//= require activestorage
+//= require popper
+//= require bootstrap-sprockets
+//= require jquery3
+//= require jquery-ui/widgets/autocomplete
+//= require jquery_ujs
+//= require cropperjs/dist/cropper
+//= require jquery-cropper/dist/jquery-cropper
+//= require simple_form_password_with_hints
+//= require simple_form_bs5_file_input
+//= require summernote/summernote-bs5
+//= require gdpr/cookie_consent
+//= require autocomplete-rails
+//= require_tree ./application/plugins
+//= require_tree ./extranet
+//= require_self
diff --git a/app/assets/javascripts/extranet/experiences.js b/app/assets/javascripts/extranet/experiences.js
new file mode 100644
index 000000000..f00ced3d8
--- /dev/null
+++ b/app/assets/javascripts/extranet/experiences.js
@@ -0,0 +1,18 @@
+/*global $ */
+$(function () {
+    'use strict';
+    var setAutocompleteTargetValue = function (targetId, value) {
+        var targetInput = document.querySelector(targetId);
+        if (targetInput) {
+            targetInput.value = value;
+        }
+    };
+
+    $('input.autocomplete')
+        .on('input', function ($event) {
+            setAutocompleteTargetValue($event.target.dataset.autocompleteTarget, '');
+        })
+        .on('railsAutocomplete.select', function ($event, data) {
+            setAutocompleteTargetValue($event.target.dataset.autocompleteTarget, data.item.id);
+        });
+});
diff --git a/app/assets/stylesheets/extranet/_default/components/_autocomplete.sass b/app/assets/stylesheets/extranet/_default/components/_autocomplete.sass
new file mode 100644
index 000000000..f3482d36e
--- /dev/null
+++ b/app/assets/stylesheets/extranet/_default/components/_autocomplete.sass
@@ -0,0 +1,12 @@
+.ui-autocomplete
+    list-style: none
+    padding: 0
+    max-width: 400px
+    .ui-menu-item
+        background: #F6F6F6
+        border-bottom: 1px solid #999999
+        cursor: pointer
+        .ui-menu-item-wrapper
+            padding: 10px
+            &.ui-state-active
+                background: #D4D4D4
\ No newline at end of file
diff --git a/app/controllers/extranet/experiences_controller.rb b/app/controllers/extranet/experiences_controller.rb
index e7c16fae0..2697cc7f8 100644
--- a/app/controllers/extranet/experiences_controller.rb
+++ b/app/controllers/extranet/experiences_controller.rb
@@ -34,7 +34,7 @@ class Extranet::ExperiencesController < Extranet::ApplicationController
 
   def experience_params
     params.require(:university_person_experience)
-          .permit(:description, :from_year, :to_year, :organization_id)
+          .permit(:description, :from_year, :to_year, :organization_id, :organization_name)
   end
 
   def breadcrumb
diff --git a/app/controllers/extranet/organizations_controller.rb b/app/controllers/extranet/organizations_controller.rb
index acf9b9b2f..d974426c2 100644
--- a/app/controllers/extranet/organizations_controller.rb
+++ b/app/controllers/extranet/organizations_controller.rb
@@ -14,8 +14,8 @@ class Extranet::OrganizationsController < Extranet::ApplicationController
 
   def search
     @term = params[:term].to_s
-    @organizations = current_extranet.organizations
-                                      .for_search_term(@term)
+    @organizations = current_university.organizations
+                                      .search_by_siren_or_name(@term)
                                       .ordered
   end
 
diff --git a/app/models/university/organization.rb b/app/models/university/organization.rb
index 46d1f7b0c..a7cd539fc 100644
--- a/app/models/university/organization.rb
+++ b/app/models/university/organization.rb
@@ -38,6 +38,8 @@ class University::Organization < ApplicationRecord
   include WithSlug
   include WithBlocks
 
+  attr_accessor :created_from_extranet
+
   has_many :experiences,
            class_name: 'University::Person::Experience'
 
@@ -64,6 +66,12 @@ class University::Organization < ApplicationRecord
       unaccent(university_organizations.url) ILIKE unaccent(:term)
     ", term: "%#{sanitize_sql_like(term)}%")
   }
+  scope :search_by_siren_or_name, -> (term) {
+    where("
+      unaccent(university_organizations.siren) ILIKE unaccent(:term) OR
+      unaccent(university_organizations.name) ILIKE unaccent(:term)
+    ", term: "%#{sanitize_sql_like(term)}%")
+  }
 
   validates_presence_of :name
 
diff --git a/app/models/university/person/experience.rb b/app/models/university/person/experience.rb
index 10e597629..5b5ec61ad 100644
--- a/app/models/university/person/experience.rb
+++ b/app/models/university/person/experience.rb
@@ -27,13 +27,34 @@
 class University::Person::Experience < ApplicationRecord
   include WithUniversity
 
+  attr_accessor :organization_name
+
   belongs_to :person
   belongs_to :organization, class_name: "University::Organization"
 
+  before_validation :create_organization_if_needed
+
   scope :ordered, -> { order(from_year: :desc)}
 
   def to_s
     persisted?  ? "#{description}"
                 : self.class.human_attribute_name('new')
   end
+
+  def organization_name
+    @organization_name || organization&.name
+  end
+
+  private
+
+  def create_organization_if_needed
+    if organization.nil? && organization_name.present?
+      self.organization_name = self.organization_name.strip
+      self.organization = university.organizations
+                          .where("name ILIKE ?", organization_name)
+                          .or(university.organizations.where(siren: organization_name)).first_or_create do |organization|
+        organization.created_from_extranet = true
+      end
+    end
+  end
 end
diff --git a/app/views/extranet/experiences/_form.html.erb b/app/views/extranet/experiences/_form.html.erb
index 77d2a7099..d176869c7 100644
--- a/app/views/extranet/experiences/_form.html.erb
+++ b/app/views/extranet/experiences/_form.html.erb
@@ -12,9 +12,20 @@
       </div>
     </div>
     <div class="col-lg-6">
-      <%= f.association :organization,
-                        include_blank: false,
-                        collection: current_extranet.organizations.ordered %>
+      <%= f.input :organization_name,
+                  label: University::Organization.model_name.human,
+                  as: :autocomplete,
+                  url: search_university_organizations_path,
+                  placeholder: t("extranet.experiences.search_organization"),
+                  input_html: {
+                    data: {
+                      "showNoMatches": "false",
+                      "autocomplete-target": "#university_person_experience_organization_id"
+                    },
+                    autocomplete: 'off',
+                    role: 'presentation'
+                  } %>
+      <%= f.hidden_field :organization_id %>
     </div>
   </div>
   <%= submit f %>
diff --git a/app/views/extranet/layouts/application.html.erb b/app/views/extranet/layouts/application.html.erb
index 9415ecf20..e00ed21ae 100644
--- a/app/views/extranet/layouts/application.html.erb
+++ b/app/views/extranet/layouts/application.html.erb
@@ -7,7 +7,7 @@
     <%= csrf_meta_tags %>
     <%= csp_meta_tag %>
     <%= stylesheet_link_tag 'extranet', media: 'all' %>
-    <%= javascript_include_tag 'application' %>
+    <%= javascript_include_tag 'extranet' %>
     <%= favicon_link_tag 'favicon.png' %>
   </head>
   <body class="extranet <%= body_classes %>">
diff --git a/app/views/extranet/organizations/search.json.jbuilder b/app/views/extranet/organizations/search.json.jbuilder
index acbaefec4..e7415127c 100644
--- a/app/views/extranet/organizations/search.json.jbuilder
+++ b/app/views/extranet/organizations/search.json.jbuilder
@@ -1,6 +1,5 @@
-json.quantity @organizations.count
-json.organizations @organizations do |organization|
+json.array! @organizations do |organization|
   json.id organization.id
-  json.title organization.to_s
-  json.url organization.url
+  json.label organization.to_s
+  json.value organization.to_s
 end
\ No newline at end of file
diff --git a/config/locales/extranet/fr.yml b/config/locales/extranet/fr.yml
index 8ea70d0ae..695f5f02e 100644
--- a/config/locales/extranet/fr.yml
+++ b/config/locales/extranet/fr.yml
@@ -11,6 +11,7 @@ fr:
       email_not_allowed_with_contact: n'est pas autorisé à accéder à cet extranet. Contactez %{contact} pour en savoir plus.
     experiences:
       new: Ajouter une expérience
+      search_organization: Rechercher par nom ou SIREN
       title: Parcours professionnel
     home:
       recent_cohorts: Promotions récentes
-- 
GitLab