Skip to content

Commit

Permalink
Merge pull request #10137 from colinux/faqs
Browse files Browse the repository at this point in the history
Internalisation de la FAQ
  • Loading branch information
colinux authored May 16, 2024
2 parents 1d2550e + a41ba20 commit b74319b
Show file tree
Hide file tree
Showing 144 changed files with 2,044 additions and 71 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ gem 'flipper'
gem 'flipper-active_record'
gem 'flipper-active_support_cache_store'
gem 'flipper-ui'
gem 'front_matter_parser'
gem 'fugit'
gem 'geocoder'
gem 'geo_coord', require: "geo/coord"
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ GEM
fog-core (~> 2.1)
fog-json (>= 1.0)
formatador (1.1.0)
front_matter_parser (1.0.1)
fugit (1.10.1)
et-orbi (~> 1, >= 1.2.7)
raabro (~> 1.4)
Expand Down Expand Up @@ -923,6 +924,7 @@ DEPENDENCIES
flipper-active_record
flipper-active_support_cache_store
flipper-ui
front_matter_parser
fugit
geo_coord
geocoder
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/images/faq/instructeur-filtres-and.png
Binary file added app/assets/images/faq/instructeur-filtres-or.png
Binary file added app/assets/images/faq/sign-in-page.png
Binary file added app/assets/images/faq/usager-dossiers-list.png
Binary file added app/assets/images/faq/usager-dropdown.png
Binary file added app/assets/images/faq/usager-edit-email.png
Binary file added app/assets/images/faq/usager-footer-contact.png
Binary file added app/assets/images/faq/usager-messagerie.png
Binary file added app/assets/images/faq/usager-transfer-dossier.png
20 changes: 20 additions & 0 deletions app/assets/stylesheets/markdown-content.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.markdown-content {
img {
max-width: 100%;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);

display: block;

// In markdown img are always wrapped in p,
// which already contains vertical margin.
// We only add margin when there are siblings.
// NOTE: CSS consider the img is only-child even
// when there are only text node siblings, but it's still fine for us.
margin: 1.5rem auto;

&:only-child {
margin-top: 0;
margin-bottom: 0;
}
}
}
2 changes: 1 addition & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def sentry_config
environment: sentry[:environment],
browser: { modern: BrowserSupport.supported?(browser) },
user: sentry_user,
release: SentryRelease.current
release: ApplicationVersion.current
}
end

Expand Down
39 changes: 39 additions & 0 deletions app/controllers/faq_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

class FAQController < ApplicationController
before_action :load_faq_data, only: :show

def index
@faqs = loader_service.all
end

def show
@renderer = Redcarpet::Markdown.new(Redcarpet::TrustedRenderer.new(view_context), autolink: true)

@siblings = loader_service.faqs_for_category(@metadata[:category])
end

private

def loader_service
@loader_service ||= begin
substitutions = {
application_base_url: Current.application_base_url,
application_name: Current.application_name,
contact_email: Current.contact_email
}

FAQsLoaderService.new(substitutions)
end
end

def load_faq_data
path = "#{params[:category]}/#{params[:slug]}"
faq_data = loader_service.find(path)

@content = faq_data.content
@metadata = faq_data.front_matter.symbolize_keys
rescue KeyError
raise ActionController::RoutingError.new("FAQ not found: #{path}")
end
end
2 changes: 1 addition & 1 deletion app/lib/redcarpet/bare_renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def autolink(link, link_type)
when :url
link(link, nil, link)
when :email
# NOTE: As of Redcarpet 3.6.0, autolinking email containing is broken https://github.com/vmg/redcarpet/issues/402
# NOTE: As of Redcarpet 3.6.0, autolinking email containing underscore is broken https://github.com/vmg/redcarpet/issues/402
content_tag(:a, link, { href: "mailto:#{link}" })
else
link
Expand Down
41 changes: 41 additions & 0 deletions app/lib/redcarpet/trusted_renderer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
module Redcarpet
class TrustedRenderer < Redcarpet::Render::HTML
include ActionView::Helpers::TagHelper
include Sprockets::Rails::Helper
include ApplicationHelper

attr_reader :view_context

def initialize(view_context, extensions = {})
@view_context = view_context

super extensions
end

def link(href, title, content)
html_options = {
href: href
}

