diff --git a/app/views/administrateurs/procedures/_unpublished_changes_navbar.html.haml b/app/views/administrateurs/procedures/_unpublished_changes_navbar.html.haml
new file mode 100644
index 000000000..97158037e
--- /dev/null
+++ b/app/views/administrateurs/procedures/_unpublished_changes_navbar.html.haml
@@ -0,0 +1,9 @@
+.sticky-header.sticky-header-warning
+ .fr-container
+ %p.flex.justify-between.align-center.fr-text-default--warning
+ %span
+ = dsfr_icon("fr-icon-warning-fill fr-mr-1v")
+ = t('.intro_html').html_safe
+ %span.no-wrap
+ = link_to t('.see_changes'), admin_procedure_path(procedure), class: 'fr-btn fr-btn--secondary fr-mr-2w'
+ = link_to t('.publish_changes'), admin_procedure_publish_revision_path(procedure), class: 'fr-btn', method: :post, data: { disable_with: "Publication...", confirm: 'Êtes-vous sûr de vouloir publier les modifications ?' }
diff --git a/app/views/administrateurs/procedures/champs.html.haml b/app/views/administrateurs/procedures/champs.html.haml
index 5f0c1fa5c..fb85b6aee 100644
--- a/app/views/administrateurs/procedures/champs.html.haml
+++ b/app/views/administrateurs/procedures/champs.html.haml
@@ -1,3 +1,7 @@
+
+- if @procedure.draft_changed?
+ - content_for(:sticky_header) do
+ = render partial: 'administrateurs/procedures/unpublished_changes_navbar', locals: { procedure: @procedure }
= render partial: 'administrateurs/breadcrumbs',
locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)],
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
diff --git a/app/views/administrateurs/types_de_champ/_insert.turbo_stream.haml b/app/views/administrateurs/types_de_champ/_insert.turbo_stream.haml
index d781b8cfc..ccf49114e 100644
--- a/app/views/administrateurs/types_de_champ/_insert.turbo_stream.haml
+++ b/app/views/administrateurs/types_de_champ/_insert.turbo_stream.haml
@@ -49,3 +49,10 @@
= turbo_stream.hide dom_id(@created.coordinate.parent, :type_de_champ_add_button)
- elsif @destroyed&.child? && @destroyed.parent.empty?
= turbo_stream.show dom_id(@destroyed.parent, :type_de_champ_add_button)
+
+- if @procedure.draft_changed?
+ = turbo_stream.update "sticky-header" do
+ = render partial: "administrateurs/procedures/unpublished_changes_navbar", locals: { procedure: @procedure }
+
+- else
+ = turbo_stream.update "sticky-header", ""
diff --git a/config/locales/views/administrateurs/procedures/en.yml b/config/locales/views/administrateurs/procedures/en.yml
index bcbf8daac..24fb5ebe0 100644
--- a/config/locales/views/administrateurs/procedures/en.yml
+++ b/config/locales/views/administrateurs/procedures/en.yml
@@ -71,3 +71,7 @@ en:
path_not_available:
owner: This URL is identical to another of your published procedures. If you publish this procedure, the old one will be unpublished and will no longer be accessible to the public.
not_owner: This URL is identical to another procedure, you must modify it.
+ unpublished_changes_navbar:
+ intro_html: Changes made will only be visible after the next publication
+ see_changes: View changes
+ publish_changes: Publish changes
diff --git a/config/locales/views/administrateurs/procedures/fr.yml b/config/locales/views/administrateurs/procedures/fr.yml
index 90fb3f4f7..18c934906 100644
--- a/config/locales/views/administrateurs/procedures/fr.yml
+++ b/config/locales/views/administrateurs/procedures/fr.yml
@@ -71,3 +71,7 @@ fr:
path_not_available:
owner: Cette url est identique à celle d’une autre de vos démarches publiées. Si vous publiez cette démarche, l’ancienne sera dépubliée et ne sera plus accessible au public.
not_owner: Cette url est identique à celle d’une autre démarche, vous devez la modifier afin de pouvoir publier votre démarche.
+ unpublished_changes_navbar:
+ intro_html: Les modifications effectuées ne seront visibles qu'à la prochaine publication
+ see_changes: Voir les modifications
+ publish_changes: Publier les modifications
diff --git a/spec/system/administrateurs/types_de_champ_spec.rb b/spec/system/administrateurs/types_de_champ_spec.rb
index 9f06e0356..b25e64087 100644
--- a/spec/system/administrateurs/types_de_champ_spec.rb
+++ b/spec/system/administrateurs/types_de_champ_spec.rb
@@ -351,4 +351,61 @@ describe 'As an administrateur I can edit types de champ', js: true do
end
end
end
+
+ context "unpublished changes navbar" do
+ let(:procedure) { create(:procedure, :published) }
+
+ before do
+ login_as administrateur.user, scope: :user
+ visit champs_admin_procedure_path(procedure)
+ end
+
+ scenario "navbar behavior for published and unpublished procedures" do
+ expect(page).not_to have_selector('.sticky-header.sticky-header-warning')
+
+ # Ajouter le premier champ
+ find('.fr-btn.fr-btn--secondary.fr-btn--icon-left.fr-icon-add-line', match: :first).click
+ fill_in 'Libellé du champ', with: 'Premier champ'
+ expect(page).to have_selector('.sticky-header.sticky-header-warning')
+ expect(page).to have_content("Les modifications effectuées ne seront visibles qu'à la prochaine publication")
+
+ expect(page).to have_field('Libellé du champ', with: 'Premier champ')
+
+ # Ajouter le deuxième champ
+ find('.fr-btn.fr-btn--secondary.fr-btn--icon-left.fr-icon-add-line', match: :first).click
+
+ expect(page).to have_selector('.type-de-champ', count: 2, wait: 5)
+
+ within all('.type-de-champ').last do
+ fill_in 'Libellé du champ', with: 'Deuxième champ'
+ end
+
+ expect(page).to have_field('Libellé du champ', with: 'Premier champ')
+ expect(page).to have_field('Libellé du champ', with: 'Deuxième champ')
+
+ expect(page).to have_selector('.sticky-header.sticky-header-warning')
+ expect(page).to have_content("Les modifications effectuées ne seront visibles qu'à la prochaine publication")
+
+ # Supprimer les champs
+
+ 2.times do
+ initial_count = page.all('.type-de-champ').count
+
+ first('.fr-btn--tertiary-no-outline[title="Supprimer le champ"]').click
+
+ page.driver.browser.switch_to.alert.accept rescue nil
+
+ expect(page).to have_selector('.type-de-champ', count: initial_count - 1, wait: 5)
+ end
+
+ expect(page).not_to have_selector('.sticky-header.sticky-header-warning')
+
+ unpublished_procedure = create(:procedure)
+ visit champs_admin_procedure_path(unpublished_procedure)
+
+ find('.fr-btn.fr-btn--secondary.fr-btn--icon-left.fr-icon-add-line', match: :first).click
+ fill_in 'Libellé du champ', with: 'Nouveau champ'
+ expect(page).not_to have_selector('.sticky-header.sticky-header-warning')
+ end
+ end
end