accessibilite(pages-authentification): evolutions des pages de connexion/creation de compte pour respecter le DSFR et supporter une meilleure accessibilite
Update app/components/dsfr/input_component/input_component.html.haml Co-authored-by: Colin Darie <colin@darie.eu>
This commit is contained in:
parent
be5b8c2683
commit
a4d6692bc6
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 19 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 19 KiB |
|
@ -21,10 +21,6 @@
|
|||
padding-top: $default-spacer;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: $default-spacer;
|
||||
}
|
||||
|
||||
.form label {
|
||||
margin-bottom: $default-spacer / 2;
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
@import "colors";
|
||||
@import "constants";
|
||||
|
||||
.france-connect-login {
|
||||
h2 {
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
|
||||
a.france-connect-login-button {
|
||||
display: inline-block;
|
||||
height: 60px;
|
||||
width: 230px;
|
||||
margin: auto;
|
||||
margin-bottom: 8px;
|
||||
background-image: image-url("franceconnect-btn.svg"), image-url("franceconnect-btn-hover.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
cursor: pointer;
|
||||
font-size: 0;
|
||||
|
||||
&:hover {
|
||||
background-image: image-url("franceconnect-btn-hover.svg");
|
||||
}
|
||||
}
|
||||
|
||||
.france-connect-login-separator {
|
||||
display: flex;
|
||||
flex-basis: 100%;
|
||||
align-items: center;
|
||||
color: $black;
|
||||
text-transform: uppercase;
|
||||
padding-bottom: $default-spacer;
|
||||
padding-top: $default-spacer;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: "";
|
||||
flex-grow: 1;
|
||||
background: $dark-grey;
|
||||
height: 1px;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
&::before {
|
||||
margin-right: $default-spacer;
|
||||
}
|
||||
|
||||
&::after {
|
||||
margin-left: $default-spacer;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
@import "colors";
|
||||
@import "constants";
|
||||
|
||||
.suspect-email {
|
||||
background-color: $orange-bg;
|
||||
text-align: center;
|
||||
margin-top: -$default-padding * 2;
|
||||
margin-bottom: $default-padding * 2;
|
||||
padding: ($default-padding - 2) $default-padding $default-padding $default-padding;
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
|
||||
.email-suggestion-address {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.email-suggestion-title {
|
||||
margin-bottom: $default-spacer;
|
||||
}
|
||||
|
||||
.email-suggestion-answer button {
|
||||
margin: 0 $default-spacer / 2;
|
||||
min-width: 66px;
|
||||
}
|
|
@ -1,4 +1,11 @@
|
|||
class Dsfr::InputComponent < ApplicationComponent
|
||||
delegate :object, to: :@form
|
||||
delegate :errors, to: :object
|
||||
|
||||
# use it to indicate detailed about the inputs, ex: https://www.systeme-de-design.gouv.fr/elements-d-interface/modeles-et-blocs-fonctionnels/demande-de-mot-de-passe
|
||||
# it uses aria-describedby on input and link it to yielded content
|
||||
renders_one :describedby
|
||||
|
||||
def initialize(form:, attribute:, input_type:, opts: {}, required: true)
|
||||
@form = form
|
||||
@attribute = attribute
|
||||
|
@ -7,60 +14,93 @@ class Dsfr::InputComponent < ApplicationComponent
|
|||
@required = required
|
||||
end
|
||||
|
||||
# add invalid class on input when input is invalid
|
||||
# and and valid on input only if another input is invalid
|
||||
def input_group_opts
|
||||
opts = {
|
||||
class: class_names('fr-input-group': true,
|
||||
'fr-password': password?,
|
||||
"fr-input-group--error": errors_on_attribute?,
|
||||
"fr-input-group--valid": !errors_on_attribute? && errors_on_another_attribute?)
|
||||
}
|
||||
if email?
|
||||
opts[:data] = { controller: 'email-input' }
|
||||
end
|
||||
opts
|
||||
end
|
||||
|
||||
def label_opts
|
||||
{ class: class_names('fr-label': true, 'fr-password__label': password?) }
|
||||
end
|
||||
|
||||
def input_opts
|
||||
@opts[:class] = class_names(map_array_to_hash_with_true(@opts[:class])
|
||||
.merge('fr-input': true,
|
||||
.merge('fr-password__input': password?,
|
||||
'fr-input': true,
|
||||
'fr-mb-0': true,
|
||||
'fr-input--error': errors_on_attribute?))
|
||||
|
||||
if errors_on_attribute?
|
||||
if errors_on_attribute? || describedby
|
||||
@opts = @opts.deep_merge(aria: {
|
||||
describedby: error_message_id,
|
||||
invalid: true
|
||||
invalid: errors_on_attribute?
|
||||
})
|
||||
end
|
||||
if @required
|
||||
@opts[:required] = true
|
||||
end
|
||||
if email?
|
||||
@opts = @opts.deep_merge(data: {
|
||||
action: "blur->email-input#checkEmail",
|
||||
'email-input-target': 'input'
|
||||
})
|
||||
end
|
||||
@opts
|
||||
end
|
||||
|
||||
# add invalid class on input when input is invalid
|
||||
# and and valid on input only if another input is invalid
|
||||
def input_group_class_names
|
||||
class_names('fr-input-group': true,
|
||||
"fr-input-group--error": errors_on_attribute?,
|
||||
"fr-input-group--valid": !errors_on_attribute? && errors_on_another_attribute?)
|
||||
end
|
||||
|
||||
# tried to inline it within the template, but failed miserably with a double render
|
||||
def label
|
||||
label = @form.object.class.human_attribute_name(@attribute)
|
||||
|
||||
if @required
|
||||
label += tag.span(" *", class: 'mandatory')
|
||||
end
|
||||
label
|
||||
end
|
||||
|
||||
# errors helpers
|
||||
def errors_on_attribute?
|
||||
@form.object.errors.has_key?(attribute_or_rich_body)
|
||||
errors.has_key?(attribute_or_rich_body)
|
||||
end
|
||||
|
||||
def error_message_id
|
||||
dom_id(@form.object, @attribute)
|
||||
dom_id(object, @attribute)
|
||||
end
|
||||
|
||||
def error_messages
|
||||
@form.object.errors.full_messages_for(attribute_or_rich_body)
|
||||
errors.full_messages_for(attribute_or_rich_body)
|
||||
end
|
||||
|
||||
# i18n lookups
|
||||
def label
|
||||
object.class.human_attribute_name(@attribute)
|
||||
end
|
||||
|
||||
def hint
|
||||
I18n.t("activerecord.attributes.#{object.class.name.underscore}.hints.#{@attribute}")
|
||||
end
|
||||
|
||||
# kind of input helpers
|
||||
def password?
|
||||
@input_type == :password_field
|
||||
end
|
||||
|
||||
def email?
|
||||
@input_type == :email_field
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def errors_on_another_attribute?
|
||||
!@form.object.errors.empty?
|
||||
def hint?
|
||||
I18n.exists?("activerecord.attributes.#{object.class.name.underscore}.hints.#{@attribute}")
|
||||
end
|
||||
|
||||
def errors_on_another_attribute?
|
||||
!errors.empty?
|
||||
end
|
||||
|
||||
# lookup for edge case from `form.rich_text_area`
|
||||
# rich text uses _rich_#{attribute}, but it is saved on #{attribute}, as well as error messages
|
||||
def attribute_or_rich_body
|
||||
case @input_type
|
||||
when :rich_text_area
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
en:
|
||||
show_password:
|
||||
aria_label: "Show password"
|
||||
label: "Show"
|
||||
email_suggest:
|
||||
wanna_say: 'Do you mean to say ?'
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
fr:
|
||||
show_password:
|
||||
aria_label: "Afficher le mot de passe"
|
||||
label: "Afficher"
|
||||
email_suggest:
|
||||
wanna_say: 'Voulez-vous dire ?'
|
|
@ -1,5 +1,11 @@
|
|||
%div{ class: input_group_class_names }
|
||||
= @form.label @attribute, label.html_safe, class: "fr-label"
|
||||
= content_tag(:div, input_group_opts) do
|
||||
= @form.label @attribute, label_opts do
|
||||
- capture do
|
||||
= label
|
||||
- if @required
|
||||
%span.mandatory *
|
||||
- if hint?
|
||||
%span.fr-hint-text= hint
|
||||
|
||||
= @form.send(@input_type, @attribute, input_opts)
|
||||
|
||||
|
@ -12,3 +18,21 @@
|
|||
- error_messages.map do |error_message|
|
||||
%li= error_message
|
||||
|
||||
- elsif describedby.present?
|
||||
= describedby
|
||||
|
||||
- if password?
|
||||
.fr-password__checkbox.fr-checkbox-group.fr-checkbox-group--sm
|
||||
%input#show_password{ "aria-label" => t('.show_password.aria_label'), type: "checkbox" }/
|
||||
%label.fr--password__checkbox.fr-label{ for: "show_password" }= t('.show_password.label')
|
||||
|
||||
- if email?
|
||||
.suspect-email.hidden{ data: { "email-input-target": 'ariaRegion'}, aria: { live: 'off' } }
|
||||
= render Dsfr::AlertComponent.new(title: t('.email_suggest.wanna_say'), state: :info, heading_level: :div) do |c|
|
||||
- c.body do
|
||||
%p{ data: { "email-input-target": 'suggestion'} } exemple@gmail.com ?
|
||||
%p
|
||||
= button_tag type: 'button', class: 'fr-btn fr-btn--sm fr-mr-3w', data: { action: 'click->email-input#accept'} do
|
||||
= t('utils.yes')
|
||||
= button_tag type: 'button', class: 'fr-btn fr-btn--sm', data: { action: 'click->email-input#discard'} do
|
||||
= t('utils.no')
|
||||
|
|
33
app/javascript/controllers/email_input_controller.ts
Normal file
33
app/javascript/controllers/email_input_controller.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { suggest } from 'email-butler';
|
||||
import { show, hide } from '@utils';
|
||||
import { ApplicationController } from './application_controller';
|
||||
|
||||
export class EmailInputController extends ApplicationController {
|
||||
static targets = ['ariaRegion', 'suggestion', 'input'];
|
||||
|
||||
declare readonly ariaRegionTarget: HTMLElement;
|
||||
declare readonly suggestionTarget: HTMLElement;
|
||||
declare readonly inputTarget: HTMLInputElement;
|
||||
|
||||
checkEmail() {
|
||||
const suggestion = suggest(this.inputTarget.value);
|
||||
if (suggestion && suggestion.full) {
|
||||
this.suggestionTarget.innerHTML = suggestion.full;
|
||||
show(this.ariaRegionTarget);
|
||||
this.ariaRegionTarget.setAttribute('aria-live', 'assertive');
|
||||
}
|
||||
}
|
||||
|
||||
accept() {
|
||||
this.ariaRegionTarget.setAttribute('aria-live', 'off');
|
||||
hide(this.ariaRegionTarget);
|
||||
this.inputTarget.value = this.suggestionTarget.innerHTML;
|
||||
this.suggestionTarget.innerHTML = '';
|
||||
}
|
||||
|
||||
discard() {
|
||||
this.ariaRegionTarget.setAttribute('aria-live', 'off');
|
||||
hide(this.ariaRegionTarget);
|
||||
this.suggestionTarget.innerHTML = '';
|
||||
}
|
||||
}
|
|
@ -24,10 +24,6 @@ import {
|
|||
motivationCancel,
|
||||
showImportJustificatif
|
||||
} from '../new_design/state-button';
|
||||
import {
|
||||
acceptEmailSuggestion,
|
||||
discardEmailSuggestionBox
|
||||
} from '../new_design/user-sign_up';
|
||||
import { showFusion, showNewAccount } from '../new_design/fc-fusion';
|
||||
|
||||
const application = Application.start();
|
||||
|
@ -41,9 +37,7 @@ const DS = {
|
|||
showImportJustificatif,
|
||||
showFusion,
|
||||
showNewAccount,
|
||||
replaceSemicolonByComma,
|
||||
acceptEmailSuggestion,
|
||||
discardEmailSuggestionBox
|
||||
replaceSemicolonByComma
|
||||
};
|
||||
|
||||
// Start Rails helpers
|
||||
|
|
|
@ -31,3 +31,4 @@
|
|||
@import '@gouvfr/dsfr/dist/component/translate/translate.css';
|
||||
@import '@gouvfr/dsfr/dist/component/pagination/pagination.css';
|
||||
@import '@gouvfr/dsfr/dist/component/skiplink/skiplink.css';
|
||||
@import '@gouvfr/dsfr/dist/component/password/password.css';
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
import { delegate, show, hide } from '@utils';
|
||||
import { suggest } from 'email-butler';
|
||||
|
||||
const userNewEmailSelector = '#new_user input#user_email';
|
||||
const passwordFieldSelector = '#new_user input#user_password';
|
||||
const suggestionsSelector = '.suspect-email';
|
||||
const emailSuggestionSelector = '.suspect-email .email-suggestion-address';
|
||||
|
||||
delegate('focusout', userNewEmailSelector, () => {
|
||||
// When the user leaves the email input during account creation, we check if this account looks correct.
|
||||
// If not (e.g if its "bidou@gmail.coo" or "john@yahoo.rf"), we attempt to suggest a fix for the invalid email.
|
||||
const userEmailInput = document.querySelector(userNewEmailSelector);
|
||||
const suggestedEmailSpan = document.querySelector(emailSuggestionSelector);
|
||||
|
||||
const suggestion = suggest(userEmailInput.value);
|
||||
if (suggestion && suggestion.full && suggestedEmailSpan) {
|
||||
suggestedEmailSpan.innerHTML = suggestion.full;
|
||||
show(document.querySelector(suggestionsSelector));
|
||||
} else {
|
||||
hide(document.querySelector(suggestionsSelector));
|
||||
}
|
||||
});
|
||||
|
||||
export function acceptEmailSuggestion() {
|
||||
const userEmailInput = document.querySelector(userNewEmailSelector);
|
||||
const suggestedEmailSpan = document.querySelector(emailSuggestionSelector);
|
||||
|
||||
userEmailInput.value = suggestedEmailSpan.innerHTML;
|
||||
hide(document.querySelector(suggestionsSelector));
|
||||
document.querySelector(passwordFieldSelector).focus();
|
||||
}
|
||||
|
||||
export function discardEmailSuggestionBox() {
|
||||
hide(document.querySelector(suggestionsSelector));
|
||||
}
|
|
@ -26,8 +26,7 @@
|
|||
= link_to t('.whats_agentconnect'), 'https://agentconnect.gouv.fr/', target: '_blank', rel: "noopener"
|
||||
|
||||
|
||||
.france-connect-login-separator
|
||||
= t('views.shared.france_connect_login.separator')
|
||||
%p.fr-hr-or= t('views.shared.france_connect_login.separator')
|
||||
|
||||
#session-new.auth-form.sign-in-form
|
||||
= form_for User.new, url: user_session_path, html: { class: "form" } do |f|
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- if FranceConnectService.enabled?
|
||||
.france-connect-login
|
||||
%h2.fr-h6.mb-0
|
||||
%h2.fr-h6
|
||||
= t('views.shared.france_connect_login.title')
|
||||
%p
|
||||
= t('views.shared.france_connect_login.description')
|
||||
|
@ -13,7 +13,6 @@
|
|||
%p
|
||||
= link_to t('views.shared.france_connect_login.help_link'), "https://franceconnect.gouv.fr/", title: new_tab_suffix(t('views.shared.france_connect_login.help_link')), **external_link_attributes
|
||||
|
||||
.france-connect-login-separator
|
||||
= t('views.shared.france_connect_login.separator')
|
||||
%p.fr-hr-or= t('views.shared.france_connect_login.separator')
|
||||
- else
|
||||
<!-- FranceConnect is not configured -->
|
||||
|
|
|
@ -2,26 +2,26 @@
|
|||
|
||||
.auth-form
|
||||
= devise_error_messages!
|
||||
= form_for resource, url: user_registration_path, html: { class: "form" } do |f|
|
||||
= form_for resource, url: user_registration_path, html: { class: "fr-py-5w" } do |f|
|
||||
|
||||
%h1.fr-h2= t('views.registrations.new.title', name: APPLICATION_NAME)
|
||||
|
||||
= render partial: 'shared/france_connect_login', locals: { url: france_connect_particulier_path }
|
||||
|
||||
= f.label :email, t('views.registrations.new.email_label'), id: :user_email_label
|
||||
= f.text_field :email, type: :email, autocomplete: 'email', autofocus: true, placeholder: t('views.registrations.new.email_placeholder'), 'aria-describedby': :user_email_label
|
||||
%fieldset.fr-mb-0.fr-fieldset{ aria: { labelledby: 'create-account-legend' } }
|
||||
%legend.fr-fieldset__legend#create-account-legend
|
||||
%h2.fr-h6= I18n.t('views.registrations.new.subtitle')
|
||||
|
||||
.suspect-email.hidden
|
||||
.email-suggestion-title
|
||||
= t('views.registrations.new.wanna_say')
|
||||
%span.email-suggestion-address blabla@gmail.com
|
||||
?
|
||||
.email-suggestion-answer
|
||||
= button_tag type: 'button', class: 'button small', onclick: "DS.acceptEmailSuggestion()" do
|
||||
= t('utils.yes')
|
||||
= button_tag type: 'button', class: 'button small', onclick: "DS.discardEmailSuggestionBox()" do
|
||||
= t('utils.no')
|
||||
.fr-fieldset__element
|
||||
%p.fr-text--sm= t('utils.asterisk_html')
|
||||
|
||||
= f.label :password, t('views.registrations.new.password_label', min_length: PASSWORD_MIN_LENGTH), id: :user_password_label
|
||||
= f.password_field :password, autocomplete: 'new-password', value: @user.password, placeholder: t('views.registrations.new.password_placeholder', min_length: PASSWORD_MIN_LENGTH), 'aria-describedby': :user_password_label
|
||||
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { autocomplete: 'email', autofocus: true })
|
||||
|
||||
= f.submit t('views.shared.account.create'), class: "button large primary expand"
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field, opts: { autocomplete: 'new-password', min_length: PASSWORD_MIN_LENGTH }) do |c|
|
||||
- c.describedby do
|
||||
#password-input-messages.fr-messages-group{ "aria-live" => "off" }
|
||||
%p#password-input-message.fr-message= t('views.registrations.new.password_message')
|
||||
%p#password-input-message-info.fr-message.fr-message--info= t('views.registrations.new.password_placeholder', min_length: PASSWORD_MIN_LENGTH)
|
||||
|
||||
= f.submit t('views.shared.account.create'), class: "fr-btn fr-btn--lg"
|
||||
|
|
|
@ -1,32 +1,40 @@
|
|||
= content_for(:page_id, 'auth')
|
||||
= content_for(:title, t('metas.signin.title'))
|
||||
|
||||
#session-new.auth-form.sign-in-form
|
||||
|
||||
= form_for resource, url: user_session_path, html: { class: "form" } do |f|
|
||||
%h1.huge-title= t('views.users.sessions.new.sign_in')
|
||||
#session-new.auth-form.sign-in-form
|
||||
= form_for resource, url: user_session_path, html: { class: "fr-py-5w" } do |f|
|
||||
|
||||
%h1.fr-h2= t('views.users.sessions.new.sign_in', application_name: APPLICATION_NAME)
|
||||
|
||||
= render partial: 'shared/france_connect_login', locals: { url: france_connect_particulier_path }
|
||||
|
||||
= f.label :email, t('views.users.sessions.new.email')
|
||||
= f.text_field :email, type: :email, autocomplete: 'email', autofocus: true
|
||||
%fieldset.fr-mb-0.fr-fieldset{ aria: { labelledby: 'new-account-legend' } }
|
||||
%legend.fr-fieldset__legend#new-account-legend
|
||||
%h2.fr-h6= I18n.t('views.users.sessions.new.subtitle')
|
||||
|
||||
= f.label :password, t('views.users.sessions.new.password', min_length: PASSWORD_MIN_LENGTH)
|
||||
= f.password_field :password, autocomplete: 'current-password'
|
||||
.fr-fieldset__element
|
||||
%p.fr-text--sm= t('utils.asterisk_html')
|
||||
|
||||
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { autocomplete: 'email', autofocus: true })
|
||||
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field, opts: { autocomplete: 'current-password' })
|
||||
|
||||
%p= link_to t('views.users.sessions.new.reset_password'), new_user_password_path, class: "link"
|
||||
|
||||
|
||||
.fr-fieldset__element
|
||||
.auth-options
|
||||
.flex-no-shrink
|
||||
= f.check_box :remember_me
|
||||
= f.label :remember_me, t('views.users.sessions.new.remember_me'), class: 'remember-me'
|
||||
|
||||
.text-right
|
||||
= link_to t('views.users.sessions.new.reset_password'), new_user_password_path, class: "link"
|
||||
|
||||
= f.submit t('views.users.sessions.new.connection'), class: "fr-btn fr-btn--lg"
|
||||
|
||||
- if AgentConnectService.enabled?
|
||||
.france-connect-login-separator
|
||||
= t('views.shared.france_connect_login.separator')
|
||||
%p.fr-hr-or= t('views.shared.france_connect_login.separator')
|
||||
.center
|
||||
%h2.important-header.mb-1= t('views.users.sessions.new.state_civil_servant')
|
||||
= link_to t('views.users.sessions.new.connect_with_agent_connect'), agent_connect_path, class: "fr-btn fr-btn--secondary"
|
||||
|
|
|
@ -92,5 +92,11 @@ module TPS
|
|||
config.view_component.show_previews_source = true
|
||||
config.view_component.default_preview_layout = 'component_preview'
|
||||
config.view_component.preview_paths << "#{Rails.root}/spec/components/previews"
|
||||
|
||||
# rubocop:disable Rails/OutputSafety
|
||||
config.action_view.field_error_proc = Proc.new do |html_tag, _instance|
|
||||
html_tag.html_safe # this is generated by rails
|
||||
end
|
||||
# rubocop:enable Rails/OutputSafety
|
||||
end
|
||||
end
|
||||
|
|
|
@ -97,6 +97,7 @@ search:
|
|||
|
||||
## Consider these keys used:
|
||||
ignore_unused:
|
||||
- 'errors.format'
|
||||
- 'activerecord.models.*'
|
||||
- 'activerecord.attributes.*'
|
||||
- 'activerecord.errors.*'
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
en:
|
||||
invisible_captcha:
|
||||
sentence_for_humans: 'If you are a human, ignore this field'
|
||||
|
||||
help: 'Help'
|
||||
help_dropdown:
|
||||
general_title: "Online help"
|
||||
|
@ -141,10 +140,10 @@ en:
|
|||
registrations:
|
||||
new:
|
||||
title: "Create an account %{name}"
|
||||
subtitle: "Create an account using an email"
|
||||
email_label: 'Email (name@site.com)'
|
||||
email_placeholder: 'Your email address'
|
||||
wanna_say: 'Do you mean to say'
|
||||
password_label: "Password (%{min_length} characters minimum)"
|
||||
password_message: "Your password must have :"
|
||||
password_placeholder: "%{min_length} characters minimum"
|
||||
invites:
|
||||
dropdown:
|
||||
|
@ -314,8 +313,7 @@ en:
|
|||
actions: "Actions"
|
||||
sessions:
|
||||
new:
|
||||
sign_in: Sign in
|
||||
email: Email address (name@site.com)
|
||||
sign_in: Sign in on %{application_name}
|
||||
password: Password (minimum length %{min_length} characters)
|
||||
remember_me: Remember me
|
||||
reset_password: Forgot password?
|
||||
|
@ -323,6 +321,7 @@ en:
|
|||
find_procedure: Find your procedure
|
||||
state_civil_servant: Are you a state civil servant?
|
||||
connect_with_agent_connect: Visit our dedicated page
|
||||
subtitle: "Sign in with my account"
|
||||
passwords:
|
||||
reset_link_sent:
|
||||
got_it: Got it!
|
||||
|
@ -352,10 +351,14 @@ en:
|
|||
user:
|
||||
one: User
|
||||
other: Users
|
||||
|
||||
attributes:
|
||||
default_attributes: &default_attributes
|
||||
password: 'password'
|
||||
email: Email
|
||||
password: 'Password'
|
||||
requested_merge_into: 'new email address'
|
||||
hints:
|
||||
email: "Expected format : john.doe@example.com"
|
||||
user:
|
||||
siret: 'SIRET number'
|
||||
<< : *default_attributes
|
||||
|
@ -363,8 +366,11 @@ en:
|
|||
<< : *default_attributes
|
||||
super_admin:
|
||||
<< : *default_attributes
|
||||
instructeur:
|
||||
password: 'password'
|
||||
procedure:
|
||||
zone: This procedure is run by
|
||||
champs:
|
||||
value: Value
|
||||
|
||||
errors:
|
||||
messages:
|
||||
not_a_phone: 'Invalid phone number'
|
||||
|
@ -374,35 +380,40 @@ en:
|
|||
attributes:
|
||||
footer:
|
||||
too_long: ": the footer is too long."
|
||||
user:
|
||||
attributes:
|
||||
reset_password_token:
|
||||
# invalid: ": Votre lien de nouveau mot de passe a expiré. Merci d’en demander un nouveau."
|
||||
email:
|
||||
invalid: invalid
|
||||
taken: already in use
|
||||
password:
|
||||
too_short: 'is too short'
|
||||
password_confirmation:
|
||||
confirmation: ': The two passwords do not match'
|
||||
requested_merge_into:
|
||||
same: "can't be the same as the old one"
|
||||
|
||||
invite:
|
||||
attributes:
|
||||
email:
|
||||
taken: ': Invitation already sent'
|
||||
|
||||
user:
|
||||
attributes: &error_attributes
|
||||
reset_password_token:
|
||||
invalid: ": is expired. Ask a new one"
|
||||
email:
|
||||
blank: "is empty. Fill in the email"
|
||||
invalid: "is invalid. Fill in a valid email address, example: john.doe@example.fr"
|
||||
taken: "already in use. Fill in another email"
|
||||
password:
|
||||
too_short: "is too short. Fill in a password with at least 8 characters"
|
||||
not_strong: "not strong enough. Fill in a stronger password"
|
||||
password_confirmation:
|
||||
confirmation: ": The two passwords do not match"
|
||||
requested_merge_into:
|
||||
same: "can't be the same as the old one"
|
||||
|
||||
instructeur:
|
||||
attributes:
|
||||
email:
|
||||
invalid: invalid
|
||||
taken: already in use
|
||||
password:
|
||||
too_short: 'is too short'
|
||||
<< : *error_attributes
|
||||
super_admin:
|
||||
attributes:
|
||||
<< : *error_attributes
|
||||
|
||||
procedure:
|
||||
attributes:
|
||||
path:
|
||||
taken: is already used for procedure. You cannot use it because it belongs to another administrator.
|
||||
# taken_can_be_claimed: est identique à celui d’une autre de vos procedures publiées. Si vous publiez cette procedure, l’ancienne sera dépubliée et ne sera plus accessible au public. Les utilisateurs qui ont commencé un brouillon vont pouvoir le déposer.
|
||||
taken_can_be_claimed: Is the same as another of your procedure. If you publish this procedure, the other one will be unpublished
|
||||
invalid: is not valid. It must countain between 3 and 50 characters among a-z, 0-9, '_' and '-'.
|
||||
"champs/cnaf_champ":
|
||||
attributes:
|
||||
|
@ -417,6 +428,7 @@ en:
|
|||
reference_avis:
|
||||
invalid: "must be 13 or 14 characters long"
|
||||
errors:
|
||||
format: "Field « %{attribute} » %{message}"
|
||||
messages:
|
||||
dossier_not_found: "The file does not exist or you do not have access to it."
|
||||
# # dossier_map_not_activated: "The file does not have access to the map."
|
||||
|
|
|
@ -132,11 +132,11 @@ fr:
|
|||
prefill_link_copy: Copier le lien de préremplissage
|
||||
registrations:
|
||||
new:
|
||||
title: "Créez-vous un compte %{name}"
|
||||
title: "Creation de compte sur %{name}"
|
||||
subtitle: "Se créer un compte en choisissant un identifiant"
|
||||
email_label: 'Email'
|
||||
email_placeholder: 'Votre adresse email'
|
||||
wanna_say: 'Voulez-vous dire'
|
||||
password_label: "Mot de passe (%{min_length} caractères minimum)"
|
||||
password_message: "Votre mot de passe doit contenir :"
|
||||
password_placeholder: "%{min_length} caractères minimum"
|
||||
invites:
|
||||
dropdown:
|
||||
|
@ -310,8 +310,7 @@ fr:
|
|||
actions: "Actions"
|
||||
sessions:
|
||||
new:
|
||||
sign_in: Connectez-vous
|
||||
email: Email
|
||||
sign_in: Connexion à %{application_name}
|
||||
password: Mot de passe (%{min_length} caractères minimum)
|
||||
remember_me: Se souvenir de moi
|
||||
reset_password: Mot de passe oublié ?
|
||||
|
@ -319,6 +318,7 @@ fr:
|
|||
find_procedure: Trouvez votre démarche
|
||||
state_civil_servant: Vous êtes agent de la fonction publique d’État ?
|
||||
connect_with_agent_connect: Accédez à notre page dédiée
|
||||
subtitle: "Se connecter avec son compte"
|
||||
passwords:
|
||||
reset_link_sent:
|
||||
email_sent_html: "Nous vous avons envoyé un email à l’adresse <strong>%{email}</strong>."
|
||||
|
@ -349,10 +349,14 @@ fr:
|
|||
user:
|
||||
one: Utilisateur
|
||||
other: Utilisateurs
|
||||
|
||||
attributes:
|
||||
default_attributes: &default_attributes
|
||||
password: 'Le mot de passe'
|
||||
email: Adresse éléctronique
|
||||
password: 'Mot de passe'
|
||||
requested_merge_into: 'La nouvelle adresse email'
|
||||
hints:
|
||||
email: "Format attendu : john.doe@exemple.fr"
|
||||
user:
|
||||
siret: 'Numéro SIRET'
|
||||
<< : *default_attributes
|
||||
|
@ -364,6 +368,7 @@ fr:
|
|||
zone: La démarche est mise en œuvre par
|
||||
champs:
|
||||
value: Valeur du champ
|
||||
|
||||
errors:
|
||||
messages:
|
||||
not_a_phone: 'Numéro de téléphone invalide'
|
||||
|
@ -373,35 +378,33 @@ fr:
|
|||
attributes:
|
||||
footer:
|
||||
too_long: ": le pied de page est trop long."
|
||||
user:
|
||||
attributes:
|
||||
reset_password_token:
|
||||
invalid: ": Votre lien de nouveau mot de passe a expiré. Merci d’en demander un nouveau."
|
||||
email:
|
||||
invalid: invalide
|
||||
taken: déjà utilisé
|
||||
password: &password
|
||||
too_short: 'est trop court'
|
||||
not_strong: 'n’est pas assez complexe'
|
||||
password_confirmation:
|
||||
confirmation: ': Les deux mots de passe ne correspondent pas'
|
||||
requested_merge_into:
|
||||
same: "ne peut être identique à l’ancienne"
|
||||
invite:
|
||||
attributes:
|
||||
email:
|
||||
taken: ': Invitation déjà envoyée'
|
||||
user:
|
||||
attributes: &error_attributes
|
||||
reset_password_token:
|
||||
invalid: ": Votre lien de nouveau mot de passe a expiré. Merci d’en demander un nouveau."
|
||||
email:
|
||||
blank: "est vide. Saisir une adresse éléctronique"
|
||||
invalid: "est invalide. Saisir une adresse éléctronique valide, exemple : john.doe@exemple.fr"
|
||||
taken: "déjà utilisé. Saisir une autre adresse éléctronique."
|
||||
password:
|
||||
too_short: "est trop court. Saisir un mot de passe avec au moins 8 caractères"
|
||||
not_strong: "n’est pas assez complexe. Saisir un mot de passe plus complexe"
|
||||
password_confirmation:
|
||||
confirmation: ': Les deux mots de passe ne correspondent pas'
|
||||
requested_merge_into:
|
||||
same: "ne peut être identique à l’ancienne. Saisir une autre adresse email"
|
||||
|
||||
instructeur:
|
||||
attributes:
|
||||
email:
|
||||
invalid: invalide
|
||||
taken: déjà utilisé
|
||||
password:
|
||||
too_short: 'est trop court'
|
||||
<< : *error_attributes
|
||||
super_admin:
|
||||
attributes:
|
||||
password:
|
||||
<< : *password
|
||||
<< : *error_attributes
|
||||
|
||||
procedure:
|
||||
attributes:
|
||||
path:
|
||||
|
@ -420,7 +423,9 @@ fr:
|
|||
invalid: "doit posséder 13 ou 14 caractères"
|
||||
reference_avis:
|
||||
invalid: "doit posséder 13 ou 14 caractères"
|
||||
|
||||
errors:
|
||||
format: "Le champ « %{attribute} » %{message}"
|
||||
messages:
|
||||
saml_not_authorized: "Vous n’êtes pas autorisé à accéder à ce service."
|
||||
dossier_not_found: "Le dossier n’existe pas ou vous n’y avez pas accès."
|
||||
|
|
|
@ -10,6 +10,6 @@ fr:
|
|||
siret:
|
||||
attributes:
|
||||
siret:
|
||||
length: 'Le numéro SIRET doit comporter 14 chiffres'
|
||||
checksum: 'Le numéro SIRET comporte une erreur, vérifiez les chiffres composant le numéro'
|
||||
invalid: 'Le numéro SIRET ne correspond pas à un établissement existant'
|
||||
length: 'est invalide. Saisir un numéro SIRET avec 14 chiffres'
|
||||
checksum: 'comporte une erreur. Vérifier les chiffres composant le numéro'
|
||||
invalid: 'ne correspond pas à un établissement existant'
|
||||
|
|
|
@ -10,7 +10,7 @@ fr:
|
|||
reponse_donnee_le: "Réponse donnée le %{date}"
|
||||
en_attente: "En attente de réponse"
|
||||
france_connect_login:
|
||||
title: 'Avec FranceConnect'
|
||||
title: 'Se créer un compte avec FranceConnect'
|
||||
description: "FranceConnect est la solution proposée par l’État pour sécuriser et simplifier la connexion aux services en ligne."
|
||||
login_button: "S’identifier avec"
|
||||
help_link: "Qu’est-ce que FranceConnect ?"
|
||||
|
|
|
@ -58,7 +58,7 @@ describe Administrateurs::TypesDeChampController, type: :controller do
|
|||
it do
|
||||
is_expected.to have_http_status(:ok)
|
||||
expect(assigns(:coordinate)).to be_nil
|
||||
expect(flash.alert).to eq(["Libelle doit être rempli"])
|
||||
expect(flash.alert).to eq(["Le champ « Libelle » doit être rempli"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -94,7 +94,7 @@ describe Administrateurs::TypesDeChampController, type: :controller do
|
|||
it do
|
||||
is_expected.to have_http_status(:ok)
|
||||
expect(assigns(:coordinate)).to be_nil
|
||||
expect(flash.alert).to eq(["Libelle doit être rempli"])
|
||||
expect(flash.alert).to eq(["Le champ « Libelle » doit être rempli"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -949,7 +949,7 @@ describe API::V2::GraphqlController do
|
|||
it "should fail" do
|
||||
expect(gql_errors).to eq(nil)
|
||||
expect(gql_data).to eq(dossierEnvoyerMessage: {
|
||||
errors: [{ message: "Votre message ne peut être vide" }],
|
||||
errors: [{ message: "Le champ « Votre message » ne peut être vide" }],
|
||||
message: nil
|
||||
})
|
||||
end
|
||||
|
|
|
@ -360,7 +360,7 @@ describe Experts::AvisController, type: :controller do
|
|||
|
||||
it do
|
||||
expect(response).to render_template :instruction
|
||||
expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"])
|
||||
expect(flash.alert).to eq(["toto.fr : Le champ « Email » n'est pas valide"])
|
||||
expect(Avis.last).to eq(previous_avis)
|
||||
expect(dossier.last_avis_updated_at).to eq(nil)
|
||||
end
|
||||
|
@ -382,7 +382,7 @@ describe Experts::AvisController, type: :controller do
|
|||
|
||||
it do
|
||||
expect(response).to render_template :instruction
|
||||
expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"])
|
||||
expect(flash.alert).to eq(["toto.fr : Le champ « Email » n'est pas valide"])
|
||||
expect(flash.notice).to eq("Une demande d’avis a été envoyée à titi@titimail.com")
|
||||
expect(Avis.count).to eq(old_avis_count + 1)
|
||||
end
|
||||
|
|
|
@ -608,7 +608,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
before { subject }
|
||||
|
||||
it { expect(response).to render_template :avis }
|
||||
it { expect(flash.alert).to eq(["emaila.com : Email n'est pas valide"]) }
|
||||
it { expect(flash.alert).to eq(["emaila.com : Le champ « Email » n'est pas valide"]) }
|
||||
it { expect { subject }.not_to change(Avis, :count) }
|
||||
it { expect(dossier.last_avis_updated_at).to eq(nil) }
|
||||
end
|
||||
|
@ -619,7 +619,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
before { subject }
|
||||
|
||||
it { expect(response).to render_template :avis }
|
||||
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }
|
||||
it { expect(flash.alert).to eq(["toto.fr : Le champ « Email » n'est pas valide"]) }
|
||||
it { expect(flash.notice).to eq("Une demande d’avis a été envoyée à titi@titimail.com") }
|
||||
it { expect(Avis.count).to eq(old_avis_count + 1) }
|
||||
it { expect(saved_avis.expert.email).to eq("titi@titimail.com") }
|
||||
|
|
|
@ -40,7 +40,7 @@ describe Manager::UsersController, type: :controller do
|
|||
subject
|
||||
|
||||
expect(User.find_by(id: user.id).email).not_to eq(nouvel_email)
|
||||
expect(flash[:error]).to match("Courriel invalide")
|
||||
expect(flash[:error]).to match("Le champ « Adresse éléctronique » est invalide. Saisir une adresse éléctronique valide, exemple : john.doe@exemple.fr")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -169,7 +169,7 @@ describe Users::DossiersController, type: :controller do
|
|||
|
||||
it do
|
||||
expect(response).not_to have_http_status(:redirect)
|
||||
expect(flash[:alert]).to include("Civilité doit être rempli", "Nom doit être rempli", "Prénom doit être rempli")
|
||||
expect(flash[:alert]).to include("Le champ « Civilité » doit être rempli", "Le champ « Nom » doit être rempli", "Le champ « Prénom » doit être rempli")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -239,7 +239,7 @@ describe Users::DossiersController, type: :controller do
|
|||
context 'with an invalid SIRET' do
|
||||
let(:params_siret) { '000 000' }
|
||||
|
||||
it_behaves_like 'the request fails with an error', ['Siret Le numéro SIRET doit comporter 14 chiffres']
|
||||
it_behaves_like 'the request fails with an error', ['Le champ « Siret » est invalide. Saisir un numéro SIRET avec 14 chiffres']
|
||||
end
|
||||
|
||||
context 'with a valid SIRET' do
|
||||
|
|
|
@ -36,7 +36,7 @@ describe Users::ProfilController, type: :controller do
|
|||
it 'fails' do
|
||||
patch :update_email, params: { user: { email: user.email } }
|
||||
expect(response).to have_http_status(302)
|
||||
expect(flash[:alert]).to eq(["La nouvelle adresse email ne peut être identique à l’ancienne"])
|
||||
expect(flash[:alert]).to eq(["Le champ « La nouvelle adresse email » ne peut être identique à l’ancienne. Saisir une autre adresse email"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -83,7 +83,7 @@ describe Users::ProfilController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(response).to redirect_to(profil_path) }
|
||||
it { expect(flash.alert).to eq(['Courriel invalide']) }
|
||||
it { expect(flash.alert).to eq(["Le champ « Adresse éléctronique » est invalide. Saisir une adresse éléctronique valide, exemple : john.doe@exemple.fr"]) }
|
||||
end
|
||||
|
||||
context 'when the user has an instructeur role' do
|
||||
|
|
|
@ -62,7 +62,7 @@ describe Users::SessionsController, type: :controller do
|
|||
subject
|
||||
|
||||
expect(response).to render_template(:new)
|
||||
expect(flash.alert).to eq('Courriel ou mot de passe incorrect.')
|
||||
expect(flash.alert).to eq("Adresse éléctronique ou mot de passe incorrect.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,7 +63,7 @@ describe Champs::CnafChamp, type: :model do
|
|||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Code postal doit posséder 5 caractères"])
|
||||
expect(champ.errors.full_messages).to eq(["Le champ « Code postal » doit posséder 5 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -72,7 +72,7 @@ describe Champs::CnafChamp, type: :model do
|
|||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Numero allocataire doit être composé au maximum de 7 chiffres"])
|
||||
expect(champ.errors.full_messages).to eq(["Le champ « Numero allocataire » doit être composé au maximum de 7 chiffres"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -81,7 +81,7 @@ describe Champs::CnafChamp, type: :model do
|
|||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Numero allocataire doit être composé au maximum de 7 chiffres"])
|
||||
expect(champ.errors.full_messages).to eq(["Le champ « Numero allocataire » doit être composé au maximum de 7 chiffres"])
|
||||
end
|
||||
|
||||
context 'and the validation_context is :brouillon' do
|
||||
|
@ -96,7 +96,7 @@ describe Champs::CnafChamp, type: :model do
|
|||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Code postal doit posséder 5 caractères"])
|
||||
expect(champ.errors.full_messages).to eq(["Le champ « Code postal » doit posséder 5 caractères"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,7 +63,7 @@ describe Champs::DgfipChamp, type: :model do
|
|||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Reference avis doit posséder 13 ou 14 caractères"])
|
||||
expect(champ.errors.full_messages).to eq(["Le champ « Reference avis » doit posséder 13 ou 14 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -72,7 +72,7 @@ describe Champs::DgfipChamp, type: :model do
|
|||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Numero fiscal doit posséder 13 ou 14 caractères"])
|
||||
expect(champ.errors.full_messages).to eq(["Le champ « Numero fiscal » doit posséder 13 ou 14 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -81,7 +81,7 @@ describe Champs::DgfipChamp, type: :model do
|
|||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Numero fiscal doit posséder 13 ou 14 caractères"])
|
||||
expect(champ.errors.full_messages).to eq(["Le champ « Numero fiscal » doit posséder 13 ou 14 caractères"])
|
||||
end
|
||||
|
||||
context 'and the validation_context is :brouillon' do
|
||||
|
@ -96,7 +96,7 @@ describe Champs::DgfipChamp, type: :model do
|
|||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Reference avis doit posséder 13 ou 14 caractères"])
|
||||
expect(champ.errors.full_messages).to eq(["Le champ « Reference avis » doit posséder 13 ou 14 caractères"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,7 +31,7 @@ describe Invite do
|
|||
|
||||
it do
|
||||
expect(invite.save).to be false
|
||||
expect(invite.errors.full_messages).to eq(["Email n'est pas valide"])
|
||||
expect(invite.errors.full_messages).to eq(["Le champ « Email » n'est pas valide"])
|
||||
end
|
||||
|
||||
context 'when an email is empty' do
|
||||
|
@ -39,7 +39,7 @@ describe Invite do
|
|||
|
||||
it do
|
||||
expect(invite.save).to be false
|
||||
expect(invite.errors.full_messages).to eq(["Email doit être rempli"])
|
||||
expect(invite.errors.full_messages).to eq(["Le champ « Email » doit être rempli"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -57,7 +57,7 @@ describe ProcedureRevision do
|
|||
context 'when a libelle is missing' do
|
||||
let(:tdc_params) { text_params.except(:libelle) }
|
||||
|
||||
it { expect(subject.errors.full_messages).to eq(["Libelle doit être rempli"]) }
|
||||
it { expect(subject.errors.full_messages).to eq(["Le champ « Libelle » doit être rempli"]) }
|
||||
end
|
||||
|
||||
context 'when a parent is incorrect' do
|
||||
|
|
|
@ -84,7 +84,7 @@ describe SuperAdmin, type: :model do
|
|||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
it 'reports an error about password length (but not about complexity)' do
|
||||
expect(subject).to eq(["Le mot de passe est trop court"])
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 8 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -92,7 +92,7 @@ describe SuperAdmin, type: :model do
|
|||
context 'when the password is long enough, but too simple' do
|
||||
let(:password) { simple_password }
|
||||
|
||||
it { expect(subject).to eq(["Le mot de passe n’est pas assez complexe"]) }
|
||||
it { expect(subject).to eq(["Le champ « Mot de passe » n’est pas assez complexe. Saisir un mot de passe plus complexe"]) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ describe TypeDeChamp do
|
|||
it { is_expected.to be_invalid }
|
||||
it do
|
||||
subject.validate
|
||||
expect(subject.errors.full_messages.to_sentence).to eq('Troll always invalid')
|
||||
expect(subject.errors.full_messages.to_sentence).to eq("Le champ « Troll » always invalid")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -156,13 +156,13 @@ describe TypeDeChamp do
|
|||
expect(type_de_champ.validate).to be_falsey
|
||||
messages = type_de_champ.errors.full_messages
|
||||
expect(messages.size).to eq(1)
|
||||
expect(messages.first.starts_with?("#{type_de_champ.libelle} doit commencer par")).to be_truthy
|
||||
expect(messages.first).to eq("Le champ « #{type_de_champ.libelle} » doit commencer par une entrée de menu primaire de la forme <code style='white-space: pre-wrap;'>--texte--</code>")
|
||||
|
||||
type_de_champ.libelle = ''
|
||||
expect(type_de_champ.validate).to be_falsey
|
||||
messages = type_de_champ.errors.full_messages
|
||||
expect(messages.size).to eq(2)
|
||||
expect(messages.last.starts_with?("La liste doit commencer par")).to be_truthy
|
||||
expect(messages.last).to eq("Le champ « La liste » doit commencer par une entrée de menu primaire de la forme <code style='white-space: pre-wrap;'>--texte--</code>")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
|
|||
it { is_expected.to be_invalid }
|
||||
it do
|
||||
subject.validate
|
||||
expect(subject.errors.full_messages).to eq ["#{subject.libelle} doit commencer par une entrée de menu primaire de la forme <code style='white-space: pre-wrap;'>--texte--</code>"]
|
||||
expect(subject.errors.full_messages).to eq ["Le champ « #{subject.libelle} » doit commencer par une entrée de menu primaire de la forme <code style='white-space: pre-wrap;'>--texte--</code>"]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -378,7 +378,7 @@ describe User, type: :model do
|
|||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
it 'reports an error about password length (but not about complexity)' do
|
||||
expect(subject).to eq(["Le mot de passe est trop court"])
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 8 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -386,7 +386,7 @@ describe User, type: :model do
|
|||
context 'when the password is long enough, but too simple' do
|
||||
let(:password) { simple_password }
|
||||
|
||||
it { expect(subject).to eq(["Le mot de passe n’est pas assez complexe"]) }
|
||||
it { expect(subject).to eq(["Le champ « Mot de passe » n’est pas assez complexe. Saisir un mot de passe plus complexe"]) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -404,7 +404,7 @@ describe User, type: :model do
|
|||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
it 'reports an error about password length (but not about complexity)' do
|
||||
expect(subject).to eq(["Le mot de passe est trop court"])
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 8 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ describe BillSignatureService do
|
|||
let(:operations_hash) { [['1', 'hash1'], ['2', 'hash3']] }
|
||||
|
||||
it do
|
||||
expect { subject }.to raise_error(/La validation a échoué : signature ne correspond pas à l’empreinte/)
|
||||
expect { subject }.to raise_error(/La validation a échoué : Le champ « signature » ne correspond pas à l’empreinte/)
|
||||
expect(BillSignature.count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,6 +17,6 @@ shared_examples "the user has got a prefilled dossier, owned by themselves" do
|
|||
expect(page).to have_current_path(brouillon_dossier_path(dossier))
|
||||
expect(page).to have_field(type_de_champ_text.libelle, with: text_value)
|
||||
expect(page).to have_field(type_de_champ_phone.libelle, with: phone_value)
|
||||
expect(page).to have_css('.field_with_errors', text: type_de_champ_phone.libelle)
|
||||
expect(page).to have_css('label', text: type_de_champ_phone.libelle)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ describe 'Creating a new procedure', js: true do
|
|||
fill_in 'procedure_duree_conservation_dossiers_dans_ds', with: '3'
|
||||
click_on 'Créer la démarche'
|
||||
|
||||
expect(page).to have_text('Libelle doit être rempli')
|
||||
expect(page).to have_text('Le champ « Libelle » doit être rempli')
|
||||
fill_in_dummy_procedure_details
|
||||
click_on 'Créer la démarche'
|
||||
|
||||
|
|
|
@ -282,7 +282,7 @@ describe 'fetch API Particulier Data', js: true do
|
|||
wait_until { cnaf_champ.reload.code_postal == 'wrong_code' }
|
||||
|
||||
click_on 'Déposer le dossier'
|
||||
expect(page).to have_content(/code postal doit posséder 5 caractères/)
|
||||
expect(page).to have_content(/Le champ « Champs public code postal » doit posséder 5 caractères/)
|
||||
|
||||
VCR.use_cassette('api_particulier/success/composition_familiale') do
|
||||
fill_in 'Le code postal', with: code_postal
|
||||
|
@ -470,7 +470,7 @@ describe 'fetch API Particulier Data', js: true do
|
|||
wait_until { dgfip_champ.reload.reference_avis == 'wrong_code' }
|
||||
|
||||
click_on 'Déposer le dossier'
|
||||
expect(page).to have_content(/reference avis doit posséder 13 ou 14 caractères/)
|
||||
expect(page).to have_content(/Le champ « Champs public reference avis » doit posséder 13 ou 14 caractères/)
|
||||
|
||||
VCR.use_cassette('api_particulier/success/avis_imposition') do
|
||||
fill_in "La référence d’avis d’imposition", with: reference_avis
|
||||
|
|
|
@ -5,7 +5,7 @@ describe 'Accessing the website in different languages:' do
|
|||
|
||||
scenario 'I can change the language of the page' do
|
||||
visit new_user_session_path
|
||||
expect(page).to have_text('Connectez-vous')
|
||||
expect(page).to have_text("Connexion à #{APPLICATION_NAME}")
|
||||
|
||||
find('.fr-translate__btn').click
|
||||
find('.fr-nav__link[hreflang="en"]').click
|
||||
|
|
|
@ -7,8 +7,8 @@ describe 'Signin in:' do
|
|||
click_on 'Se connecter', match: :first
|
||||
|
||||
sign_in_with user.email, 'invalid-password'
|
||||
expect(page).to have_content 'Courriel ou mot de passe incorrect.'
|
||||
expect(page).to have_field('Email', with: user.email)
|
||||
expect(page).to have_content 'Adresse éléctronique ou mot de passe incorrect.'
|
||||
expect(page).to have_field('Adresse éléctronique', with: user.email)
|
||||
|
||||
sign_in_with user.email, password
|
||||
expect(page).to have_current_path dossiers_path
|
||||
|
|
|
@ -114,7 +114,7 @@ describe 'Creating a new dossier:' do
|
|||
click_on 'Valider'
|
||||
|
||||
expect(page).to have_current_path(siret_dossier_path(dossier))
|
||||
expect(page).to have_content('Le numéro SIRET doit comporter 14 chiffres')
|
||||
expect(page).to have_content('Le champ « Siret » est invalide. Saisir un numéro SIRET avec 14 chiffres')
|
||||
expect(page).to have_field('Numéro SIRET', with: '0000')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,27 +21,27 @@ describe 'Signing up:' do
|
|||
visit commencer_path(path: procedure.path)
|
||||
click_on "Créer un compte #{APPLICATION_NAME}"
|
||||
expect(page).to have_selector('.suspect-email', visible: false)
|
||||
fill_in 'Email', with: 'bidou@yahoo.rf'
|
||||
fill_in 'Adresse éléctronique', with: 'bidou@yahoo.rf'
|
||||
fill_in 'Mot de passe', with: '12345'
|
||||
end
|
||||
|
||||
scenario 'they can accept the suggestion', js: true do
|
||||
expect(page).to have_selector('.suspect-email', visible: true)
|
||||
click_on 'Oui'
|
||||
expect(page).to have_field("Email", :with => 'bidou@yahoo.fr')
|
||||
expect(page).to have_field("Adresse éléctronique", :with => 'bidou@yahoo.fr')
|
||||
expect(page).to have_selector('.suspect-email', visible: false)
|
||||
end
|
||||
|
||||
scenario 'they can discard the suggestion', js: true do
|
||||
expect(page).to have_selector('.suspect-email', visible: true)
|
||||
click_on 'Non'
|
||||
expect(page).to have_field("Email", :with => 'bidou@yahoo.rf')
|
||||
expect(page).to have_field("Adresse éléctronique", :with => 'bidou@yahoo.rf')
|
||||
expect(page).to have_selector('.suspect-email', visible: false)
|
||||
end
|
||||
|
||||
scenario 'they can fix the typo themselves', js: true do
|
||||
expect(page).to have_selector('.suspect-email', visible: true)
|
||||
fill_in 'Email', with: 'bidou@yahoo.fr'
|
||||
fill_in 'Adresse éléctronique', with: 'bidou@yahoo.fr'
|
||||
blur
|
||||
expect(page).to have_selector('.suspect-email', visible: false)
|
||||
end
|
||||
|
@ -54,7 +54,7 @@ describe 'Signing up:' do
|
|||
expect(page).to have_current_path new_user_registration_path
|
||||
sign_up_with user_email, '1234567'
|
||||
expect(page).to have_current_path user_registration_path
|
||||
expect(page).to have_content 'Le mot de passe est trop court'
|
||||
expect(page).to have_content "Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 8 caractères"
|
||||
|
||||
# Then with a good password
|
||||
sign_up_with user_email, user_password
|
||||
|
|
|
@ -3,7 +3,7 @@ describe 'users/sessions/new.html.haml', type: :view do
|
|||
|
||||
before(:each) do
|
||||
allow(view).to receive(:devise_mapping).and_return(Devise.mappings[:user])
|
||||
allow(view).to receive(:resource).and_return(:user)
|
||||
allow(view).to receive(:resource).and_return(User.new)
|
||||
end
|
||||
|
||||
before do
|
||||
|
@ -12,7 +12,7 @@ describe 'users/sessions/new.html.haml', type: :view do
|
|||
end
|
||||
|
||||
it 'renders' do
|
||||
expect(rendered).to have_field('Email')
|
||||
expect(rendered).to have_field('Adresse éléctronique')
|
||||
expect(rendered).to have_field('Mot de passe')
|
||||
expect(rendered).to have_button('Se connecter')
|
||||
end
|
||||
|
|
143
vendor/assets/stylesheets/franceconnect.scss
vendored
143
vendor/assets/stylesheets/franceconnect.scss
vendored
|
@ -1,143 +0,0 @@
|
|||
.btn-fconnect {
|
||||
all: initial;
|
||||
color: #0b6ba8;
|
||||
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||
background-color: #ffffff;
|
||||
background-image: none;
|
||||
border: 1px solid #ccc;
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 1px rgba(255,255,255,0.75);
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.btn-fconnect-full {
|
||||
font-size: 14px;
|
||||
max-width: 175px;
|
||||
padding: 11px 19px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn-fconnect-mini {
|
||||
font-size: 14px;
|
||||
width: 182px;
|
||||
padding: 11px 19px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn-fconnect-full img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-fconnect-mini img {
|
||||
float:left;
|
||||
width: 38px;
|
||||
}
|
||||
|
||||
#fconnect-access {
|
||||
all: initial;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
display: none;
|
||||
position: absolute;
|
||||
background: white;
|
||||
border: 1px solid #ccc;
|
||||
width: 300px;
|
||||
padding: 15px;
|
||||
margin-top: 20px;
|
||||
z-index: 9990;
|
||||
box-shadow: 1px 1px 3px #ccc;
|
||||
}
|
||||
|
||||
#fconnect-access hr {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
#fconnect-access:after, #fconnect-access:before {
|
||||
bottom: 100%;
|
||||
border: solid transparent;
|
||||
content: "";
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#fconnect-access:after {
|
||||
border-bottom-color: white;
|
||||
border-width: 13px;
|
||||
left: 10%;
|
||||
}
|
||||
|
||||
#fconnect-access:before {
|
||||
border-bottom-color: #ccc;
|
||||
border-width: 14px;
|
||||
left: 9.70%;
|
||||
}
|
||||
|
||||
#fconnect-access .logout {
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#fconnect-access .btn {
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
touch-action: manipulation;
|
||||
cursor: pointer;
|
||||
background-image: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#fconnect-access .btn-default {
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
border-color: #ccc;
|
||||
}
|
||||
|
||||
#fconnect-access .btn-default:hover,
|
||||
#fconnect-access .btn-default:focus {
|
||||
color: #333;
|
||||
background-color: #e6e6e6;
|
||||
border-color: #adadad;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#fc-background {
|
||||
all: initial;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.80);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in;
|
||||
}
|
||||
|
||||
#fc-background.fade-in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#fc-background.fade-out {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#fconnect-iframe {
|
||||
display: block;
|
||||
width: 600px;
|
||||
height: 500px;
|
||||
margin: 60px auto 0 auto;
|
||||
}
|
||||
|
Loading…
Reference in a new issue