feat(announces): show Nouveautés link in main navigation
This commit is contained in:
parent
352ed3969c
commit
49cd10458c
14 changed files with 224 additions and 11 deletions
|
@ -13,3 +13,14 @@ span.notifications {
|
|||
top: 5px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
.fr-nav {
|
||||
&__notifiable {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.notifications {
|
||||
top: 1rem;
|
||||
right: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
|
24
app/components/main_navigation/announces_link_component.rb
Normal file
24
app/components/main_navigation/announces_link_component.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MainNavigation::AnnouncesLinkComponent < ApplicationComponent
|
||||
def render?
|
||||
# also see app/controllers/release_notes_controller.rb#ensure_access_allowed!
|
||||
return false if !helpers.instructeur_signed_in? && !helpers.administrateur_signed_in? && !helpers.expert_signed_in?
|
||||
|
||||
@most_recent_released_on = load_most_recent_released_on
|
||||
|
||||
@most_recent_released_on.present?
|
||||
end
|
||||
|
||||
def something_new?
|
||||
return true if current_user.announces_seen_at.nil?
|
||||
|
||||
@most_recent_released_on.after? current_user.announces_seen_at
|
||||
end
|
||||
|
||||
def load_most_recent_released_on
|
||||
categories = helpers.infer_default_announce_categories
|
||||
|
||||
ReleaseNote.most_recent_announce_date_for_categories(categories)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
en:
|
||||
news: News
|
||||
something_new: New informations about the website may be of interest to you.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
fr:
|
||||
news: Nouveautés
|
||||
something_new: De nouvelles informations à propos du site pourraient vous intéresser.
|
|
@ -0,0 +1,4 @@
|
|||
%li.fr-nav__item.fr-nav__notifiable
|
||||
= link_to t('.news'), release_notes_path, class: "fr-nav__link",'aria-current': current_page?(release_notes_path) ? 'page' : nil
|
||||
- if something_new?
|
||||
%span.notifications{ 'aria-label': t('.something_new') }
|
|
@ -10,3 +10,5 @@
|
|||
= Avis.model_name.human(count: 10)
|
||||
- if helpers.current_expert.avis_summary[:unanswered] > 0
|
||||
%span.badge.warning= helpers.current_expert.avis_summary[:unanswered]
|
||||
|
||||
= render MainNavigation::AnnouncesLinkComponent.new
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
class ReleaseNotesController < ApplicationController
|
||||
before_action :ensure_access_allowed!
|
||||
after_action :touch_default_categories_seen_at
|
||||
|
||||
def index
|
||||
@categories = params[:categories].presence || infer_default_categories
|
||||
@categories = params[:categories].presence || helpers.infer_default_announce_categories
|
||||
|
||||
# Paginate per group of dates, then show all announces for theses dates
|
||||
@paginated_groups = ReleaseNote.published
|
||||
|
@ -20,18 +21,26 @@ class ReleaseNotesController < ApplicationController
|
|||
render "scrollable_list" if params[:page].present?
|
||||
end
|
||||
|
||||
def nav_bar_profile
|
||||
# detect context from referer, simple (no detection when refreshing the page)
|
||||
params = Rails.application.routes.recognize_path(request&.referer)
|
||||
|
||||
controller_class = "#{params[:controller].camelize}Controller".safe_constantize
|
||||
return if controller_class.nil?
|
||||
|
||||
controller_instance = controller_class.new
|
||||
controller_instance.try(:nav_bar_profile)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def infer_default_categories
|
||||
if administrateur_signed_in?
|
||||
['administrateur', 'usager', current_administrateur.api_tokens.exists? ? 'api' : nil]
|
||||
elsif instructeur_signed_in?
|
||||
['instructeur', 'expert']
|
||||
elsif expert_signed_in?
|
||||
['expert']
|
||||
else
|
||||
['usager']
|
||||
end
|
||||
def touch_default_categories_seen_at
|
||||
return if params[:categories].present? || params[:page].present?
|
||||
return if current_user.blank?
|
||||
|
||||
return if current_user.announces_seen_at&.after?(@announces.max_by(&:released_on).released_on)
|
||||
|
||||
current_user.touch(:announces_seen_at)
|
||||
end
|
||||
|
||||
def ensure_access_allowed!
|
||||
|
|
|
@ -15,4 +15,16 @@ module ReleaseNotesHelper
|
|||
|
||||
content_tag(:span, ReleaseNote.human_attribute_name("categories.#{category}"), class: "fr-badge #{color_class}")
|
||||
end
|
||||
|
||||
def infer_default_announce_categories
|
||||
if administrateur_signed_in?
|
||||
ReleaseNote.default_categories_for_role(:administrateur, current_administrateur)
|
||||
elsif instructeur_signed_in?
|
||||
ReleaseNote.default_categories_for_role(:instructeur, current_instructeur)
|
||||
elsif expert_signed_in?
|
||||
ReleaseNote.default_categories_for_role(:expert, current_expert)
|
||||
else
|
||||
ReleaseNote.default_categories_for_role(:usager)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,4 +14,21 @@ class ReleaseNote < ApplicationRecord
|
|||
|
||||
scope :published, -> { where(published: true, released_on: ..Date.current) }
|
||||
scope :for_categories, -> (categories) { where("categories && ARRAY[?]::varchar[]", categories) }
|
||||
|
||||
def self.default_categories_for_role(role, instance = nil)
|
||||
case role
|
||||
when :administrateur
|
||||
['administrateur', 'usager', instance.api_tokens.exists? ? 'api' : nil]
|
||||
when :instructeur
|
||||
['instructeur', instance.user.expert? ? 'expert' : nil]
|
||||
when :expert
|
||||
['expert', instance.user.instructeur? ? 'instructeur' : nil]
|
||||
else
|
||||
['usager']
|
||||
end
|
||||
end
|
||||
|
||||
def self.most_recent_announce_date_for_categories(categories)
|
||||
published.for_categories(categories).maximum(:released_on)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,3 +3,5 @@
|
|||
%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: current_administrateur.zones), class:'fr-nav__link', 'aria-current': current_page?(all_admin_procedures_path) ? 'page' : nil
|
||||
|
||||
= render MainNavigation::AnnouncesLinkComponent.new
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe MainNavigation::AnnouncesLinkComponent, type: :component do
|
||||
let(:user) { build(:user) }
|
||||
let!(:admin_release_note) { create(:release_note, released_on: Date.yesterday, categories: ["administrateur"]) }
|
||||
let!(:instructeur_release_note) { create(:release_note, released_on: Date.yesterday, categories: ["instructeur"]) }
|
||||
let(:not_published_release_note) { create(:release_note, published: false, released_on: Date.tomorrow) }
|
||||
|
||||
let(:as_administrateur) { false }
|
||||
let(:as_instructeur) { false }
|
||||
|
||||
before do
|
||||
if as_administrateur
|
||||
user.build_administrateur
|
||||
end
|
||||
|
||||
if as_instructeur
|
||||
user.build_instructeur
|
||||
end
|
||||
|
||||
allow(controller).to receive(:current_user).and_return(user)
|
||||
end
|
||||
|
||||
subject { render_inline(described_class.new) }
|
||||
|
||||
context 'when signed as simple user' do
|
||||
it 'does not render the announcements link if not signed in' do
|
||||
expect(subject.to_html).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no signed in' do
|
||||
let(:current_user) { nil }
|
||||
|
||||
it 'does not render the announcements link if not signed in' do
|
||||
expect(subject.to_html).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when instructeur signed in' do
|
||||
let(:as_instructeur) { true }
|
||||
|
||||
it 'renders the announcements link' do
|
||||
expect(subject).to have_link("Nouveautés")
|
||||
end
|
||||
|
||||
context 'when there are new announcements' do
|
||||
before do
|
||||
user.announces_seen_at = 5.days.ago
|
||||
end
|
||||
|
||||
it 'does not render the notification badge' do
|
||||
expect(subject).to have_link("Nouveautés")
|
||||
expect(subject).to have_css(".notifications")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are no new announcements' do
|
||||
before do
|
||||
user.announces_seen_at = 1.minute.ago
|
||||
end
|
||||
|
||||
it 'does not render the notification badge' do
|
||||
expect(subject).to have_link("Nouveautés")
|
||||
expect(subject).not_to have_css(".notifications")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are no announcement at all' do
|
||||
let(:instructeur_release_note) { nil }
|
||||
|
||||
it 'does not render anything' do
|
||||
expect(subject.to_html).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when administrateur signed in' do
|
||||
let(:as_administrateur) { true }
|
||||
|
||||
it 'renders the announcements link' do
|
||||
expect(subject).to have_link("Nouveautés")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -42,6 +42,14 @@ describe MainNavigation::InstructeurExpertNavigationComponent, type: :component
|
|||
expect(subject).not_to have_selector('a[aria-current="page"]', text: 'Avis')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are release notes' do
|
||||
let!(:release_note) { create(:release_note, categories: ['instructeur']) }
|
||||
|
||||
it 'renders a link to Announces page' do
|
||||
expect(subject).to have_link('Nouveautés')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when expert is signed in' do
|
||||
|
|
|
@ -47,5 +47,31 @@ RSpec.describe ReleaseNotesController, type: :controller do
|
|||
it { is_expected.to be_redirection }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'touch user announces_seen_at' do
|
||||
let(:user) { create(:user, administrateur: build(:administrateur)) }
|
||||
|
||||
context 'when default categories' do
|
||||
it 'touch announces_seen_at' do
|
||||
expect { subject }.to change { user.reload.announces_seen_at }
|
||||
end
|
||||
|
||||
context 'when current announces_seen_at is more recent than last announce' do
|
||||
before { user.update(announces_seen_at: 1.second.ago) }
|
||||
|
||||
it 'does not touch announces_seen_at' do
|
||||
expect { subject }.not_to change { user.reload.announces_seen_at }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when specific categories' do
|
||||
subject { get :index, params: { categories: ['administrateur', 'instructeur'] } }
|
||||
|
||||
it 'does not touch announces_seen_at' do
|
||||
expect { subject }.not_to change { user.reload.announces_seen_at }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,8 @@ describe 'layouts/_header', type: :view do
|
|||
allow(view).to receive(:multiple_devise_profile_connect?).and_return(false)
|
||||
allow(view).to receive(:instructeur_signed_in?).and_return((profile == :instructeur))
|
||||
allow(view).to receive(:current_instructeur).and_return(current_instructeur)
|
||||
allow(view).to receive(:administrateur_signed_in?).and_return(false)
|
||||
allow(view).to receive(:expert_signed_in?).and_return(false)
|
||||
allow(view).to receive(:localization_enabled?).and_return(false)
|
||||
|
||||
if user
|
||||
|
@ -57,6 +59,7 @@ describe 'layouts/_header', type: :view do
|
|||
let(:user) { instructeur.user }
|
||||
let(:profile) { :instructeur }
|
||||
let(:current_instructeur) { instructeur }
|
||||
let!(:release_note) { create(:release_note, categories: ['instructeur']) }
|
||||
|
||||
it { is_expected.to have_css(".fr-header__logo") }
|
||||
it { is_expected.to have_selector(:button, user.email, class: "account-btn") }
|
||||
|
|
Loading…
Reference in a new issue