Skip to content

Commit

Permalink
add modalitites block to api impot particulier
Browse files Browse the repository at this point in the history
  • Loading branch information
JeSuisUnCaillou committed Dec 2, 2024
1 parent 9b962a6 commit 2fd0d9b
Show file tree
Hide file tree
Showing 28 changed files with 406 additions and 67 deletions.
7 changes: 7 additions & 0 deletions app/decorators/authorization_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class AuthorizationDecorator < ApplicationDecorator
delegate_all

def name_for_select
"Habilitation du #{slug} : #{name}"
end
end
6 changes: 5 additions & 1 deletion app/helpers/authorization_requests_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
module AuthorizationRequestsHelpers
def hidden_attributes
params.slice(:attributes).permit!
end

def start_authorization_request_form(form, disabled: false)
text = t('start_authorization_request_form.cta', authorization_name: form.authorization_definition.name)
css_classes = %w[fr-btn fr-icon-save-line fr-btn--icon-left]

if disabled
button_tag(text, class: css_classes, disabled: true, id: dom_id(form, :start_authorization_request))
else
link_to(text, start_authorization_request_forms_path(form_uid: form.id), class: css_classes, id: dom_id(form, :start_authorization_request))
link_to(text, start_authorization_request_forms_path(form_uid: form.id, params: hidden_attributes), class: css_classes, id: dom_id(form, :start_authorization_request))
end
end

Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,61 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static targets = ['franceConnectSelector', 'franceConnectSelectorContainer', 'nextStage', 'links']
static targets = ['modality', 'franceConnectSelector', 'franceConnectContainer', 'nextStage', 'links']

