From d2ab8b559330010ff816283a2b723e8f9958e9e6 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Mon, 25 Apr 2022 12:41:01 +0200 Subject: [PATCH] feat(message): replace message partial with MessageComponent --- app/components/dossiers/message_component.rb | 58 +++++++++++++++ .../message_component.en.yml | 9 +++ .../message_component.fr.yml | 9 +++ .../message_component.html.haml} | 14 ++-- app/helpers/commentaire_helper.rb | 16 ---- .../commentaires/destroy.turbo_stream.haml | 3 +- .../instructeurs/dossiers/print.html.haml | 2 +- .../shared/dossiers/_messagerie.html.haml | 2 +- .../dossiers/messages/_message_icon.html.haml | 7 -- .../messages/_message_issuer.html.haml | 6 -- .../dossiers/show/_latest_message.html.haml | 2 +- config/locales/en.yml | 3 - config/locales/fr.yml | 3 - config/locales/views/instructeurs/en.yml | 2 - config/locales/views/instructeurs/fr.yml | 2 - config/locales/views/shared/dossiers/en.yml | 9 --- config/locales/views/shared/dossiers/fr.yml | 9 --- config/locales/views/shared/en.yml | 3 - config/locales/views/shared/fr.yml | 3 - .../dossiers/message_component_spec.rb} | 73 ++++++++++++++++--- .../dossiers/message_component_preview.rb | 31 ++++++++ spec/helpers/commentaire_helper_spec.rb | 47 ------------ 22 files changed, 182 insertions(+), 131 deletions(-) create mode 100644 app/components/dossiers/message_component.rb create mode 100644 app/components/dossiers/message_component/message_component.en.yml create mode 100644 app/components/dossiers/message_component/message_component.fr.yml rename app/{views/shared/dossiers/messages/_message.html.haml => components/dossiers/message_component/message_component.html.haml} (60%) delete mode 100644 app/views/shared/dossiers/messages/_message_icon.html.haml delete mode 100644 app/views/shared/dossiers/messages/_message_issuer.html.haml delete mode 100644 config/locales/views/shared/dossiers/en.yml delete mode 100644 config/locales/views/shared/dossiers/fr.yml rename spec/{views/shared/dossiers/messages/message.html.haml_spec.rb => components/dossiers/message_component_spec.rb} (59%) create mode 100644 spec/components/previews/dossiers/message_component_preview.rb diff --git a/app/components/dossiers/message_component.rb b/app/components/dossiers/message_component.rb new file mode 100644 index 000000000..8e2a185a1 --- /dev/null +++ b/app/components/dossiers/message_component.rb @@ -0,0 +1,58 @@ +class Dossiers::MessageComponent < ApplicationComponent + def initialize(commentaire:, connected_user:, messagerie_seen_at: nil, show_reply_button: false) + @commentaire = commentaire + @connected_user = connected_user + @messagerie_seen_at = messagerie_seen_at + @show_reply_button = show_reply_button + end + + attr_reader :commentaire, :connected_user, :messagerie_seen_at + + private + + def show_reply_button? + @show_reply_button + end + + def highlight_if_unseen_class + helpers.highlight_if_unseen_class(@messagerie_seen_at, commentaire.created_at) + end + + def icon_path + if commentaire.sent_by_system? + 'icons/mail.svg' + elsif commentaire.sent_by?(connected_user) + 'icons/account-circle.svg' + else + 'icons/blue-person.svg' + end + end + + def commentaire_issuer + if commentaire.sent_by_system? + t('.automatic_email') + elsif commentaire.sent_by?(connected_user) + t('.you') + else + commentaire.redacted_email + end + end + + def commentaire_from_guest? + commentaire.dossier.invites.map(&:email).include?(commentaire.email) + end + + def commentaire_date + is_current_year = (commentaire.created_at.year == Time.zone.today.year) + l(commentaire.created_at, format: is_current_year ? :message_date : :message_date_with_year) + end + + def commentaire_body + if commentaire.discarded? + t('.deleted_body') + else + body_formatted = commentaire.sent_by_system? ? commentaire.body : simple_format(commentaire.body) + sanitize(body_formatted) + end + end +end diff --git a/app/components/dossiers/message_component/message_component.en.yml b/app/components/dossiers/message_component/message_component.en.yml new file mode 100644 index 000000000..a24af5c49 --- /dev/null +++ b/app/components/dossiers/message_component/message_component.en.yml @@ -0,0 +1,9 @@ +--- +en: + reply: Reply + guest: Guest + delete_button: Delete this message + confirm: Are you sure you want to delete this message ? + automatic_email: Automatic email + you: You + deleted_body: Message deleted diff --git a/app/components/dossiers/message_component/message_component.fr.yml b/app/components/dossiers/message_component/message_component.fr.yml new file mode 100644 index 000000000..4386b2ea2 --- /dev/null +++ b/app/components/dossiers/message_component/message_component.fr.yml @@ -0,0 +1,9 @@ +--- +fr: + reply: Répondre + guest: Invité + delete_button: Supprimer le message + confirm: Êtes-vous sûr de vouloir supprimer ce message ? + automatic_email: Email automatique + you: Vous + deleted_body: Message supprimé diff --git a/app/views/shared/dossiers/messages/_message.html.haml b/app/components/dossiers/message_component/message_component.html.haml similarity index 60% rename from app/views/shared/dossiers/messages/_message.html.haml rename to app/components/dossiers/message_component/message_component.html.haml index 646692125..c19f78791 100644 --- a/app/views/shared/dossiers/messages/_message.html.haml +++ b/app/components/dossiers/message_component/message_component.html.haml @@ -1,14 +1,14 @@ -= render partial: 'shared/dossiers/messages/message_icon', locals: { commentaire: commentaire, connected_user: connected_user } += image_tag(icon_path, class: 'person-icon', alt: '') .width-100 %h2 %span.mail - = render partial: 'shared/dossiers/messages/message_issuer', locals: { commentaire: commentaire, connected_user: connected_user } - - if commentaire_is_from_guest(commentaire) + = commentaire_issuer + - if commentaire_from_guest? %span.guest= t('.guest') - %span.date{ class: highlight_if_unseen_class(messagerie_seen_at, commentaire.created_at) } - = commentaire_date(commentaire) - .rich-text= pretty_commentaire(commentaire) + %span.date{ class: highlight_if_unseen_class } + = commentaire_date + .rich-text= commentaire_body .message-extras.flex.justify-start - if commentaire.soft_deletable?(connected_user) @@ -20,7 +20,7 @@ .attachment-link = render partial: "shared/attachment/show", locals: { attachment: commentaire.piece_jointe.attachment } - - if show_reply_button + - if show_reply_button? = button_tag type: 'button', class: 'button small message-answer-button', onclick: 'document.querySelector("#commentaire_body").focus()' do %span.icon.reply = t('.reply') diff --git a/app/helpers/commentaire_helper.rb b/app/helpers/commentaire_helper.rb index 2518c8506..8ba5bfab8 100644 --- a/app/helpers/commentaire_helper.rb +++ b/app/helpers/commentaire_helper.rb @@ -12,20 +12,4 @@ module CommentaireHelper I18n.t('helpers.commentaire.reply_in_mailbox') end end - - def commentaire_is_from_guest(commentaire) - commentaire.dossier.invites.map(&:email).include?(commentaire.email) - end - - def commentaire_date(commentaire) - is_current_year = (commentaire.created_at.year == Time.zone.today.year) - template = is_current_year ? :message_date : :message_date_with_year - I18n.l(commentaire.created_at, format: template) - end - - def pretty_commentaire(commentaire) - return t('views.shared.commentaires.destroy.deleted_body') if commentaire.discarded? - body_formatted = commentaire.sent_by_system? ? commentaire.body : simple_format(commentaire.body) - sanitize(body_formatted) - end end diff --git a/app/views/instructeurs/commentaires/destroy.turbo_stream.haml b/app/views/instructeurs/commentaires/destroy.turbo_stream.haml index fb9a0f1a9..d84c39d0d 100644 --- a/app/views/instructeurs/commentaires/destroy.turbo_stream.haml +++ b/app/views/instructeurs/commentaires/destroy.turbo_stream.haml @@ -1,2 +1,3 @@ - if @commentaire.discarded? - = turbo_stream.update @commentaire, partial: "shared/dossiers/messages/message", locals: { commentaire: @commentaire, connected_user: @commentaire.instructeur || @commentaire.expert, messagerie_seen_at: nil, show_reply_button: false } + = turbo_stream.update @commentaire do + = render Dossiers::MessageComponent.new(commentaire: @commentaire, connected_user: @commentaire.instructeur || @commentaire.expert) diff --git a/app/views/instructeurs/dossiers/print.html.haml b/app/views/instructeurs/dossiers/print.html.haml index 656085d58..12c2fa5d0 100644 --- a/app/views/instructeurs/dossiers/print.html.haml +++ b/app/views/instructeurs/dossiers/print.html.haml @@ -49,7 +49,7 @@ %ul.messages-list - @dossier.commentaires.with_attached_piece_jointe.each do |commentaire| %li - = render partial: "shared/dossiers/messages/message", locals: { commentaire: commentaire, connected_user: current_instructeur, messagerie_seen_at: nil, show_reply_button: false } + = render Dossiers::MessageComponent.new(commentaire: commentaire, connected_user: current_instructeur) %script{ type: "text/javascript" } window.print(); diff --git a/app/views/shared/dossiers/_messagerie.html.haml b/app/views/shared/dossiers/_messagerie.html.haml index 7e3a33f18..e72046db4 100644 --- a/app/views/shared/dossiers/_messagerie.html.haml +++ b/app/views/shared/dossiers/_messagerie.html.haml @@ -2,7 +2,7 @@ %ul.messages-list - dossier.commentaires.with_attached_piece_jointe.each do |commentaire| %li.message{ class: commentaire_is_from_me_class(commentaire, connected_user), id: dom_id(commentaire) } - = render partial: "shared/dossiers/messages/message", locals: { commentaire: commentaire, connected_user: connected_user, messagerie_seen_at: messagerie_seen_at, show_reply_button: show_reply_button(commentaire, connected_user) } + = render Dossiers::MessageComponent.new(commentaire: commentaire, connected_user: connected_user, messagerie_seen_at: messagerie_seen_at, show_reply_button: show_reply_button(commentaire, connected_user)) - if dossier.messagerie_available? = render partial: "shared/dossiers/messages/form", locals: { commentaire: new_commentaire, form_url: form_url, dossier: dossier } diff --git a/app/views/shared/dossiers/messages/_message_icon.html.haml b/app/views/shared/dossiers/messages/_message_icon.html.haml deleted file mode 100644 index 849337641..000000000 --- a/app/views/shared/dossiers/messages/_message_icon.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -- if commentaire.sent_by_system? - = image_tag('icons/mail.svg', class: 'person-icon', alt: '') -- elsif commentaire.sent_by?(connected_user) - = image_tag('icons/account-circle.svg', class: 'person-icon', alt: '') -- else - = image_tag('icons/blue-person.svg', class: 'person-icon', alt: '') - diff --git a/app/views/shared/dossiers/messages/_message_issuer.html.haml b/app/views/shared/dossiers/messages/_message_issuer.html.haml deleted file mode 100644 index 87a12da64..000000000 --- a/app/views/shared/dossiers/messages/_message_issuer.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -- if commentaire.sent_by_system? - = t('views.shared.dossiers.messages.message_issuer.automatic_email') -- elsif commentaire.sent_by?(connected_user) - = t('views.shared.dossiers.messages.message_issuer.you') -- else - = commentaire.redacted_email diff --git a/app/views/users/dossiers/show/_latest_message.html.haml b/app/views/users/dossiers/show/_latest_message.html.haml index 73ec2e106..6fc81ff8e 100644 --- a/app/views/users/dossiers/show/_latest_message.html.haml +++ b/app/views/users/dossiers/show/_latest_message.html.haml @@ -4,7 +4,7 @@ %h3.tab-title= t('views.users.dossiers.show.latest_message.latest_message') .message.inverted-background - = render partial: "shared/dossiers/messages/message", locals: { commentaire: latest_message, connected_user: current_user, messagerie_seen_at: nil, show_reply_button: false } + = render Dossiers::MessageComponent.new(commentaire: latest_message, connected_user: current_user) = link_to messagerie_dossier_url(dossier, anchor: 'new_commentaire'), class: 'button send' do %span.icon.reply diff --git a/config/locales/en.yml b/config/locales/en.yml index e122e7020..bf6db58e3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -127,9 +127,6 @@ en: submit_dossier: Submit the file save_changes: Save the changes of the file messages: - message_issuer: - automatic_email: "Automatic email" - you: "You" form: send_message: "Send message" attachment_size: "(attachment size max : 20 Mo)" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 2fcff2cae..177b44dd4 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -122,9 +122,6 @@ fr: submit_dossier: Déposer le dossier save_changes: Enregistrer les modifications du dossier messages: - message_issuer: - automatic_email: "Email automatique" - you: "Vous" form: send_message: "Envoyer le message" attachment_size: "(taille max : 20 Mo)" diff --git a/config/locales/views/instructeurs/en.yml b/config/locales/views/instructeurs/en.yml index ebd1f3cea..49ea80d96 100644 --- a/config/locales/views/instructeurs/en.yml +++ b/config/locales/views/instructeurs/en.yml @@ -1,7 +1,5 @@ en: instructeurs: - commentaires_controller: - alert_already_discarded: "Can not destroy message: it was already destroyed" procedure: archive_pending_html: Archive creation pending
(requested %{created_period} ago) archive_ready_html: Download archive
(requested %{generated_period} ago) diff --git a/config/locales/views/instructeurs/fr.yml b/config/locales/views/instructeurs/fr.yml index 2b5c8c035..153dbc679 100644 --- a/config/locales/views/instructeurs/fr.yml +++ b/config/locales/views/instructeurs/fr.yml @@ -1,7 +1,5 @@ fr: instructeurs: - commentaires_controller: - alert_already_discarded: Ce message a déjà été supprimé procedure: archive_pending_html: Archive en cours de création
(demandée il y a %{created_period}) archive_ready_html: Télécharger l’archive
(demandée il y a %{generated_period}) diff --git a/config/locales/views/shared/dossiers/en.yml b/config/locales/views/shared/dossiers/en.yml deleted file mode 100644 index 50fe2ce18..000000000 --- a/config/locales/views/shared/dossiers/en.yml +++ /dev/null @@ -1,9 +0,0 @@ -en: - shared: - dossiers: - messages: - message: - reply: Reply - guest: Guest - delete_button: Delete this message - confirm: Are you sure you want to delete this message ? diff --git a/config/locales/views/shared/dossiers/fr.yml b/config/locales/views/shared/dossiers/fr.yml deleted file mode 100644 index fe70e4cf7..000000000 --- a/config/locales/views/shared/dossiers/fr.yml +++ /dev/null @@ -1,9 +0,0 @@ -fr: - shared: - dossiers: - messages: - message: - reply: Répondre - guest: Invité - delete_button: Supprimer le message - confirm: Êtes-vous sûr de vouloir supprimer ce message ? diff --git a/config/locales/views/shared/en.yml b/config/locales/views/shared/en.yml index bb67c5377..f1bb0982c 100644 --- a/config/locales/views/shared/en.yml +++ b/config/locales/views/shared/en.yml @@ -20,6 +20,3 @@ en: already_user: "I already have an account" create: 'Create an account' signin: 'Sign in' - commentaires: - destroy: - deleted_body: Message deleted diff --git a/config/locales/views/shared/fr.yml b/config/locales/views/shared/fr.yml index 42f484605..4053b3cd3 100644 --- a/config/locales/views/shared/fr.yml +++ b/config/locales/views/shared/fr.yml @@ -20,6 +20,3 @@ fr: already_user: 'J’ai déjà un compte' create: 'Créer un compte' signin: 'Connexion' - commentaires: - destroy: - deleted_body: Message supprimé diff --git a/spec/views/shared/dossiers/messages/message.html.haml_spec.rb b/spec/components/dossiers/message_component_spec.rb similarity index 59% rename from spec/views/shared/dossiers/messages/message.html.haml_spec.rb rename to spec/components/dossiers/message_component_spec.rb index 00744a27a..9fb4b9d99 100644 --- a/spec/views/shared/dossiers/messages/message.html.haml_spec.rb +++ b/spec/components/dossiers/message_component_spec.rb @@ -1,21 +1,28 @@ -describe 'shared/dossiers/messages/message.html.haml', type: :view do - before { view.extend DossierHelper } - - subject { render 'shared/dossiers/messages/message.html.haml', commentaire: commentaire, messagerie_seen_at: seen_at, connected_user: dossier.user, show_reply_button: true } - +RSpec.describe Dossiers::MessageComponent, type: :component do + let(:component) do + described_class.new( + commentaire: commentaire, + connected_user: connected_user, + messagerie_seen_at: seen_at, + show_reply_button: true + ) + end let(:dossier) { create(:dossier, :en_construction) } let(:commentaire) { create(:commentaire, dossier: dossier) } + let(:connected_user) { dossier.user } let(:seen_at) { commentaire.created_at + 1.hour } + subject { render_inline(component).to_html } + it { is_expected.to have_button("Répondre") } - context "with a seen_at after commentaire created_at" do + context 'with a seen_at after commentaire created_at' do let(:seen_at) { commentaire.created_at + 1.hour } it { is_expected.not_to have_css(".highlighted") } end - context "with a seen_at after commentaire created_at" do + context 'with a seen_at after commentaire created_at' do let(:seen_at) { commentaire.created_at - 1.hour } it { is_expected.to have_css(".highlighted") } @@ -51,8 +58,8 @@ describe 'shared/dossiers/messages/message.html.haml', type: :view do let(:instructeur) { create(:instructeur) } let(:procedure) { create(:procedure) } let(:dossier) { create(:dossier, :en_construction, commentaires: [commentaire], procedure: procedure) } - subject { render 'shared/dossiers/messages/message.html.haml', commentaire: commentaire, messagerie_seen_at: seen_at, connected_user: instructeur, show_reply_button: true } - let(:form_url) { instructeur_commentaire_path(commentaire.dossier.procedure, commentaire.dossier, commentaire) } + let(:connected_user) { instructeur } + let(:form_url) { component.helpers.instructeur_commentaire_path(commentaire.dossier.procedure, commentaire.dossier, commentaire) } context 'on a procedure where commentaire had been written by connected instructeur' do let(:commentaire) { create(:commentaire, instructeur: instructeur, body: 'Second message') } @@ -64,7 +71,7 @@ describe 'shared/dossiers/messages/message.html.haml', type: :view do let(:commentaire) { create(:commentaire, instructeur: instructeur, body: 'Second message', discarded_at: 2.days.ago) } it { is_expected.not_to have_selector("form[action=\"#{form_url}\"]") } - it { is_expected.not_to have_selector(".rich-text", text: I18n.t(t('views.shared.commentaires.destroy.deleted_body'))) } + it { is_expected.to have_selector(".rich-text", text: component.t('.deleted_body')) } end context 'on a procedure where commentaire had been written by connected an user' do @@ -86,4 +93,50 @@ describe 'shared/dossiers/messages/message.html.haml', type: :view do end end end + + describe '#commentaire_from_guest?' do + let!(:guest) { create(:invite, dossier: dossier) } + + subject { component.send(:commentaire_from_guest?) } + + context 'when the commentaire sender is not a guest' do + let(:commentaire) { create(:commentaire, dossier: dossier, email: "michel@pref.fr") } + it { is_expected.to be false } + end + + context 'when the commentaire sender is a guest on this dossier' do + let(:commentaire) { create(:commentaire, dossier: dossier, email: guest.email) } + it { is_expected.to be true } + end + end + + describe '#commentaire_date' do + let(:present_date) { Time.zone.local(2018, 9, 2, 10, 5, 0) } + let(:creation_date) { present_date } + let(:commentaire) do + Timecop.freeze(creation_date) { create(:commentaire, email: "michel@pref.fr") } + end + + subject do + Timecop.freeze(present_date) { component.send(:commentaire_date) } + end + + it 'doesn’t include the creation year' do + expect(subject).to eq 'le 2 septembre à 10 h 05' + end + + context 'when displaying a commentaire created on a previous year' do + let(:creation_date) { present_date.prev_year } + it 'includes the creation year' do + expect(subject).to eq 'le 2 septembre 2017 à 10 h 05' + end + end + + context 'when formatting the first day of the month' do + let(:present_date) { Time.zone.local(2018, 9, 1, 10, 5, 0) } + it 'includes the ordinal' do + expect(subject).to eq 'le 1er septembre à 10 h 05' + end + end + end end diff --git a/spec/components/previews/dossiers/message_component_preview.rb b/spec/components/previews/dossiers/message_component_preview.rb new file mode 100644 index 000000000..e85ac03d1 --- /dev/null +++ b/spec/components/previews/dossiers/message_component_preview.rb @@ -0,0 +1,31 @@ +class Dossiers::MessageComponentPreview < ViewComponent::Preview + def with_default_commentaire + render Dossiers::MessageComponent.new(commentaire: commentaire, connected_user: user) + end + + def with_discarded_commentaire + render Dossiers::MessageComponent.new(commentaire: discarded_commentaire, connected_user: user) + end + + private + + def user + User.new email: "usager@example.com", locale: I18n.locale + end + + def commentaire + Commentaire.new body: 'Hello world!', email: user.email, dossier: dossier, created_at: 2.days.ago + end + + def discarded_commentaire + Commentaire.new body: 'Hello world!', email: user.email, dossier: dossier, created_at: 2.days.ago, discarded_at: 1.day.ago + end + + def dossier + Dossier.new(id: 47882, state: :en_instruction, procedure: procedure, user: user) + end + + def procedure + Procedure.new id: 1234, libelle: 'Dotation d’Équipement des Territoires Ruraux - Exercice 2019' + end +end diff --git a/spec/helpers/commentaire_helper_spec.rb b/spec/helpers/commentaire_helper_spec.rb index e54b1a860..13a0710a6 100644 --- a/spec/helpers/commentaire_helper_spec.rb +++ b/spec/helpers/commentaire_helper_spec.rb @@ -28,51 +28,4 @@ RSpec.describe CommentaireHelper, type: :helper do it { is_expected.to include('Répondre') } end end - - describe '.commentaire_is_from_guest' do - let(:dossier) { create(:dossier, :en_instruction) } - let!(:guest) { create(:invite, dossier: dossier) } - - subject { commentaire_is_from_guest(commentaire) } - - context 'when the commentaire sender is not a guest' do - let(:commentaire) { create(:commentaire, dossier: dossier, email: "michel@pref.fr") } - it { is_expected.to be false } - end - - context 'when the commentaire sender is a guest on this dossier' do - let(:commentaire) { create(:commentaire, dossier: dossier, email: guest.email) } - it { is_expected.to be true } - end - end - - describe '.commentaire_date' do - let(:present_date) { Time.zone.local(2018, 9, 2, 10, 5, 0) } - let(:creation_date) { present_date } - let(:commentaire) do - Timecop.freeze(creation_date) { create(:commentaire, email: "michel@pref.fr") } - end - - subject do - Timecop.freeze(present_date) { commentaire_date(commentaire) } - end - - it 'doesn’t include the creation year' do - expect(subject).to eq 'le 2 septembre à 10 h 05' - end - - context 'when displaying a commentaire created on a previous year' do - let(:creation_date) { present_date.prev_year } - it 'includes the creation year' do - expect(subject).to eq 'le 2 septembre 2017 à 10 h 05' - end - end - - context 'when formatting the first day of the month' do - let(:present_date) { Time.zone.local(2018, 9, 1, 10, 5, 0) } - it 'includes the ordinal' do - expect(subject).to eq 'le 1er septembre à 10 h 05' - end - end - end end