diff --git a/app/views/admin/_closed_mail_template_attestation_inconsistency_alert.html.erb b/app/views/admin/_closed_mail_template_attestation_inconsistency_alert.html.erb
new file mode 100644
index 00000000000..5b3e4e39790
--- /dev/null
+++ b/app/views/admin/_closed_mail_template_attestation_inconsistency_alert.html.erb
@@ -0,0 +1,30 @@
+<% case @procedure.closed_mail_template_attestation_inconsistency_state %>
+<% when :missing_tag %>
+
+
+ Cette démarche comporte une attestation, mais l’accusé d’acceptation ne la mentionne pas :
+ <% unless @procedure.locked? %>
+ <%= link_to('désactivez l’attestation', edit_admin_procedure_attestation_template_path(@procedure)) %>
+ ou
+ <% end %>
+ <%= link_to('ajoutez la balise', edit_admin_procedure_mail_template_path(@procedure, Mails::ClosedMail::SLUG)) %>
+
+ --lien attestation--
+
+ à l’accusé d’acceptation
+
+
+<% when :extraneous_tag %>
+
+
+ Cette démarche ne comporte pas d’attestation, mais l’accusé d’acceptation en mentionne une :
+ <%= link_to('activez l’attestation', edit_admin_procedure_attestation_template_path(@procedure)) %>
+ ou
+ <%= link_to('enlevez la balise', edit_admin_procedure_mail_template_path(@procedure, Mails::ClosedMail::SLUG)) %>
+
+ --lien attestation--
+
+ de l’accusé d’acceptation
+
+
+<% end %>
diff --git a/app/views/admin/_closed_mail_template_attestation_inconsistency_alert.html.haml b/app/views/admin/_closed_mail_template_attestation_inconsistency_alert.html.haml
deleted file mode 100644
index a0ea44b394c..00000000000
--- a/app/views/admin/_closed_mail_template_attestation_inconsistency_alert.html.haml
+++ /dev/null
@@ -1,22 +0,0 @@
-- case @procedure.closed_mail_template_attestation_inconsistency_state
-- when :missing_tag
- .center
- .alert{ class: flash_class('alert') }
- Cette démarche comporte une attestation, mais l’accusé d’acceptation ne la mentionne pas :
- - if !@procedure.locked?
- = link_to('désactivez l’attestation', edit_admin_procedure_attestation_template_path(@procedure))
- ou
- = link_to('ajoutez la balise', edit_admin_procedure_mail_template_path(@procedure, Mails::ClosedMail::SLUG))
- %code{ style: "white-space: pre-wrap;" }
- \--lien attestation--
- à l’accusé d’acceptation
-- when :extraneous_tag
- .center
- .alert{ class: flash_class('alert') }
- Cette démarche ne comporte pas d’attestation, mais l’accusé d’acceptation en mentionne une :
- = link_to('activez l’attestation', edit_admin_procedure_attestation_template_path(@procedure))
- ou
- = link_to('enlevez la balise', edit_admin_procedure_mail_template_path(@procedure, Mails::ClosedMail::SLUG))
- %code{ style: "white-space: pre-wrap;" }
- \--lien attestation--
- de l’accusé d’acceptation
diff --git a/app/views/administrate/application/_pagination.html.erb b/app/views/administrate/application/_pagination.html.erb
new file mode 100644
index 00000000000..c765d7444fd
--- /dev/null
+++ b/app/views/administrate/application/_pagination.html.erb
@@ -0,0 +1,8 @@
+<% if resources.singleton_class.included_modules.include?(Kaminari::PaginatableWithoutCount) %>
+
+<% else %>
+ <%= paginate resources, param_name: local_assigns.fetch(:param_name) { '_page' } %>
+<% end %>
diff --git a/app/views/administrate/application/_pagination.html.haml b/app/views/administrate/application/_pagination.html.haml
deleted file mode 100644
index 731a09cb5d2..00000000000
--- a/app/views/administrate/application/_pagination.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- if resources.singleton_class.included_modules.include?(Kaminari::PaginatableWithoutCount)
- %nav.pagination
- = link_to_prev_page resources, t("views.pagination.previous").html_safe, param_name: "_page"
- = link_to_next_page resources, t("views.pagination.next").html_safe, param_name: "_page"
-- else
- = paginate resources, param_name: local_assigns.fetch(:param_name) { "_page" }
diff --git a/app/views/administrateur_mailer/activate_before_expiration.haml b/app/views/administrateur_mailer/activate_before_expiration.haml
deleted file mode 100644
index ffaa8f74b07..00000000000
--- a/app/views/administrateur_mailer/activate_before_expiration.haml
+++ /dev/null
@@ -1,18 +0,0 @@
-- content_for(:title, @subject)
-
-%p
- Bonjour,
-
-%p
- Vous avez fait la demande d’un compte administrateur sur #{Current.application_name}.
- Votre compte a été créé mais reste inactif, il arrivera à expiration le #{try_format_date(@expiration_date)}
-
-%p
- Afin d’activer votre compte, veuillez cliquer sur le lien ci-dessous :
- = link_to(users_activate_url(token: @reset_password_token), users_activate_url(token: @reset_password_token))
-
-%p
- Nous restons à votre disposition si vous avez besoin d’accompagnement.
-
-%p
- = render partial: "layouts/mailers/bizdev_signature", locals: { author_name: "Benjamin Doberset" }
diff --git a/app/views/administrateur_mailer/activate_before_expiration.html.erb b/app/views/administrateur_mailer/activate_before_expiration.html.erb
new file mode 100644
index 00000000000..0f3174a44c2
--- /dev/null
+++ b/app/views/administrateur_mailer/activate_before_expiration.html.erb
@@ -0,0 +1,23 @@
+<% content_for(:title, @subject) %>
+
+
+ Bonjour,
+
+
+
+ Vous avez fait la demande d’un compte administrateur sur <%= Current.application_name %>.
+ Votre compte a été créé mais reste inactif, il arrivera à expiration le <%= try_format_date(@expiration_date) %>
+
+
+
+ Afin d’activer votre compte, veuillez cliquer sur le lien ci-dessous :
+ <%= link_to(users_activate_url(token: @reset_password_token), users_activate_url(token: @reset_password_token)) %>
+
+
+
+ Nous restons à votre disposition si vous avez besoin d’accompagnement.
+
+
+
+ <%= render partial: 'layouts/mailers/bizdev_signature', locals: { author_name: 'Benjamin Doberset' } %>
+
diff --git a/app/views/administrateur_mailer/api_token_expiration.haml b/app/views/administrateur_mailer/api_token_expiration.haml
deleted file mode 100644
index f850431430f..00000000000
--- a/app/views/administrateur_mailer/api_token_expiration.haml
+++ /dev/null
@@ -1,19 +0,0 @@
-- content_for(:title, @subject)
-
-%p
- Bonjour,
-
-%p
- - if @tokens.one?
- Votre jeton d'API « #{@tokens.first.prefix} » expirera le 1er juillet 2023.
- - else
- Vos jetons d'API « #{@tokens.map(&:prefix).join(', ')} » expireront le 1er juillet 2023.
- Passée cette date, vos interconnexions utilisant ce jeton ne marcheront plus.
-
-%p
- Vous devrez le(s) remplacer par de nouveaux jetons que vous pouvez obtenir en utilisant la page #{link_to(profil_url, profil_url)}.
-
-%p
- Nous restons à votre disposition si vous avez besoin d’accompagnement à l'adresse #{link_to CONTACT_EMAIL, "mailto:#{CONTACT_EMAIL}"}.
-
-= render partial: "layouts/mailers/signature"
diff --git a/app/views/administrateur_mailer/api_token_expiration.html.erb b/app/views/administrateur_mailer/api_token_expiration.html.erb
new file mode 100644
index 00000000000..20e28922aa0
--- /dev/null
+++ b/app/views/administrateur_mailer/api_token_expiration.html.erb
@@ -0,0 +1,24 @@
+<% content_for(:title, @subject) %>
+
+
+ Bonjour,
+
+
+
+ <% if @tokens.one? %>
+ Votre jeton d'API « <%= @tokens.first.prefix %> » expirera le 1er juillet 2023.
+ <% else %>
+ Vos jetons d'API « <%= @tokens.map(&:prefix).join(', ') %> » expireront le 1er juillet 2023.
+ <% end %>
+ Passée cette date, vos interconnexions utilisant ce jeton ne marcheront plus.
+
+
+
+ Vous devrez le(s) remplacer par de nouveaux jetons que vous pouvez obtenir en utilisant la page <%= link_to(profil_url, profil_url) %>.
+
+
+
+ Nous restons à votre disposition si vous avez besoin d’accompagnement à l'adresse <%= link_to CONTACT_EMAIL, "mailto:#{CONTACT_EMAIL}" %>.
+
+
+<%= render partial: 'layouts/mailers/signature' %>
diff --git a/app/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.haml b/app/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.haml
deleted file mode 100644
index c8d6bbee526..00000000000
--- a/app/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- content_for(:title, "Suppression des dossiers automatique activée")
-
-%p
- Bonjour,
-
-%p
- Le règlement général sur la protection des données (RGPD) responsabilise les organismes publics et privés qui traitent leurs données.
-
-%p
- Dans le cadre du respect du RGPD, nous (la plateforme #{Current.application_name}) venons d'activer la suppression automatique des dossiers sur la démarche : "#{@procedure.libelle}".
-
-%p
- Vous pouvez d’ores et déjà archiver ces données en accédant à
- = link_to("notre systeme d'archivage pour les admnistrateurs de démarche",admin_procedures_archived_url(@procedure) )
- \.
-
-= render partial: "layouts/mailers/signature"
diff --git a/app/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.html.erb b/app/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.html.erb
new file mode 100644
index 00000000000..9435d637d44
--- /dev/null
+++ b/app/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.html.erb
@@ -0,0 +1,20 @@
+<% content_for(:title, 'Suppression des dossiers automatique activée') %>
+
+
+ Bonjour,
+
+
+
+ Le règlement général sur la protection des données (RGPD) responsabilise les organismes publics et privés qui traitent leurs données.
+
+
+
+ Dans le cadre du respect du RGPD, nous (la plateforme <%= Current.application_name %>) venons d'activer la suppression automatique des dossiers sur la démarche : "<%= @procedure.libelle %>".
+
+
+
+ Vous pouvez d’ores et déjà archiver ces données en accédant à
+ <%= link_to("notre systeme d'archivage pour les admnistrateurs de démarche", admin_procedures_archived_url(@procedure)) %>.
+
+
+<%= render partial: 'layouts/mailers/signature' %>
diff --git a/app/views/administrateur_mailer/notify_service_without_siret.haml b/app/views/administrateur_mailer/notify_service_without_siret.html.erb
similarity index 51%
rename from app/views/administrateur_mailer/notify_service_without_siret.haml
rename to app/views/administrateur_mailer/notify_service_without_siret.html.erb
index 4952736449b..cfd3213c741 100644
--- a/app/views/administrateur_mailer/notify_service_without_siret.haml
+++ b/app/views/administrateur_mailer/notify_service_without_siret.html.erb
@@ -1,15 +1,18 @@
-- content_for(:title, "Service avec Siret manquant")
+<% content_for(:title, 'Service avec Siret manquant') %>
-%p
+
Bonjour,
+
-%p
+
Vous êtes administrateur sur la plateforme
- = Current.application_name
+ <%= Current.application_name %>
et au moins un de vos services n'a pas son siret renseigné.
+
-%p
+
Afin d'éviter tout dysfonctionnement sur la plateforme, nous vous invitons à le remplir au plus vite à cette adresse :
- = link_to admin_procedures_url, admin_procedures_url
+ <%= link_to admin_procedures_url, admin_procedures_url %>
+
-= render partial: "layouts/mailers/signature"
+<%= render partial: 'layouts/mailers/signature' %>
diff --git a/app/views/administrateurs/_breadcrumbs.html.erb b/app/views/administrateurs/_breadcrumbs.html.erb
new file mode 100644
index 00000000000..5c92fb75336
--- /dev/null
+++ b/app/views/administrateurs/_breadcrumbs.html.erb
@@ -0,0 +1,66 @@
+
diff --git a/app/views/administrateurs/_breadcrumbs.html.haml b/app/views/administrateurs/_breadcrumbs.html.haml
deleted file mode 100644
index 6dd00d67178..00000000000
--- a/app/views/administrateurs/_breadcrumbs.html.haml
+++ /dev/null
@@ -1,50 +0,0 @@
-#breadcrumbs.sub-header
- .fr-container.flex.justify-between.align-baseline.column
- %nav.fr-breadcrumb.mt-0{ role: "navigation", aria: { label: t('you_are_here', scope: [:layouts, :breadcrumb]) } }
- %button.fr-breadcrumb__button{ aria: { expanded: "false", controls: "breadcrumb-1" } }
- = t('show', scope: [:layouts, :breadcrumb])
-
- .fr-collapse#breadcrumb-1
- %ol.fr-breadcrumb__list
- %li= link_to t('root', scope: [:layouts, :breadcrumb]), root_path, class: 'fr-breadcrumb__link'
-
- - steps.each.with_index do |step, i|
- - if i == steps.size - 1
- %li= link_to step[0], '', { aria: { current: "page" } , class: 'fr-breadcrumb__link' }
- - else
- %li= link_to step[0], step[1], class: 'fr-breadcrumb__link'
-
- - if defined?(metadatas)
- .metadatas.pb-3
- %h1.fr-h6.fr-mb-1w
- = @procedure.libelle
-
- - if @procedure.close?
- .flex
- %span.fr-badge.fr-badge--warning.fr-mr-1w
- = t('closed', scope: [:layouts, :breadcrumb])
- = t('since', scope: [:layouts, :breadcrumb], date: l(@procedure.closed_at.to_date))
-
- - elsif @procedure.locked?
- = link_to commencer_url(@procedure.path), commencer_url(@procedure.path), class: "fr-link"
-
- = link_to "", admin_procedure_path_path(@procedure), class: "fr-btn fr-icon-pencil-line fr-btn--sm fr-btn--tertiary-no-outline", "aria-label": t('edit_path', scope: [:layouts, :breadcrumb]), title: t('edit_path', scope: [:layouts, :breadcrumb])
-
- .flex.fr-mt-1w
-
- - if @procedure.api_entreprise_token.expired_or_expires_soon?
- %span.fr-badge.fr-badge--error.fr-mr-1w
- = t('to_modify', scope: [:layouts, :breadcrumb])
-
- %span.fr-badge.fr-badge--success.fr-mr-1w
- = t('published', scope: [:layouts, :breadcrumb])
- = t('since', scope: [:layouts, :breadcrumb], number: @procedure.id, date: l(@procedure.published_at.to_date))
-
- - else
- %p.fr-mb-1w
- = t('more_info_on_test', scope: [:layouts, :breadcrumb])
- = link_to t('go_to_FAQ', scope: [:layouts, :breadcrumb]), t("url_FAQ", scope: [:layouts, :breadcrumb]), title: new_tab_suffix(t('go_to_FAQ', scope: [:layouts, :breadcrumb]))
- .flex
- %span.fr-badge.fr-badge--new.fr-mr-1w
- = t('draft', scope: [:layouts, :breadcrumb])
- = t('since', scope: [:layouts, :breadcrumb], number: @procedure.id, date: l(@procedure.created_at.to_date))
diff --git a/app/views/administrateurs/_groups_header.haml b/app/views/administrateurs/_groups_header.haml
deleted file mode 100644
index 36493a51985..00000000000
--- a/app/views/administrateurs/_groups_header.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-%h1 Groupe « #{@groupe_instructeur.label} »
-.card.mt-2
- = form_for @groupe_instructeur,
- url: admin_procedure_groupe_instructeur_path(@procedure, @groupe_instructeur),
- html: { class: 'form' } do |f|
-
- = f.label :label, 'Nom du groupe'
- = f.text_field :label, placeholder: 'Ville de Bordeaux', required: true
- .editable-champ.editable-champ-checkbox
- = f.label :closed, 'Groupe inactif'
- .notice
- %p Si cette option est activée, les usagers ne pourront plus sélectionner ce groupe d'instructeurs
- = f.check_box :closed
-
- %br
- = f.submit 'Modifier le groupe', class: 'button primary send'
diff --git a/app/views/administrateurs/_groups_header.html.erb b/app/views/administrateurs/_groups_header.html.erb
new file mode 100644
index 00000000000..62a8b13883c
--- /dev/null
+++ b/app/views/administrateurs/_groups_header.html.erb
@@ -0,0 +1,19 @@
+Groupe « <%= @groupe_instructeur.label %> »
+
+ <%= form_for @groupe_instructeur,
+ url: admin_procedure_groupe_instructeur_path(@procedure, @groupe_instructeur),
+ html: { class: 'form' } do |f| %>
+ <%= f.label :label, 'Nom du groupe' %>
+ <%= f.text_field :label, placeholder: 'Ville de Bordeaux', required: true %>
+
+ <%= f.label :closed, 'Groupe inactif' %>
+
+
Si cette option est activée, les usagers ne pourront plus sélectionner ce groupe d'instructeurs
+
+ <%= f.check_box :closed %>
+
+
+
+ <%= f.submit 'Modifier le groupe', class: 'button primary send' %>
+ <% end %>
+
diff --git a/app/views/administrateurs/_login_banner.html.erb b/app/views/administrateurs/_login_banner.html.erb
new file mode 100644
index 00000000000..03b47e4f854
--- /dev/null
+++ b/app/views/administrateurs/_login_banner.html.erb
@@ -0,0 +1,4 @@
+<%= link_to '/administrateurs/sign_out', method: :delete do %>
+
+ Se déconnecter
+<% end %>
diff --git a/app/views/administrateurs/_login_banner.html.haml b/app/views/administrateurs/_login_banner.html.haml
deleted file mode 100644
index 687342eb7d0..00000000000
--- a/app/views/administrateurs/_login_banner.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-= link_to "/administrateurs/sign_out", method: :delete do
- %span.fa.fa-sign-out
- Se déconnecter
diff --git a/app/views/administrateurs/_main_navigation.html.erb b/app/views/administrateurs/_main_navigation.html.erb
new file mode 100644
index 00000000000..6aa4ece1c78
--- /dev/null
+++ b/app/views/administrateurs/_main_navigation.html.erb
@@ -0,0 +1,13 @@
+
diff --git a/app/views/administrateurs/_main_navigation.html.haml b/app/views/administrateurs/_main_navigation.html.haml
deleted file mode 100644
index f775ff34a3d..00000000000
--- a/app/views/administrateurs/_main_navigation.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-#header-navigation.fr-nav
- %ul.fr-nav__list
- %li.fr-nav__item= link_to 'Mes démarches', admin_procedures_path, class:'fr-nav__link', 'aria-current': current_page?(controller: 'administrateurs/procedures', action: :index) ? 'true' : nil
- - if Rails.application.config.ds_zonage_enabled
- %li.fr-nav__item= link_to 'Toutes les démarches', all_admin_procedures_path(zone_ids: :admin_default), class:'fr-nav__link', 'aria-current': current_page?(all_admin_procedures_path) ? 'page' : nil
- - if current_administrateur.groupe_gestionnaire_id
- %li.fr-nav__item= link_to 'Mon groupe gestionnaire', admin_groupe_gestionnaire_path, class:'fr-nav__link', 'aria-current': current_page?(admin_groupe_gestionnaire_path) ? 'page' : nil
-
- = render MainNavigation::AnnouncesLinkComponent.new
diff --git a/spec/snapshots/_breadcrumbs.html.haml_spec_it_renders_the_breadcrumb_trail_with_metadatas-25.html b/spec/snapshots/_breadcrumbs.html.haml_spec_it_renders_the_breadcrumb_trail_with_metadatas-25.html
new file mode 100644
index 00000000000..40677412e22
--- /dev/null
+++ b/spec/snapshots/_breadcrumbs.html.haml_spec_it_renders_the_breadcrumb_trail_with_metadatas-25.html
@@ -0,0 +1,30 @@
+
diff --git a/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_attestation_template_edit-23.html b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_attestation_template_edit-23.html
new file mode 100644
index 00000000000..9a10e9363e2
--- /dev/null
+++ b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_attestation_template_edit-23.html
@@ -0,0 +1,12 @@
+
+
+ Cette démarche ne comporte pas d’attestation, mais l’accusé d’acceptation en mentionne une :
+
activez l’attestation
+ ou
+
enlevez la balise
+
+ --lien attestation--
+
+ de l’accusé d’acceptation
+
+
diff --git a/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_attestation_template_edit-43.html b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_attestation_template_edit-43.html
new file mode 100644
index 00000000000..40b23498d05
--- /dev/null
+++ b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_attestation_template_edit-43.html
@@ -0,0 +1,12 @@
+
diff --git a/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_mail_templates_closed_mail_edit-24.html b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_mail_templates_closed_mail_edit-24.html
new file mode 100644
index 00000000000..6fe302fdb86
--- /dev/null
+++ b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_mail_templates_closed_mail_edit-24.html
@@ -0,0 +1,12 @@
+
+
+ Cette démarche ne comporte pas d’attestation, mais l’accusé d’acceptation en mentionne une :
+
activez l’attestation
+ ou
+
enlevez la balise
+
+ --lien attestation--
+
+ de l’accusé d’acceptation
+
+
diff --git a/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_mail_templates_closed_mail_edit-32.html b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_mail_templates_closed_mail_edit-32.html
new file mode 100644
index 00000000000..ea2f0caf6f0
--- /dev/null
+++ b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_admin_procedures_mail_templates_closed_mail_edit-32.html
@@ -0,0 +1,12 @@
+
diff --git a/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_cette_d_marche_comporte_une_attestation_mais_l_accus_d_acceptation_ne_la_mentionne_pas-31.html b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_cette_d_marche_comporte_une_attestation_mais_l_accus_d_acceptation_ne_la_mentionne_pas-31.html
new file mode 100644
index 00000000000..d39a3a45f1f
--- /dev/null
+++ b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_cette_d_marche_comporte_une_attestation_mais_l_accus_d_acceptation_ne_la_mentionne_pas-31.html
@@ -0,0 +1,12 @@
+
diff --git a/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_cette_d_marche_ne_comporte_pas_d_attestation_mais_l_accus_d_acceptation_en_mentionne_une-22.html b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_cette_d_marche_ne_comporte_pas_d_attestation_mais_l_accus_d_acceptation_en_mentionne_une-22.html
new file mode 100644
index 00000000000..a71f3cf8f7d
--- /dev/null
+++ b/spec/snapshots/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec_it_is_expected_to_include_cette_d_marche_ne_comporte_pas_d_attestation_mais_l_accus_d_acceptation_en_mentionne_une-22.html
@@ -0,0 +1,12 @@
+
+
+ Cette démarche ne comporte pas d’attestation, mais l’accusé d’acceptation en mentionne une :
+
activez l’attestation
+ ou
+
enlevez la balise
+
+ --lien attestation--
+
+ de l’accusé d’acceptation
+
+
diff --git a/spec/snapshots/_groups_header.haml_spec_it_renders_the_group_header_form-14.html b/spec/snapshots/_groups_header.haml_spec_it_renders_the_group_header_form-14.html
new file mode 100644
index 00000000000..d9045f1e026
--- /dev/null
+++ b/spec/snapshots/_groups_header.haml_spec_it_renders_the_group_header_form-14.html
@@ -0,0 +1,14 @@
+Groupe « Groupe Bordeaux »
+
diff --git a/spec/snapshots/_login_banner.html.haml_spec_it_renders_the_sign_out_link-6.html b/spec/snapshots/_login_banner.html.haml_spec_it_renders_the_sign_out_link-6.html
new file mode 100644
index 00000000000..b7f9d24e095
--- /dev/null
+++ b/spec/snapshots/_login_banner.html.haml_spec_it_renders_the_sign_out_link-6.html
@@ -0,0 +1,3 @@
+
+Se déconnecter
+
\ No newline at end of file
diff --git a/spec/snapshots/_main_navigation.html.haml_spec_it_renders_the_navigation_menu-16.html b/spec/snapshots/_main_navigation.html.haml_spec_it_renders_the_navigation_menu-16.html
new file mode 100644
index 00000000000..8ec21e0ac17
--- /dev/null
+++ b/spec/snapshots/_main_navigation.html.haml_spec_it_renders_the_navigation_menu-16.html
@@ -0,0 +1,8 @@
+
diff --git a/spec/snapshots/_pagination.html.haml_spec_it_renders_navigation_when_resources_are_without_count-27.html b/spec/snapshots/_pagination.html.haml_spec_it_renders_navigation_when_resources_are_without_count-27.html
new file mode 100644
index 00000000000..4a7ef6de2b4
--- /dev/null
+++ b/spec/snapshots/_pagination.html.haml_spec_it_renders_navigation_when_resources_are_without_count-27.html
@@ -0,0 +1,4 @@
+
diff --git a/spec/snapshots/_pagination.html.haml_spec_it_renders_paginate_for_standard_resources-21.html b/spec/snapshots/_pagination.html.haml_spec_it_renders_paginate_for_standard_resources-21.html
new file mode 100644
index 00000000000..6a8919b7ac5
--- /dev/null
+++ b/spec/snapshots/_pagination.html.haml_spec_it_renders_paginate_for_standard_resources-21.html
@@ -0,0 +1 @@
+
diff --git a/spec/snapshots/activate_before_expiration.haml_spec_it_renders_the_activation_notice-15.html b/spec/snapshots/activate_before_expiration.haml_spec_it_renders_the_activation_notice-15.html
new file mode 100644
index 00000000000..950f2c86629
--- /dev/null
+++ b/spec/snapshots/activate_before_expiration.haml_spec_it_renders_the_activation_notice-15.html
@@ -0,0 +1,29 @@
+
+Bonjour,
+
+
+Vous avez fait la demande d’un compte administrateur sur .
+Votre compte a été créé mais reste inactif, il arrivera à expiration le 10 juillet 24 00:00
+
+
+Afin d’activer votre compte, veuillez cliquer sur le lien ci-dessous :
+http://test.host/users/activate?token=reset-token
+
+
+Nous restons à votre disposition si vous avez besoin d’accompagnement.
+
+
+Cordialement,
+
+
+Benjamin Doberset
+
+
+Équipe
+
+Téléphone (standard) :
+01 76 42 02 87
+
+Incubateur de Services Numériques / beta.gouv.fr
Services du Premier Ministre, 20 avenue de Ségur, 75007 Paris
+
+
diff --git a/spec/snapshots/api_token_expiration.haml_spec_it_renders_the_plural_expiration_message-29.html b/spec/snapshots/api_token_expiration.haml_spec_it_renders_the_plural_expiration_message-29.html
new file mode 100644
index 00000000000..048757e3216
--- /dev/null
+++ b/spec/snapshots/api_token_expiration.haml_spec_it_renders_the_plural_expiration_message-29.html
@@ -0,0 +1,20 @@
+
+Bonjour,
+
+
+Vos jetons d'API « ABC123, XYZ789 » expireront le 1er juillet 2023.
+Passée cette date, vos interconnexions utilisant ce jeton ne marcheront plus.
+
+
+Vous devrez le(s) remplacer par de nouveaux jetons que vous pouvez obtenir en utilisant la page https://example.test/profil.
+
+
+Nous restons à votre disposition si vous avez besoin d’accompagnement à l'adresse contact@demarches-simplifiees.fr.
+
+
+Cordialement,
+
+L’équipe
+Démarches Simplifiées
+
+
diff --git a/spec/snapshots/api_token_expiration.haml_spec_it_renders_the_singular_expiration_message-19.html b/spec/snapshots/api_token_expiration.haml_spec_it_renders_the_singular_expiration_message-19.html
new file mode 100644
index 00000000000..d7137e947e7
--- /dev/null
+++ b/spec/snapshots/api_token_expiration.haml_spec_it_renders_the_singular_expiration_message-19.html
@@ -0,0 +1,20 @@
+
+Bonjour,
+
+
+Votre jeton d'API « ABC123 » expirera le 1er juillet 2023.
+Passée cette date, vos interconnexions utilisant ce jeton ne marcheront plus.
+
+
+Vous devrez le(s) remplacer par de nouveaux jetons que vous pouvez obtenir en utilisant la page https://example.test/profil.
+
+
+Nous restons à votre disposition si vous avez besoin d’accompagnement à l'adresse contact@demarches-simplifiees.fr.
+
+
+Cordialement,
+
+L’équipe
+Démarches Simplifiées
+
+
diff --git a/spec/snapshots/notify_procedure_expires_when_termine_forced.haml_spec_it_renders_the_notification_email-15.html b/spec/snapshots/notify_procedure_expires_when_termine_forced.haml_spec_it_renders_the_notification_email-15.html
new file mode 100644
index 00000000000..2fb7110d5dd
--- /dev/null
+++ b/spec/snapshots/notify_procedure_expires_when_termine_forced.haml_spec_it_renders_the_notification_email-15.html
@@ -0,0 +1,21 @@
+
+Bonjour,
+
+
+Le règlement général sur la protection des données (RGPD) responsabilise les organismes publics et privés qui traitent leurs données.
+
+
+Dans le cadre du respect du RGPD, nous (la plateforme Démarches Simplifiées) venons d'activer la suppression automatique des dossiers sur la démarche : "Démarche Test".
+
+
+Vous pouvez d’ores et déjà archiver ces données en accédant à
+notre systeme d'archivage pour les admnistrateurs de démarche
+.
+
+
+Cordialement,
+
+L’équipe
+Démarches Simplifiées
+
+
diff --git a/spec/snapshots/notify_service_without_siret.haml_spec_it_renders_the_reminder_email-12.html b/spec/snapshots/notify_service_without_siret.haml_spec_it_renders_the_reminder_email-12.html
new file mode 100644
index 00000000000..3bc430b4dda
--- /dev/null
+++ b/spec/snapshots/notify_service_without_siret.haml_spec_it_renders_the_reminder_email-12.html
@@ -0,0 +1,19 @@
+
+Bonjour,
+
+
+Vous êtes administrateur sur la plateforme
+Démarches Simplifiées
+et au moins un de vos services n'a pas son siret renseigné.
+
+
+Afin d'éviter tout dysfonctionnement sur la plateforme, nous vous invitons à le remplir au plus vite à cette adresse :
+http://test.host/admin/procedures
+
+
+Cordialement,
+
+L’équipe
+Démarches Simplifiées
+
+
diff --git a/spec/support/view_snapshot.rb b/spec/support/view_snapshot.rb
new file mode 100644
index 00000000000..90aac97fa14
--- /dev/null
+++ b/spec/support/view_snapshot.rb
@@ -0,0 +1,137 @@
+# frozen_string_literal: true
+
+require 'fileutils'
+require 'nokogiri'
+require 'pathname'
+
+module ViewSnapshot
+ SNAPSHOT_DIR = Rails.root.join('spec', 'snapshots')
+ SPEC_FAILURES_PATH = Rails.root.join('spec.failures')
+
+ class << self
+ def mode
+ return @mode if defined?(@mode)
+
+ @mode = if ENV['SNAPSHOT'].present?
+ :record
+ elsif ENV['CHECK_SNAPSHOT'].present?
+ :check
+ end
+ end
+
+ def active?
+ mode.present?
+ end
+
+ def handle_example(example, html)
+ return unless active?
+
+ case mode
+ when :record
+ save_snapshot(example, html)
+ when :check
+ check_snapshot(example, html)
+ end
+ end
+
+ def record_failure(path)
+ failures << path unless failures.include?(path)
+ end
+
+ def failures
+ @failures ||= []
+ end
+
+ def flush_failures
+ return unless mode == :check
+
+ if failures.any?
+ File.write(SPEC_FAILURES_PATH, failures.join("\n") + "\n")
+ elsif File.exist?(SPEC_FAILURES_PATH)
+ File.delete(SPEC_FAILURES_PATH)
+ end
+ end
+
+ private
+
+ def save_snapshot(example, html)
+ FileUtils.mkdir_p(SNAPSHOT_DIR)
+ File.write(snapshot_file(example), html)
+ end
+
+ def check_snapshot(example, html)
+ snapshot_path = snapshot_file(example)
+
+ unless File.exist?(snapshot_path)
+ record_failure(relative_path(snapshot_path))
+ raise RSpec::Expectations::ExpectationNotMetError, "Snapshot missing for #{relative_path(snapshot_path)}"
+ end
+
+ stored_html = File.read(snapshot_path)
+ unless html_structure(html) == html_structure(stored_html)
+ record_failure(relative_path(snapshot_path))
+ raise RSpec::Expectations::ExpectationNotMetError, "Snapshot mismatch for #{relative_path(snapshot_path)}"
+ end
+ end
+
+ def snapshot_file(example)
+ FileUtils.mkdir_p(SNAPSHOT_DIR)
+ SNAPSHOT_DIR.join(snapshot_filename(example))
+ end
+
+ def snapshot_filename(example)
+ spec_path = example.metadata[:file_path]
+ relative_spec = begin
+ Pathname(spec_path).relative_path_from(Rails.root.join('spec')).to_s
+ rescue StandardError
+ File.basename(spec_path)
+ end
+
+ spec_name = relative_spec.tr(File::SEPARATOR, '__').sub(/\.rb\z/, '')
+ line_number = example.metadata[:line_number] || example.metadata[:location]&.split(':')&.last
+ line_number = line_number.to_s
+ line_number = 'unknown' if line_number.blank?
+ sanitized_description = sanitize_description(example.metadata[:description])
+
+ "#{spec_name}_it_#{sanitized_description}-#{line_number}.html"
+ end
+
+ def sanitize_description(description)
+ sanitized = description.to_s.downcase
+ sanitized = sanitized.gsub(/\d+/, '')
+ sanitized = sanitized.gsub(/[^a-z0-9]+/, '_').gsub(/\A_+|_+\z/, '')
+ sanitized = 'example' if sanitized.blank?
+ sanitized
+ end
+
+ def html_structure(html)
+ fragment = Nokogiri::HTML.fragment(html.to_s)
+ fragment.children.filter_map { |node| node_structure(node) }
+ end
+
+ def node_structure(node)
+ return nil unless node.element?
+
+ [node.name, node.children.filter_map { |child| node_structure(child) }]
+ end
+
+ def relative_path(path)
+ Pathname(path).relative_path_from(Rails.root).to_s
+ end
+ end
+end
+
+if ViewSnapshot.active?
+ RSpec.configure do |config|
+ config.after(:each, type: :view) do |example|
+ next unless defined?(rendered)
+ next if rendered.blank?
+
+ ViewSnapshot.handle_example(example, rendered)
+ end
+
+ config.after(:suite) do
+ ViewSnapshot.flush_failures
+ end
+ end
+end
diff --git a/spec/views/administrate/application/_pagination.html.haml_spec.rb b/spec/views/administrate/application/_pagination.html.haml_spec.rb
new file mode 100644
index 00000000000..93045902c03
--- /dev/null
+++ b/spec/views/administrate/application/_pagination.html.haml_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrate/application/pagination', type: :view do
+ let(:previous_link) { 'Précédent'.html_safe }
+ let(:next_link) { 'Suivant'.html_safe }
+
+ before do
+ allow(view).to receive(:paginate).and_return(''.html_safe)
+ allow(view).to receive(:link_to_prev_page).and_return(previous_link)
+ allow(view).to receive(:link_to_next_page).and_return(next_link)
+ end
+
+ def paginated_array
+ array = Kaminari.paginate_array((1..10).to_a).page(2).per(2)
+ array.define_singleton_method(:loaded?) { true }
+ array
+ end
+
+ it 'renders paginate for standard resources' do
+ render partial: 'administrate/application/pagination', locals: { resources: paginated_array }
+
+ expect(rendered).to include('pagination')
+ end
+
+ it 'renders navigation when resources are without count' do
+ resources = paginated_array
+ resources.singleton_class.include(Kaminari::PaginatableWithoutCount)
+
+ render partial: 'administrate/application/pagination', locals: { resources: resources }
+
+ expect(rendered).to include('pagination')
+ end
+end
diff --git a/spec/views/administrateur_mailer/activate_before_expiration.haml_spec.rb b/spec/views/administrateur_mailer/activate_before_expiration.haml_spec.rb
new file mode 100644
index 00000000000..f98da22aa07
--- /dev/null
+++ b/spec/views/administrateur_mailer/activate_before_expiration.haml_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrateur_mailer/activate_before_expiration', type: :view do
+ let(:token) { 'reset-token' }
+ let(:expiration_date) { Time.zone.local(2024, 7, 10) }
+
+ before do
+ assign(:subject, 'Activation requise')
+ assign(:reset_password_token, token)
+ assign(:expiration_date, expiration_date)
+ end
+
+ it 'renders the activation notice' do
+ render template: 'administrateur_mailer/activate_before_expiration'
+
+ expect(rendered).to include(users_activate_url(token: token))
+ end
+end
diff --git a/spec/views/administrateur_mailer/api_token_expiration.haml_spec.rb b/spec/views/administrateur_mailer/api_token_expiration.haml_spec.rb
new file mode 100644
index 00000000000..c66bc300889
--- /dev/null
+++ b/spec/views/administrateur_mailer/api_token_expiration.haml_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrateur_mailer/api_token_expiration', type: :view do
+ let(:profil_link) { 'https://example.test/profil' }
+
+ before do
+ assign(:subject, 'Expiration des jetons API')
+ allow(view).to receive(:profil_url).and_return(profil_link)
+ Current.application_name = 'Démarches Simplifiées'
+ end
+
+ after { Current.reset_all }
+
+ context 'with a single token' do
+ before { assign(:tokens, [OpenStruct.new(prefix: 'ABC123')]) }
+
+ it 'renders the singular expiration message' do
+ render template: 'administrateur_mailer/api_token_expiration'
+
+ expect(rendered).to include('ABC123')
+ end
+ end
+
+ context 'with multiple tokens' do
+ before { assign(:tokens, [OpenStruct.new(prefix: 'ABC123'), OpenStruct.new(prefix: 'XYZ789')]) }
+
+ it 'renders the plural expiration message' do
+ render template: 'administrateur_mailer/api_token_expiration'
+
+ expect(rendered).to include('ABC123')
+ expect(rendered).to include('XYZ789')
+ end
+ end
+end
diff --git a/spec/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.haml_spec.rb b/spec/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.haml_spec.rb
new file mode 100644
index 00000000000..c5933f5917b
--- /dev/null
+++ b/spec/views/administrateur_mailer/notify_procedure_expires_when_termine_forced.haml_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrateur_mailer/notify_procedure_expires_when_termine_forced', type: :view do
+ let(:procedure) { create(:procedure, libelle: 'Démarche Test') }
+
+ before do
+ assign(:procedure, procedure)
+ Current.application_name = 'Démarches Simplifiées'
+ end
+
+ after { Current.reset_all }
+
+ it 'renders the notification email' do
+ render template: 'administrateur_mailer/notify_procedure_expires_when_termine_forced'
+
+ expect(rendered).to include(procedure.libelle)
+ expect(rendered).to include(admin_procedures_archived_url(procedure))
+ end
+end
diff --git a/spec/views/administrateur_mailer/notify_service_without_siret.haml_spec.rb b/spec/views/administrateur_mailer/notify_service_without_siret.haml_spec.rb
new file mode 100644
index 00000000000..05c6ccd81e1
--- /dev/null
+++ b/spec/views/administrateur_mailer/notify_service_without_siret.haml_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrateur_mailer/notify_service_without_siret', type: :view do
+ before do
+ Current.application_name = 'Démarches Simplifiées'
+ end
+
+ after { Current.reset_all }
+
+ it 'renders the reminder email' do
+ render template: 'administrateur_mailer/notify_service_without_siret'
+
+ expect(rendered).to include(Current.application_name)
+ expect(rendered).to include(admin_procedures_url)
+ end
+end
diff --git a/spec/views/administrateurs/_breadcrumbs.html.haml_spec.rb b/spec/views/administrateurs/_breadcrumbs.html.haml_spec.rb
new file mode 100644
index 00000000000..a53e6537086
--- /dev/null
+++ b/spec/views/administrateurs/_breadcrumbs.html.haml_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrateurs/breadcrumbs', type: :view do
+ let(:procedure) do
+ instance_double(Procedure,
+ libelle: 'Ma démarche',
+ close?: false,
+ locked?: true,
+ path: 'ma-demarche',
+ id: 42,
+ published_at: Time.zone.local(2024, 1, 15),
+ closed_at: nil,
+ created_at: Time.zone.local(2023, 5, 10),
+ api_entreprise_token: double('ApiEntrepriseToken', expired_or_expires_soon?: false))
+ end
+ let(:steps) { [['Accueil', '/'], ['Démarches', '/procedures'], ['Paramètres', '#']] }
+
+ before do
+ allow(procedure).to receive(:to_param).and_return(procedure.id.to_s)
+ assign(:procedure, procedure)
+ end
+
+ it 'renders the breadcrumb trail with metadatas' do
+ render partial: 'administrateurs/breadcrumbs', locals: { steps: steps, metadatas: true }
+
+ expect(rendered).to include('breadcrumbs')
+ expect(rendered).to include(procedure.libelle)
+ end
+end
diff --git a/spec/views/administrateurs/_groups_header.haml_spec.rb b/spec/views/administrateurs/_groups_header.haml_spec.rb
new file mode 100644
index 00000000000..c2d42083c21
--- /dev/null
+++ b/spec/views/administrateurs/_groups_header.haml_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrateurs/groups_header', type: :view do
+ let(:procedure) { create(:procedure) }
+ let(:groupe_instructeur) { create(:groupe_instructeur, procedure: procedure, label: 'Groupe Bordeaux') }
+
+ before do
+ assign(:procedure, procedure)
+ assign(:groupe_instructeur, groupe_instructeur)
+ end
+
+ it 'renders the group header form' do
+ render partial: 'administrateurs/groups_header'
+
+ expect(rendered).to include('Groupe «')
+ expect(rendered).to include(groupe_instructeur.label)
+ end
+end
diff --git a/spec/views/administrateurs/_login_banner.html.haml_spec.rb b/spec/views/administrateurs/_login_banner.html.haml_spec.rb
new file mode 100644
index 00000000000..202acf1aa2d
--- /dev/null
+++ b/spec/views/administrateurs/_login_banner.html.haml_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrateurs/login_banner', type: :view do
+ it 'renders the sign out link' do
+ render partial: 'administrateurs/login_banner'
+
+ expect(rendered).to include('/administrateurs/sign_out')
+ end
+end
diff --git a/spec/views/administrateurs/_main_navigation.html.haml_spec.rb b/spec/views/administrateurs/_main_navigation.html.haml_spec.rb
new file mode 100644
index 00000000000..f46ee36a1c8
--- /dev/null
+++ b/spec/views/administrateurs/_main_navigation.html.haml_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'administrateurs/main_navigation', type: :view do
+ before do
+ allow(Rails.application.config).to receive(:ds_zonage_enabled).and_return(true)
+ current_admin = double(groupe_gestionnaire_id: 1, api_tokens: double(exists?: false))
+ allow(view).to receive(:current_administrateur).and_return(current_admin)
+ allow(view).to receive(:current_page?).and_return(false)
+ allow(view).to receive(:instructeur_signed_in?).and_return(false)
+ allow(view).to receive(:administrateur_signed_in?).and_return(true)
+ allow(view).to receive(:expert_signed_in?).and_return(false)
+ end
+
+ it 'renders the navigation menu' do
+ render partial: 'administrateurs/main_navigation'
+
+ expect(rendered).to include('Mes démarches')
+ expect(rendered).to include('Toutes les démarches')
+ expect(rendered).to include('Mon groupe gestionnaire')
+ end
+end