trigger (event) {
const selectedOption = event.target.value
trigger () {
const modalityValue = this.modalityTargets.find(modality => modality.checked).value

if (selectedOption === 'with_france_connect') {
this.show(this.franceConnectSelectorContainerTarget)

if (!this.hasFranceConnectSelectorTarget || !this.franceConnectSelectorTarget.value) {
this.hide(this.nextStageTarget)
}
if (modalityValue === 'with_france_connect') {
this.show(this.franceConnectContainerTarget)
this.showNextStageIfHabilitationSelected()
} else {
this.hide(this.franceConnectSelectorContainerTarget)
if (this.hasFranceConnectSelectorTarget) {
this.franceConnectSelectorTarget.value = ''
}
this.hide(this.franceConnectContainerTarget)
this.emptyFranceConnectSelector()
this.showNextStage()
}

this.updateLinks({ modalite: selectedOption })
this.addToLinks({ 'attributes[modalities]': modalityValue })
}

showNextStageIfHabilitationSelected (event) {
const franceConnectAuthorizationId = event.target.value

if (franceConnectAuthorizationId) {
this.updateLinks({ france_connect_authorization_id: franceConnectAuthorizationId })
showNextStageIfHabilitationSelected () {
if (this.hasFranceConnectSelectorTarget) {
this.franceConnectSelectorTarget.required = 'required'
const franceConnectAuthorizationId = this.valueOrDefaultFranceConnectAuthorizationId()
this.addToLinks({ 'attributes[france_connect_authorization_id]': franceConnectAuthorizationId })
this.showNextStage()
} else {
this.hideNextStage()
}
}

valueOrDefaultFranceConnectAuthorizationId () {
if (!this.franceConnectSelectorTarget.value) {
const defaultValue = Array.from(this.franceConnectSelectorTarget.options).filter(option => option.value)[0].value
this.franceConnectSelectorTarget.value = defaultValue
}

return this.franceConnectSelectorTarget.value
}

emptyFranceConnectSelector () {
if (this.hasFranceConnectSelectorTarget) {
this.franceConnectSelectorTarget.value = null
this.franceConnectSelectorTarget.required = ''
this.removeFromLinks('attributes[france_connect_authorization_id]')
}
}

showNextStage () {
this.show(this.nextStageTarget)
if (this.hasNextStageTarget) {
this.show(this.nextStageTarget)
}
}

hideNextStage () {
if (this.hasNextStageTarget) {
this.hide(this.nextStageTarget)
}
}

show (element) {
Expand All @@ -44,13 +66,13 @@ export default class extends Controller {
element.classList.add('fr-hidden')
}

updateLinks (params) {
addToLinks (params) {
this.linksTargets.forEach((link) => {
this.updateLink(link, params)
this.addToLink(link, params)
})
}

updateLink (link, params) {
addToLink (link, params) {
const url = new URL(link.href)

Object.entries(params).forEach(entry => {
Expand All @@ -59,4 +81,16 @@ export default class extends Controller {

link.href = url
}

removeFromLinks (param) {
this.linksTargets.forEach((link) => {
this.removeFromLink(link, param)
})
}

removeFromLink (link, param) {
const url = new URL(link.href)
url.searchParams.delete(param)
link.href = url
}
}
2 changes: 1 addition & 1 deletion app/models/authorization_request/api_impot_particulier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ class AuthorizationRequest::APIImpotParticulier < AuthorizationRequest
include AuthorizationExtensions::OperationalAcceptance
include AuthorizationExtensions::SafetyCertification
include AuthorizationExtensions::Volumetrie

include DGFIPExtensions::APIImpotParticulierScopes
include DGFIPExtensions::APIImpotParticulierModalities

VOLUMETRIES = {
'50 appels / minute': 50,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ class AuthorizationRequest::APIImpotParticulierSandbox < AuthorizationRequest
include AuthorizationExtensions::PersonalData
include AuthorizationExtensions::CadreJuridique
include AuthorizationExtensions::GDPRContacts

include DGFIPExtensions::APIImpotParticulierScopes
include DGFIPExtensions::APIImpotParticulierModalities

add_document :maquette_projet, content_type: ['application/pdf'], size: { less_than: 10.megabytes }

Expand Down
28 changes: 28 additions & 0 deletions app/models/concerns/authorization_extensions/modalities.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module AuthorizationExtensions::Modalities
extend ActiveSupport::Concern

included do
add_attributes :modalities

validates :modalities,
presence: true,
if: -> { need_complete_validation?(:modalities) }

validate :modalities_in_available_values,
if: -> { need_complete_validation?(:modalities) }
end

def modalities_in_available_values
if modalities.is_a? Array
errors.add(:modalities) unless (modalities - available_modalities).empty?
elsif available_modalities.exclude?(modalities)
errors.add(:modalities)
end
end

def available_modalities
self.class::MODALITIES
rescue NameError
raise "Must declare a constant MODALITIES in the model #{self.class}, for example %w[with_france_connect with_spi]"
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module DGFIPExtensions::APIImpotParticulierModalities
extend ActiveSupport::Concern

MODALITIES = %w[with_france_connect with_spi with_etat_civil].freeze

included do
include AuthorizationExtensions::Modalities

add_attribute :france_connect_authorization_id

validates :france_connect_authorization_id,
presence: true,
inclusion: { in: ->(authorization_request) { authorization_request.organization.valid_authorizations_of(AuthorizationRequest::FranceConnect).pluck(:id).map(&:to_s) } },
if: -> { modalities == 'with_france_connect' && need_complete_validation?(:modalities) }
end

def associated_france_connect_authorization
return nil if france_connect_authorization_id.blank?

Authorization.find(france_connect_authorization_id)
end
end
2 changes: 2 additions & 0 deletions app/views/authorization_request_forms/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
<% end %>
<%= yield %>
<%= render partial: "authorization_request_forms/shared/hidden_attributes", locals: { f: f } %>
</div>

<% if content_for? :sticky_bar %>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%= authorization_request_form(@authorization_request) do |f| %>
<%= render partial: 'authorization_request_forms/shared/modalities', locals: { f: } %>
<%= render partial: 'authorization_request_forms/build/wizard_buttons', locals: { f: } %>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<% if hidden_attributes.present? && hidden_attributes[:attributes].present? %>
<% hidden_attributes[:attributes].each do |key, value| %>
<%= f.hidden_field key, value: %>
<% end %>
<% end %>
Original file line number Diff line number Diff line change
@@ -1 +1,42 @@
<!-- No need to implement it yet -->
<% if @authorization_request.display_prefilled_banner_for_each_block? && @authorization_request.prefilled_data?(%i[modalities france_connect_authorization_id]) %>
<%= render partial: "authorization_request_forms/shared/prefilled_banner" %>
<% end %>
<%= f.info_for(:modalities) %>

<div data-controller="choose-modalite-impot-particulier">
<div class="fr-col-lg-9">
<%=
f.dsfr_radio_buttons :modalities,
@authorization_request.available_modalities,
required: true,
radio_group_class: "fr-radio-rich",
fieldset_element_class: "small",
input_options: {
"data-action": "click->choose-modalite-impot-particulier#trigger",
"data-choose-modalite-impot-particulier-target": "modality"
}
%>
</div>

<div class="fr-col-lg-9 fr-mb-5w <%= 'fr-hidden' if @authorization_request.modalities != 'with_france_connect' %>" data-choose-modalite-impot-particulier-target="franceConnectContainer">
<% france_connect_authorizations = current_organization.valid_authorizations_of(AuthorizationRequest::FranceConnect).map(&:decorate) %>
<% if france_connect_authorizations.empty? %>
<div class="fr-callout red-callout">
<h3 class="fr-callout__title">
<%= t("authorization_request_forms.api_impot_particulier_sandbox.modalities.callout.title") %>
</h3>
<p class="fr-callout__text fr-my-3w">
<%= t("authorization_request_forms.api_impot_particulier_sandbox.modalities.callout.content") %>
</p>
<%= link_to t("authorization_request_forms.api_impot_particulier_sandbox.modalities.callout.link"), new_authorization_request_form_path("france-connect"), class: "fr-link fr-btn--icon-right fr-icon-arrow-right-line" %>
</div>

<% else %>
<% options = france_connect_authorizations.map{ |authorization| [authorization.name_for_select, authorization.id] } %>
<% selected_option = @authorization_request.france_connect_authorization_id || france_connect_authorizations.first.id %>
<%= f.dsfr_select :france_connect_authorization_id, options_for_select(options, selected_option), class: %w[fr-select], include_blank: "Sélectionner une option", required: true, input_options: { "data-choose-modalite-impot-particulier-target": "franceConnectSelector" } %>
<% end %>
</div>
</div>
32 changes: 16 additions & 16 deletions app/views/authorization_requests/new/api_impot_particulier.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,25 @@
</div>


<h2 class="fr-h4"><%= t("authorization_requests.new.modalite.title") %></h2>
<h2 class="fr-h4"><%= t("authorization_request_forms.api_impot_particulier_sandbox.modalities.title") %></h2>

<div data-controller="choose-modalite-impot-particulier">
<div class="fr-col-lg-9 fr-mb-5w">
<p class=""><%= t("authorization_requests.new.modalite.subtitle").html_safe %></p>
<p class=""><%= t("authorization_request_forms.api_impot_particulier_sandbox.modalities.subtitle").html_safe %></p>

<fieldset class="fr-fieldset" id="radio-rich" aria-labelledby="radio-rich-legend radio-rich-messages">
<% t("authorization_requests.new.modalite.options").each do |option| %>
<% t("authorization_request_forms.api_impot_particulier_sandbox.modalities.values").each do |value, options| %>
<div class="fr-fieldset__element small">
<div class="fr-radio-group fr-radio-rich">
<input value="<%= option[:value] %>"
<input value="<%= value %>"
type="radio"
id="modalite_<%=option[:value]%>"
id="modalite_<%= value %>"
name="modalite"
data-action="click->choose-modalite-impot-particulier#trigger"
data-choose-modalite-impot-particulier-target="modality"
>
<label class="fr-label" for="modalite_<%=option[:value]%>">
<%= option[:label] %>
<label class="fr-label" for="modalite_<%= value %>">
<%= options[:label] %>
</label>
</div>
</div>
Expand All @@ -36,28 +37,27 @@
</fieldset>
</div>

<div class="fr-col-lg-9 fr-mb-5w fr-hidden" data-choose-modalite-impot-particulier-target="franceConnectSelectorContainer">
<% france_connect_authorizations = current_organization.valid_authorizations_of(AuthorizationRequest::FranceConnect) %>
<div class="fr-col-lg-9 fr-mb-5w fr-hidden" data-choose-modalite-impot-particulier-target="franceConnectContainer">
<% france_connect_authorizations = current_organization.valid_authorizations_of(AuthorizationRequest::FranceConnect).map(&:decorate) %>
<% if france_connect_authorizations.empty? %>
<div class="fr-callout red-callout">
<h3 class="fr-callout__title">
<%= t("authorization_requests.new.modalite.callout.title") %>
<%= t("authorization_request_forms.api_impot_particulier_sandbox.modalities.callout.title") %>
</h3>
<p class="fr-callout__text fr-my-3w">
<%= t("authorization_requests.new.modalite.callout.content") %>
<%= t("authorization_request_forms.api_impot_particulier_sandbox.modalities.callout.content") %>
</p>
<%= link_to t("authorization_requests.new.modalite.callout.link"), new_authorization_request_form_path("france-connect"), class: "fr-link fr-btn--icon-right fr-icon-arrow-right-line" %>
<%= link_to t("authorization_request_forms.api_impot_particulier_sandbox.modalities.callout.link"), new_authorization_request_form_path("france-connect"), class: "fr-link fr-btn--icon-right fr-icon-arrow-right-line" %>
</div>

<% else %>
<div class="fr-select-group">
<label class="fr-h4 fr-label" for="france_connect_authorization_id">
<%= t("authorization_requests.new.france_connect_authorization_selection.title") %>
<%= t("authorization_request_forms.api_impot_particulier_sandbox.france_connect_authorization_id.label") %>
</label>
<select class="fr-select" id="france_connect_authorization_id" name="france_connect_authorization_id" data-choose-modalite-impot-particulier-target="franceConnectSelector" data-action="click->choose-modalite-impot-particulier#showNextStageIfHabilitationSelected">
<% options = france_connect_authorizations.map{ |authorization| ["Habilitation du #{authorization.slug} - #{authorization.data["intitule"]}", authorization.id] } %>
<% options = [["Sélectionner une option", nil, hidden: true]] + options %>
<select class="fr-select" id="france_connect_authorization_id" name="france_connect_authorization_id" data-choose-modalite-impot-particulier-target="franceConnectSelector" data-action="click->choose-modalite-impot-particulier#trigger">
<% options = france_connect_authorizations.map{ |authorization| [authorization.name_for_select, authorization.id] } %>
<%= options_for_select options, selected: options.first[1] %>
</select>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
<%= render layout: 'authorization_requests/shared/blocks/summary_block', locals: { title: f.wording_for('steps.modalities'), block_id: :basic_infos, f:, editable: } do %>
<%= render layout: 'authorization_requests/shared/blocks/summary_block', locals: { title: f.wording_for('steps.modalities'), block_id: :modalities, f:, editable: } do %>
<% if f.wording_for('modalities.intro') %>
<%= f.wording_for('modalities.intro').html_safe %>
<% end %>

<% modalities = @authorization_request.modalities.is_a?(Array) ? @authorization_request.modalities : [@authorization_request.modalities] %>
<ul>
<% @authorization_request.modalities.each do |modality| %>
<% modalities.each do |modality| %>
<li>
<%= f.label_value("modalities.values.#{modality}").html_safe %>
</li>
<% end %>
</ul>

<% if @authorization_request.try(:france_connect_authorization_id).present? && @authorization_request.modalities == 'with_france_connect' %>
<p class="fr-pl-2w">
<%= @authorization_request.associated_france_connect_authorization.full_name %>
</p>
<% end %>
<% end %>
2 changes: 2 additions & 0 deletions config/authorization_definitions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ shared:
- name: basic_infos
- name: personal_data
- name: legal
- name: modalities
- name: scopes
- name: contacts
- name: operational_acceptance
Expand Down Expand Up @@ -486,6 +487,7 @@ shared:
- name: basic_infos
- name: personal_data
- name: legal
- name: modalities
- name: scopes
- name: contacts
scopes: *api_impot_particulier_scopes
Expand Down
Loading

0 comments on commit 2fd0d9b

Please sign in to comment.