unless href.starts_with?('/')
html_options.merge!(title: new_tab_suffix(title), **external_link_attributes)
end

content_tag(:a, content, html_options, false)
end

def autolink(link, link_type)
case link_type
when :url
link(link, nil, link)
when :email
# NOTE: As of Redcarpet 3.6.0, autolinking email containing underscore is broken https://github.com/vmg/redcarpet/issues/402
content_tag(:a, link, { href: "mailto:#{link}" })
end
end

def image(link, title, alt)
view_context.image_tag(link, title:, alt:, loading: :lazy)
end
end
end
63 changes: 63 additions & 0 deletions app/services/faqs_loader_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

class FAQsLoaderService
PATH = Rails.root.join('doc', 'faqs').freeze
ORDER = ['usager', 'instructeur', 'administrateur'].freeze

attr_reader :substitutions

def initialize(substitutions)
@substitutions = substitutions

@faqs_by_path ||= Rails.cache.fetch(["faqs_data", ApplicationVersion.current, substitutions], expires_in: 1.week) do
load_faqs
end
end

def find(path)
Rails.cache.fetch(["faq", path, ApplicationVersion.current, substitutions], expires_in: 1.week) do
file_path = @faqs_by_path.fetch(path).fetch(:file_path)

parse_with_substitutions(file_path)
end
end

def faqs_for_category(category)
@faqs_by_path.values
.filter { |faq| faq[:category] == category }
.group_by { |faq| faq[:subcategory] }
end

def all
@faqs_by_path.values
.group_by { |faq| faq.fetch(:category) }
.sort_by { |category, _| ORDER.index(category) || ORDER.size }
.to_h
.transform_values do |faqs|
faqs.group_by { |faq| faq.fetch(:subcategory) }
end
end

private

def load_faqs
Dir.glob("#{PATH}/**/*.md").each_with_object({}) do |file_path, faqs_by_path|
parsed = parse_with_substitutions(file_path)
front_matter = parsed.front_matter.symbolize_keys

faq_data = front_matter.slice(:slug, :title, :category, :subcategory, :locale, :keywords).merge(file_path: file_path)

path = front_matter.fetch(:category) + '/' + front_matter.fetch(:slug)
faqs_by_path[path] = faq_data
end
end

# Substitute all string before front matter parser so metadata are also substituted.
# using standard ruby formatting, ie => `%{my_var} % { my_var: 'value' }`
# We have to escape % chars not used for substitutions, ie. not preceeded by {
def parse_with_substitutions(file_path)
substituted_content = File.read(file_path).gsub(/%(?!{)/, '%%') % substitutions

FrontMatterParser::Parser.new(:md).call(substituted_content)
end
end
2 changes: 1 addition & 1 deletion app/views/administrateurs/_breadcrumbs.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
- 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])), **external_link_attributes
= 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])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
- c.with_body do
%p
= t('.faq_test_alert')
= link_to t('.faq_test_alert_link'), t('.faq_test_alert_link_url'), **external_link_attributes
= link_to t('.faq_test_alert_link'), t('.faq_test_alert_link_url')
= render partial: 'publication_form_inputs', locals: { procedure: procedure, closed_procedures: @closed_procedures, form: f }
= render Dsfr::CalloutComponent.new(title: t('.dpd_title'), heading_level: 'h2') do |c|
- c.with_body do
Expand Down
13 changes: 13 additions & 0 deletions app/views/faq/_breadcrumb.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
%nav.fr-breadcrumb{ role: "navigation", 'aria-label': t('you_are_here', scope: [:layouts, :breadcrumb]) }
%button.fr-breadcrumb__button{ 'aria-expanded' => "false", 'aria-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'

%li
%a.fr-breadcrumb__link{ **(defined?(faq_title) ? { href: faq_index_path } : { "aria-current": "page" }) }= t('faq', scope: [:layouts, :breadcrumb])

- if defined?(faq_title)
%li
%a.fr-breadcrumb__link{ 'aria-current' => "page" }= faq_title
20 changes: 20 additions & 0 deletions app/views/faq/_sidebar.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
%nav.fr-sidemenu.fr-sidemenu--sticky{ role: "navigation", 'aria-labelledby': "fr-sidemenu-title" }
.fr-sidemenu__inner
%button.fr-sidemenu__btn{ 'aria-controls': "fr-sidemenu-wrapper", 'aria-expanded': "false" }
= t(:sidebar_button, scope: [:faq])
.fr-collapse#fr-sidemenu-wrapper
.fr-sidemenu__title#fr-sidemenu-title
= t(:name, scope: [:faq, :categories, current[:category]])
%ul.fr-sidemenu__list
- faqs.each_with_index do |(subcategory, faqs), index|
%li{ class: class_names("fr-sidemenu__item", "fr-sidemenu__item--active" => subcategory == current[:subcategory]) }
%button.fr-sidemenu__btn{ aria: { 'expanded': subcategory == current[:subcategory] ? "true" : "false",
'controls': "fr-sidemenu-item-#{index}",
'current' => subcategory == current[:subcategory] ? "true" : nil } }
= t(:name, scope: [:faq, :subcategories, subcategory])
.fr-collapse{ id: "fr-sidemenu-item-#{index}" }
%ul.fr-sidemenu__list
- faqs.each do |faq|
%li{ class: class_names("fr-sidemenu__item", "fr-sidemenu__item--active" => faq[:slug] == current[:slug]) }
= link_to faq[:title], faq_path(category: faq[:category], slug: faq[:slug]),
class: 'fr-sidemenu__link', target: "_self", "aria-current" => current[:slug] == faq[:slug] ? "page" : nil
26 changes: 26 additions & 0 deletions app/views/faq/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
- content_for(:title, t('.meta_title'))

.fr-container.fr-my-4w
= render partial: "breadcrumb"
.fr-grid-row
.fr-col-12.fr-col-md-10
%h1= t('.title', app_name: Current.application_name)

- @faqs.each do |category, subcategories|
%h2= t(:name, scope: [:faq, :categories, category], raise: true) # i18n-tasks-use t("faq.categories.#{category}.name")
%p= t(:description, scope: [:faq, :categories, category], raise: true) # i18n-tasks-use t("faq.categories.#{category}.description")

.fr-accordions-group.fr-mb-6w
- subcategories.each_with_index do |(subcategory, faqs), index|
%section.fr-accordion
%h3.fr-accordion__title
%button.fr-accordion__btn{ 'aria-expanded': "false", 'aria-controls': "accordion-#{category}-#{index}" }
= t(:name, scope: [:faq, :subcategories, subcategory], raise: true) # i18n-tasks-use t("faq.subcategories.#{subcategory}.name")

.fr-collapse{ id: "accordion-#{category}-#{index}" }
- description = t(:description, scope: [:faq, :subcategories, subcategory], default: nil) # i18n-tasks-use t("faq.subcategories.#{subcategory}.description")
%p= description if description.present?

%ul
- faqs.each do |faq|
%li= link_to faq[:title], faq_path(category: faq[:category], slug: faq[:slug]), class: "fr-link"
13 changes: 13 additions & 0 deletions app/views/faq/show.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
- content_for(:title, @metadata[:title])

.fr-container.fr-my-4w

.fr-grid-row
.fr-col-12.fr-col-md-4
= render partial: "sidebar", locals: { faqs: @siblings, current: @metadata }
.fr-col-12.fr-col-md-8
-# i18n-tasks-use t("faq.categories.#{@metadata[:category]}.short_name")
= render partial: "breadcrumb", locals: { faq_title: "#{t(:short_name, scope: [:faq, :categories, @metadata[:category]])} : #{@metadata[:title]}" }

.markdown-content
= @renderer.render(@content).html_safe
2 changes: 1 addition & 1 deletion app/views/layouts/_header.haml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
= render partial: 'shared/help/help_dropdown_instructeur'
- else
// NB: on mobile in order to have links correctly aligned, we need a left icon
= link_to t('help'), t("links.common.faq.url"), class: 'fr-btn dropdown-button', title: new_tab_suffix(t('help')), **external_link_attributes
= link_to t('help'), t("links.common.faq.url"), class: 'fr-btn dropdown-button', title: t('help')



Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/commencer/_no_procedure.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
%p= t('.line3')
%hr
%p.small-simple= t('.are_you_new', app_name: Current.application_name)
= link_to t('views.users.sessions.new.find_procedure'), t("links.common.faq.comment_trouver_ma_demarche_url"), title: new_tab_suffix(t('views.users.sessions.new.find_procedure')), class: "fr-btn fr-btn--secondary", **external_link_attributes
= link_to t('views.users.sessions.new.find_procedure'), t("links.common.faq.comment_trouver_ma_demarche_url"), title: new_tab_suffix(t('views.users.sessions.new.find_procedure')), class: "fr-btn fr-btn--secondary"
4 changes: 2 additions & 2 deletions app/views/root/landing.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
%h2= t(".have_a_procedure")
%p.fr-h5= t(".fill_procedure")

= link_to t(".how_to_find_procedure"), t("links.common.faq.comment_trouver_ma_demarche_url"), class: "fr-btn fr-btn--lg fr-mr-1w fr-mb-2w", title: new_tab_suffix(t(".how_to_find_procedure")), **external_link_attributes
= link_to t(".how_to_find_procedure"), t("links.common.faq.comment_trouver_ma_demarche_url"), class: "fr-btn fr-btn--lg fr-mr-1w fr-mb-2w", title: new_tab_suffix(t(".how_to_find_procedure"))
= link_to t("views.users.sessions.new.connection"), new_user_session_path, class: "fr-btn fr-btn--secondary fr-btn--lg"

.fr-py-6w
Expand Down Expand Up @@ -51,7 +51,7 @@
%h2= t(".question")
%p.fr-h5= t(".answer_in_faq")
%div
= link_to t(".online_help"), t("links.common.faq.url"), class: "fr-btn fr-btn--lg", title: new_tab_suffix(t(".online_help")), **external_link_attributes
= link_to t(".online_help"), t("links.common.faq.url"), class: "fr-btn fr-btn--lg", title: t(".online_help")

.fr-py-6w
.container
Expand Down
2 changes: 1 addition & 1 deletion app/views/shared/champs/siret/_etablissement.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- when :not_found
%p.fr-error-text
Nous n’avons pas trouvé d’établissement correspondant à ce numéro de SIRET.
= link_to('Plus d’informations', t("links.common.faq.erreur_siret_url"), **external_link_attributes)
= link_to('Plus d’informations', t("links.common.faq.erreur_siret_url"))

- when :network_error
%p.fr-error-text= t('errors.messages.siret_network_error')
Expand Down
4 changes: 2 additions & 2 deletions app/views/static_pages/accessibility_statement.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@
= t("views.accessibility_statement.preparation.page_six")
%li
= link_to t("views.accessibility_statement.preparation.page_seven.label"), t("views.accessibility_statement.preparation.page_seven.url"),
title: t("views.accessibility_statement.preparation.page_seven.title"), **external_link_attributes
title: t("views.accessibility_statement.preparation.page_seven.title")
%li
= link_to t("views.accessibility_statement.preparation.page_eight.label"), t("views.accessibility_statement.preparation.page_eight.url"),
title: t("views.accessibility_statement.preparation.page_eight.title"), **external_link_attributes
title: t("views.accessibility_statement.preparation.page_eight.title")
%li
= t("views.accessibility_statement.preparation.page_nine")
%li
Expand Down
2 changes: 1 addition & 1 deletion app/views/users/dossiers/_dossiers_list.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,4 @@
%p.empty-text-details
= t('views.users.dossiers.dossiers_list.no_result_text_html', app_base: Current.application_base_url)
%p
= link_to t("root.landing.how_to_find_procedure"), t("links.common.faq.comment_trouver_ma_demarche_url"), class: "fr-btn fr-btn--lg fr-mr-1w fr-mb-2w", **external_link_attributes
= link_to t("root.landing.how_to_find_procedure"), t("links.common.faq.comment_trouver_ma_demarche_url"), class: "fr-btn fr-btn--lg fr-mr-1w fr-mb-2w"
2 changes: 1 addition & 1 deletion app/views/users/sessions/link_sent.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@

%section
%p.fr-mt-3w
Si vous voyez cette page trop souvent, consultez notre aide : #{link_to t("links.common.faq.confirmer_compte_chaque_connexion_url"), t("links.common.faq.confirmer_compte_chaque_connexion_url"), **external_link_attributes}
Si vous voyez cette page trop souvent, #{link_to "consultez notre aide", t("links.common.faq.confirmer_compte_chaque_connexion_url")}
%p.fr-mt-3w
= t('views.users.shared.contact_us_if_any_trouble_html', href: contact_admin_url)
Loading

0 comments on commit b74319b

Please sign in to comment.