diff --git a/Gemfile b/Gemfile
index 7c2898a62..3e235b9b0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
source "http://rubygems.org"
-ruby "2.7.2"
+ruby "2.7.8"
#gem "rails", "~> 3.2.16"
gem "rails", "5.1.7"
diff --git a/app/assets/javascripts/application.js.erb b/app/assets/javascripts/application.js.erb
index e59f2262d..a4fba8548 100755
--- a/app/assets/javascripts/application.js.erb
+++ b/app/assets/javascripts/application.js.erb
@@ -48,6 +48,8 @@
// = require initialize-jspanel
+// = require faqs
+
/**
* General
*/
diff --git a/app/assets/javascripts/faqs.js.erb b/app/assets/javascripts/faqs.js.erb
new file mode 100644
index 000000000..ee355e87b
--- /dev/null
+++ b/app/assets/javascripts/faqs.js.erb
@@ -0,0 +1,185 @@
+<%# @encoding: UTF-8 %>
+
+function faq_save(){
+ if (typeof CKEDITOR !== 'undefined') {
+ for (var instanceName in CKEDITOR.instances) {
+ CKEDITOR.instances[instanceName].updateElement();
+ }
+ }
+
+ $('form#faq_form').serialize_and_submit({
+ replace_list: $('.list_faqs')
+ });
+}
+
+function initFaqCKEditor(textareaId) {
+ if (typeof CKEDITOR !== 'undefined') {
+ if (CKEDITOR.instances[textareaId]) {
+ CKEDITOR.instances[textareaId].destroy();
+ }
+ CKEDITOR.replace(textareaId);
+ }
+}
+
+function updateFaqRemoveButtons() {
+ $('#translations-container .translation-fields:visible').each(function() {
+ var locale = $(this).find('select[name*="[locale]"]').val();
+ if (locale === 'pt_BR' || locale === 'en_US') {
+ $(this).find('.remove-translation').hide();
+ } else {
+ $(this).find('.remove-translation').show();
+ }
+ });
+}
+
+$(document).off('click.faqForm', '#add-translation').on('click.faqForm', '#add-translation', function(e) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ var translationIndex = $('#translations-container .translation-fields').length;
+ var $template = $('#translations-container .translation-fields').first().clone();
+
+ $template.find('.cke').remove();
+
+ $template.find('input[type="text"], textarea, select').val('');
+ $template.find('input[type="hidden"]').not('.destroy-flag').val('');
+ $template.find('.destroy-flag').val('false');
+
+ var newAnswerId;
+
+ $template.find('input, select, textarea').each(function() {
+ var $field = $(this);
+
+ if ($field.attr('name')) {
+ $field.attr('name', $field.attr('name').replace(/\[\d+\]/, '[' + translationIndex + ']'));
+ }
+
+ if ($field.attr('id')) {
+ var newId = $field.attr('id').replace(/_\d+_/, '_' + translationIndex + '_');
+ $field.attr('id', newId);
+
+ if ($field.attr('name') && $field.attr('name').indexOf('[answer]') > -1) {
+ newAnswerId = newId;
+ }
+ }
+ });
+
+ $template.find('label').each(function() {
+ if ($(this).attr('for')) {
+ $(this).attr('for', $(this).attr('for').replace(/_\d+_/, '_' + translationIndex + '_'));
+ }
+ });
+
+ if ($template.find('.remove-translation').length === 0) {
+ $template.prepend('');
+ }
+
+ $('#translations-container').append($template);
+
+ if (newAnswerId) {
+ setTimeout(function() {
+ initFaqCKEditor(newAnswerId);
+ }, 100);
+ }
+
+ updateFaqRemoveButtons();
+});
+
+$(document).off('click.faqForm', '.remove-translation').on('click.faqForm', '.remove-translation', function(e) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ var $translationField = $(this).closest('.translation-fields');
+ var visibleFields = $('#translations-container .translation-fields:visible').length;
+
+ if (visibleFields <= 2) {
+ alert('<%= I18n.t("faqs.form.min_translations_alert") %>');
+ return;
+ }
+
+ var $answerField = $translationField.find('textarea[name*="[answer]"]');
+ if ($answerField.length && $answerField.attr('id')) {
+ var editorId = $answerField.attr('id');
+ if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances[editorId]) {
+ CKEDITOR.instances[editorId].destroy();
+ }
+ }
+
+ // Se já existe no banco, marca para destruição; senão, remove do DOM
+ var $idField = $translationField.find('input[name*="[id]"]');
+ if ($idField.length && $idField.val() !== '') {
+ $translationField.find('.destroy-flag').val('true');
+ $translationField.hide();
+ } else {
+ $translationField.remove();
+ }
+
+ updateFaqRemoveButtons();
+});
+
+jQuery(function ($) {
+ $(".link_new_faq").call_fancybox({
+ width: '70%'
+ });
+
+ $(".link_show_faq").call_fancybox({
+ width: '70%'
+ });
+
+ $(".btn_edit[data-link-edit]").on('click', function(e) {
+ e.preventDefault();
+
+ var checkedBoxes = $('.ckb_faq:checked');
+ if (checkedBoxes.length === 1 && !$(this).attr('disabled')) {
+ var faqId = checkedBoxes.first().val();
+ var editUrl = $(this).data('link-edit').replace(':id', faqId);
+ $(this).call_fancybox({href: editUrl, open: true, width: '70%'});
+ }
+ return false;
+ });
+});
+
+jQuery(function ($) {
+ if ($(".tb_faqs").length === 0) {
+ return;
+ }
+
+ $(".up, .down").sort_row({
+ announceSelector: '#faq_announce',
+
+ getItemData: function($row) {
+ return {
+ id: $row.data('faq').id,
+ question: $row.data('question').trim()
+ };
+ },
+
+ isValidTarget: function($row) {
+ return !!$row.data('faq');
+ },
+
+ buildUrl: function(item, $targetRow) {
+ var $table = $targetRow.closest('table');
+ var urlTemplate = $table.data('reorderUrl');
+ var targetData = $targetRow.data('faq');
+ return urlTemplate.replace(':id', item.id).replace(':change_id', targetData.id);
+ },
+
+ formatBoundaryMessage: function(item, direction) {
+ if (direction === 'up') {
+ return 'A FAQ "' + item.question + '" já está no topo da lista';
+ } else {
+ return 'A FAQ "' + item.question + '" já está no final da lista';
+ }
+ },
+
+ formatMoveMessage: function(item, position) {
+ return 'FAQ "' + item.question + '" movida para a posição ' + position;
+ },
+
+ handleError: function(error) {
+ console.error("Falha ao atualizar a ordem:", error);
+ alert('<%= I18n.t("faqs.error.order") %>');
+ }
+ });
+});
diff --git a/app/assets/stylesheets/faq.scss b/app/assets/stylesheets/faq.scss
new file mode 100644
index 000000000..9d6d203f8
--- /dev/null
+++ b/app/assets/stylesheets/faq.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Faq controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: https://sass-lang.com/
diff --git a/app/assets/stylesheets/partials/_all.scss b/app/assets/stylesheets/partials/_all.scss
index e91fad5f4..e9e418c08 100644
--- a/app/assets/stylesheets/partials/_all.scss
+++ b/app/assets/stylesheets/partials/_all.scss
@@ -56,6 +56,7 @@
@import 'tutorials';
@import 'panels';
+@import 'faq';
@import 'load';
diff --git a/app/assets/stylesheets/partials/_faq.scss b/app/assets/stylesheets/partials/_faq.scss
new file mode 100644
index 000000000..3c713454d
--- /dev/null
+++ b/app/assets/stylesheets/partials/_faq.scss
@@ -0,0 +1,47 @@
+.faq-answer {
+ padding: 15px;
+ margin-top: 5px;
+ background-color: $background_light;
+ border-left: 3px solid $color_main;
+}
+
+.translation-content {
+ margin-bottom: 20px;
+ padding: 15px;
+ background-color: $background_light;
+ border-left: 3px solid $color_main;
+}
+
+#faq_form {
+ .faq_order input {
+ width: 80px !important;
+ }
+
+ .translation-fields input[type="text"] {
+ width: 100% !important;
+ }
+
+ .faq_active {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+
+ .control-label {
+ margin-bottom: 0;
+ }
+
+ span.radio {
+ display: inline-flex !important;
+ align-items: center;
+ margin: 0;
+
+ label {
+ display: inline-flex !important;
+ align-items: center;
+ gap: 5px;
+ margin: 0;
+ white-space: nowrap;
+ }
+ }
+ }
+}
diff --git a/app/controllers/faqs_controller.rb b/app/controllers/faqs_controller.rb
new file mode 100644
index 000000000..1e96f83dc
--- /dev/null
+++ b/app/controllers/faqs_controller.rb
@@ -0,0 +1,123 @@
+class FaqsController < ApplicationController
+
+ layout false, except: [:index, :apresentation]
+
+ before_action :require_admin
+ before_action :set_faq, only: [:show, :edit, :update, :destroy, :toggle_active, :order]
+ skip_before_action :require_admin, only:[:apresentation]
+
+ def index
+ @faqs = Faq.all
+ render layout: false if params[:layout].present? && params[:layout] == 'false'
+ end
+
+ def show
+ end
+
+ def new
+ @faq = Faq.new(active: true)
+ @faq.faq_translations.build(locale: 'pt_BR')
+ @faq.faq_translations.build(locale: 'en_US')
+ end
+
+ def create
+ @faq = Faq.new(faq_params)
+
+ begin
+ @faq.save!
+ render json: {success: true, notice: t('faqs.success.created')}
+ rescue
+ render :new
+ end
+ end
+
+ def edit
+ @faq.translation_pt
+ @faq.translation_en
+ end
+
+ def update
+ begin
+ @faq.update!(faq_params)
+ render json: {success: true, notice: t('faqs.success.updated')}
+ rescue
+ render :edit
+ end
+ end
+
+ def destroy
+ @faq.destroy
+
+ respond_to do |format|
+ format.html { redirect_to admin_faq_index_path, notice: t('faqs.success.deleted') }
+ format.json { render json: { success: true, notice: t('faqs.success.deleted') } }
+ end
+ end
+
+ def toggle_active
+ @faq.active = !@faq.active
+ @toggle_success = @faq.save
+ @toggle_errors = @faq.errors.full_messages.join(', ') unless @toggle_success
+
+ respond_to do |format|
+ format.js
+ format.json do
+ if @toggle_success
+ render json: { success: true, active: @faq.active }
+ else
+ render json: { success: false, errors: @faq.errors.full_messages }, status: :unprocessable_entity
+ end
+ end
+ end
+ end
+
+ def order
+ faq1 = @faq
+ faq2 = Faq.find(params[:change_id])
+
+ order1 = faq1.order
+ order2 = faq2.order
+
+ Faq.connection.execute(
+ "UPDATE faqs SET \"order\" = CASE
+ WHEN id = #{faq1.id} THEN #{order2}
+ WHEN id = #{faq2.id} THEN #{order1}
+ END
+ WHERE id IN (#{faq1.id}, #{faq2.id})"
+ )
+
+ render json: { success: true }
+ rescue => e
+ render json: { success: false, error: e.message }, status: :unprocessable_entity
+ end
+
+ def apresentation
+ @faq_order = Faq.faq_translations
+ render :faq
+ end
+
+ private
+ def require_admin
+ unless current_user.admin?
+ redirect_to home_path, alert: t(:no_permission)
+ end
+ end
+
+ def set_faq
+ @faq = Faq.find(params[:id])
+ end
+
+ def faq_params
+ params.require(:faq).permit(
+ :order,
+ :active,
+ faq_translations_attributes: [
+ :id,
+ :locale,
+ :question,
+ :answer,
+ :_destroy
+ ]
+ )
+ end
+end
diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb
index d2d2c4d6b..e3135ef46 100644
--- a/app/controllers/pages_controller.rb
+++ b/app/controllers/pages_controller.rb
@@ -12,6 +12,8 @@ def apps
end
def faq
+ # Busca FAQs ativos com traduções (usa scope :faq_translations do model Faq)
+ @faq_order = Faq.faq_translations
end
def privacy_policy
diff --git a/app/models/faq.rb b/app/models/faq.rb
new file mode 100644
index 000000000..62378d5d8
--- /dev/null
+++ b/app/models/faq.rb
@@ -0,0 +1,67 @@
+class Faq < ApplicationRecord
+ has_many :faq_translations, dependent: :destroy
+ accepts_nested_attributes_for :faq_translations, allow_destroy: true
+ validates :order, presence: true, numericality: {only_integer: true}
+ validates :active, inclusion: {in: [true, false]}
+ validate :unique_order_for_active_faqs
+
+ before_save :reorder_faqs_if_order_changed
+
+ default_scope {order(:order)}
+
+ scope :faq_translations, -> { includes(:faq_translations).where(active: true) }
+
+ def question
+ translation_for(I18n.locale)&.question
+ end
+
+ def answer
+ translation_for(I18n.locale)&.answer
+ end
+
+ def translation_for(locale)
+ faq_translations.find_by(locale: locale.to_s)
+ end
+
+ def translation_pt
+ faq_translations.find_or_initialize_by(locale: 'pt_BR')
+ end
+
+ def translation_en
+ faq_translations.find_or_initialize_by(locale: 'en_US')
+ end
+
+ private
+
+ def unique_order_for_active_faqs
+ return unless active
+
+ duplicate = Faq.where(active: true, order: order)
+ .where.not(id: id)
+ .exists?
+
+ if duplicate
+ errors.add(:order, 'já está em uso por outro FAQ ativo')
+ end
+ end
+
+ def reorder_faqs_if_order_changed
+ return unless order_changed? && persisted?
+
+ old_order = order_was
+ new_order = order
+
+ return if old_order == new_order
+
+ Faq.unscoped do
+ if new_order < old_order
+ Faq.where('id != ? AND "order" >= ? AND "order" < ?', id, new_order, old_order)
+ .update_all('"order" = "order" + 1')
+ else
+ Faq.where('id != ? AND "order" > ? AND "order" <= ?', id, old_order, new_order)
+ .update_all('"order" = "order" - 1')
+ end
+ end
+ end
+
+end
diff --git a/app/models/faq_translation.rb b/app/models/faq_translation.rb
new file mode 100644
index 000000000..df1324be0
--- /dev/null
+++ b/app/models/faq_translation.rb
@@ -0,0 +1,15 @@
+class FaqTranslation < ApplicationRecord
+ belongs_to :faq
+
+ AVAILABLE_LOCALES = %w[pt_BR en_US es_ES fr_FR de_DE it_IT].freeze
+
+ validates :locale, presence: true, inclusion: { in: AVAILABLE_LOCALES }
+ validates :question, presence: true
+ validates :answer, presence: true
+ validates :locale, uniqueness: { scope: :faq_id, message: "já existe para este FAQ" }
+ validates :question, uniqueness: {
+ scope: :locale,
+ case_sensitive: false,
+ message: "já existe neste idioma. Não é permitido perguntas duplicadas."
+ }
+end
diff --git a/app/views/faqs/_faq_row.html.haml b/app/views/faqs/_faq_row.html.haml
new file mode 100644
index 000000000..1746fdfa6
--- /dev/null
+++ b/app/views/faqs/_faq_row.html.haml
@@ -0,0 +1,20 @@
+%td{style: 'text-align: center;'}
+ = check_box_tag "ckb_faq[]", faq.id, false, class: 'ckb_faq', :'data-faq-id' => faq.id, :'aria-label' => t('.select_faq_aria', question: faq.question || 'FAQ')
+%td.center
+ .arrow_up= button_tag content_tag(:i, nil, class: 'icon-arrow-up-triangle'), class: 'up btn_arrow', :"aria-label" => t('faqs.index.up_aria', question: faq.question || 'FAQ'), :"data-tooltip" => t('faqs.index.up', default: 'Mover para cima')
+ .arrow_down= button_tag content_tag(:i, nil, class: 'icon-arrow-down-triangle'), class: 'down btn_arrow', :"aria-label" => t('faqs.index.down_aria', question: faq.question || 'FAQ'), :"data-tooltip" => t('faqs.index.down', default: 'Mover para baixo')
+%td
+ = link_to '#void', onclick: 'toggle_answer(this, event)', onkeydown: 'click_on_keypress(event, this);', class: 'faq-question', role: 'button', :'aria-expanded' => 'false', :'aria-label' => t('.toggle_answer_aria', question: faq.question || 'FAQ'), :'data-tooltip' => t('.expand_answer') do
+ = content_tag(:i, nil, class: 'icon-arrow-down-triangle', :'aria-hidden' => 'true')
+ %span= faq.question || t('.no_translation')
+ .faq-answer.invisible{:'aria-hidden' => 'true'}
+ %strong= t('.answer', default: 'Resposta:')
+ %p= raw(faq.answer || t('.no_translation'))
+%td.center{style: 'width: 70px;'}
+ - img_status = faq.active ? 'released.png' : 'rejected.png'
+ - tooltip_text = faq.active ? t('.deactivate', default: 'Desativar') : t('.activate', default: 'Ativar')
+ - aria_label_text = faq.active ? t('.deactivate_aria', question: faq.question || 'FAQ') : t('.activate_aria', question: faq.question || 'FAQ')
+ = link_to image_tag(img_status, alt: ''), toggle_active_admin_faq_path(faq), method: :patch, remote: true, class: 'change_faq_status', :'data-faq-id' => faq.id, :'data-tooltip' => tooltip_text, :'aria-label' => aria_label_text
+%td{style: 'text-align: center;'}
+ = link_to admin_faq_path(faq), class: 'btn link_show_faq', :'data-tooltip' => t('.show', default: 'Visualizar'), :'aria-label' => t('.show_aria', question: faq.question || 'FAQ') do
+ = content_tag(:i, nil, class: 'icon-eye', :'aria-hidden' => 'true')
diff --git a/app/views/faqs/_form.html.haml b/app/views/faqs/_form.html.haml
new file mode 100644
index 000000000..e9ff399ba
--- /dev/null
+++ b/app/views/faqs/_form.html.haml
@@ -0,0 +1,57 @@
+= simple_form_for @faq, url: (@faq.new_record? ? admin_faq_index_path : admin_faq_path(@faq)), html: { id: 'faq_form' } do |f|
+
+ %h1#lightBoxDialogTitle= t("faqs.#{@faq.persisted? ? 'edit' : 'new'}")
+ %span.form_requirement= t(:required_fields)
+
+ .form-inputs.block_content.faq_box#basic_info
+
+ = f.input :order, required: true, input_html: { value: @faq.order || 0 }
+ = f.input :active, as: :radio_buttons, required: true
+
+ %hr
+ %br
+
+ %h2= t('faqs.form.translations')
+
+ #translations-container
+ = f.simple_fields_for :faq_translations do |translation_form|
+ .translation-fields
+
+ - unless ['pt_BR', 'en_US'].include?(translation_form.object.locale)
+ %button.remove-translation{type: 'button', :'aria-label' => t('faqs.form.remove_aria', default: 'Remover esta tradução')}
+ %i.icon-remove{"aria-hidden" => "true"}
+ = t('faqs.form.remove')
+
+ = translation_form.input :locale,
+ collection: [['🇧🇷 Português (Brasil)', 'pt_BR'], ['🇺🇸 English (US)', 'en_US'], ['🇪🇸 Español', 'es_ES'], ['🇫🇷 Français', 'fr_FR'], ['🇩🇪 Deutsch', 'de_DE'], ['🇮🇹 Italiano', 'it_IT']],
+ required: true
+
+ = translation_form.input :question, required: true
+ = translation_form.input :answer, as: :ckeditor, required: true
+
+ = translation_form.input :_destroy, as: :hidden, input_html: { class: 'destroy-flag' }
+
+ %button#add-translation.btn.btn_default{type: 'button', :'aria-label' => t('faqs.form.add_language_aria', default: 'Adicionar nova tradução de idioma')}
+ %i.icon-plus{"aria-hidden" => "true"}
+ = t('faqs.form.add_language')
+
+ .form-actions.right_buttons
+ = button_tag t('faqs.form.cancel'), type: 'button', onclick: "jQuery.fancybox.close()", class: 'btn btn_default btn_lightbox', :'aria-label' => t('faqs.form.cancel_aria', default: 'Cancelar e fechar formulário')
+ = button_tag t('faqs.form.save'), type: 'button', onclick: "faq_save()", class: 'btn btn_main btn_lightbox', :'aria-label' => t('faqs.form.save_aria', default: 'Salvar FAQ')
+
+= javascript_include_tag 'ckeditor/init'
+
+:javascript
+ CKEDITOR_BASEPATH = "#{request.env['RAILS_RELATIVE_URL_ROOT']}/assets/ckeditor/";
+ CKEDITOR.editorConfig = function (config) {
+ config.language = "#{I18n.locale}";
+ config.toolbar =
+ [
+ { name: 'clipboard', items : [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ] },
+ { name: 'styles', items : [ 'Styles', 'Format', 'Font', 'TextColor' ] },
+ { name: 'basicstyles', items : [ 'Bold', 'Italic', 'Underline', 'Strike', '-', 'RemoveFormat' ] },
+ { name: 'paragraph', items : [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent' ] },
+ { name: 'links', items : [ 'Link', 'Unlink', 'Image' ] },
+ ];
+ config.autoParagraph = false;
+ };
diff --git a/app/views/faqs/edit.html.haml b/app/views/faqs/edit.html.haml
new file mode 100644
index 000000000..bcc583279
--- /dev/null
+++ b/app/views/faqs/edit.html.haml
@@ -0,0 +1 @@
+= render 'form'
diff --git a/app/views/faqs/faq.html.haml b/app/views/faqs/faq.html.haml
new file mode 100644
index 000000000..27b8931fb
--- /dev/null
+++ b/app/views/faqs/faq.html.haml
@@ -0,0 +1,73 @@
+= render '/user_sessions/header'
+#faq
+ .content
+ %br
+ #link
+ %a#link-password{href: home_path}= t(:back_home)
+
+ %h2= t(:faq_title)
+
+ .search
+ = t('faq.search')
+ = text_field_tag :search_faq, nil, :'aria-label'=>t('faq.search')
+
+ - @faqs.each do |faq|
+ .question
+ = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
+ %h4.title= faq.question
+ .invisible
+ %p.title_child_first=raw faq.answer
+
+ %h2= t(:video_tutorials)
+ %p.title_child_first=raw t(:video_tutorials_link)
+
+ %h2= t('faq.file_tutorials')
+ - if current_user.blank?
+ %p.title_child_first= raw t('faq.file_tutorials_title', url: tutorials_login_path)
+ - else
+ %p.title_child_first=raw t('faq.file_tutorials_link')
+
+
+:javascript
+ $(function(){
+ $('#search_faq').keyup(function(e){
+ var words = $(this).val().toLowerCase().split(' ');
+
+ if(words.length == 0 || (words.length == 1 && words[0] == '')){
+ $('.question').show();
+ }else{
+ $('.question').each(function(a){
+ var text = $(this).prop('textContent').toLowerCase();
+
+ var result = words.every(function(a) {
+ return text.indexOf(a) != -1;
+ });
+
+ if(result)
+ $(this).show();
+ else
+ $(this).hide();
+ });
+ }
+ });
+
+ });
+
+ function slide_info(obj, event){
+ event.preventDefault();
+ $(obj).next(".invisible").toggle();
+ if ($(obj).next(".invisible").is(":visible")) {
+ focus_element($(obj).next());
+ }
+ }
+
+ function click_on_keypress(event, element){
+ if(event.which == 13)
+ $(element).click();
+ return false;
+ }
+
+ function focus_element(element){
+ $(element).prop('tabindex', 0);
+ $(element).focus();
+ }
\ No newline at end of file
diff --git a/app/views/faqs/index.html.haml b/app/views/faqs/index.html.haml
new file mode 100644
index 000000000..90c37a53c
--- /dev/null
+++ b/app/views/faqs/index.html.haml
@@ -0,0 +1,145 @@
+.block_wrapper.list_faqs{:"data-link-list" => admin_faq_index_path(layout: false)}
+ .block_title
+ %h2= t('.title', default: 'Perguntas Frequentes (FAQ)')
+
+ .block_content_toolbar
+ .block_toolbar_left.btn-group
+ = link_to content_tag(:i, nil, class: 'icon-plus', :'aria-hidden' => 'true'), new_admin_faq_path, class: 'btn btn_main link_new_faq', :'data-tooltip' => t('.new', default: 'Novo FAQ'), :'aria-label' => t('.new_aria', default: 'Criar nova FAQ')
+
+ .block_toolbar_right
+ .btn-group
+ = link_to content_tag(:i, nil, class: 'icon-edit', :'aria-hidden' => 'true'), '#void', class: 'btn btn_edit', :'data-link-edit' => edit_admin_faq_path(id: ':id'), disabled: true, :'data-tooltip' => t('.edit', default: 'Editar'), :'aria-label' => t('.edit_aria', default: 'Editar FAQ selecionada')
+ = link_to content_tag(:i, nil, class: 'icon-trash', :'aria-hidden' => 'true'), '#void', class: 'btn btn_del delete_faq', :'data-link-delete' => admin_faq_path(id: ':id'), disabled: true, :'data-tooltip' => t('.delete', default: 'Deletar'), :'aria-label' => t('.delete_aria', default: 'Deletar FAQ(s) selecionada(s)')
+
+ .block_content.responsive-table
+ %table.tb_list.tb_faqs{data: { reorder_url: change_order_admin_faq_path(':id', ':change_id') }}
+ %thead{style: (@faqs.blank? ? 'display: none' : '')}
+ %tr.lines
+ %th.no_sort{style: 'text-align: center; width: 25px;'}= check_box_tag :all_faqs, false, false, :'data-children-names' => 'ckb_faq', class: 'all_faqs', :'aria-label' => t('.select_all_aria', default: 'Selecionar todas as FAQs')
+ %th.no_sort{style: 'width: 60px;'}= t('.order', default: 'Ordem')
+ %th{align: 'left'}= t('.question', default: 'Pergunta')
+ %th.no_sort{style: 'width: 80px; text-align: center;'}= t('.active', default: 'Ativo')
+ %th.no_sort{style: 'width: 60px; text-align: center;'}= t('.preview', default: 'Prévia')
+ %tbody
+ - @faqs.order(:order).each do |faq|
+ %tr.faq-row{"data-faq-id" => faq.id, "data-faq" => {id: faq.id}.to_json, "data-question" => faq.question || t('.no_translation')}
+ = render partial: 'faq_row', locals: { faq: faq }
+ .text_none.empty_message{class: (@faqs.blank? ? '' : 'hide_message')}= t('.no_data', default: 'Nenhuma FAQ cadastrada')
+
+ #faq_announce.visuallyhidden{"aria-live" => "polite"}
+
+:javascript
+ $(function(){
+ window.toggle_answer = function(element, event) {
+ event.preventDefault();
+ var $element = $(element);
+ var $answer = $element.next('.faq-answer');
+ var $icon = $element.find('i');
+ var isExpanded = $answer.is(':visible');
+
+ $answer.toggle();
+
+ if (!isExpanded) {
+ $icon.removeClass('icon-arrow-down-triangle').addClass('icon-arrow-up-triangle');
+ $element.attr('aria-expanded', 'true');
+ $answer.attr('aria-hidden', 'false');
+ } else {
+ $icon.removeClass('icon-arrow-up-triangle').addClass('icon-arrow-down-triangle');
+ $element.attr('aria-expanded', 'false');
+ $answer.attr('aria-hidden', 'true');
+ }
+ };
+
+ window.click_on_keypress = function(event, element) {
+ if (event.which == 13) {
+ $(element).click();
+ }
+ };
+
+ $('.all_faqs').on('change', function() {
+ var isChecked = $(this).is(':checked');
+ $('.ckb_faq').prop('checked', isChecked);
+ toggleActionButtons();
+ });
+
+ $('.ckb_faq').on('change', function() {
+ toggleActionButtons();
+ });
+
+ window.toggleActionButtons = function() {
+ var checkedBoxes = $('.ckb_faq:checked');
+ var $editBtn = $('.btn_edit[data-link-edit]');
+ var $deleteBtn = $('.delete_faq[data-link-delete]');
+
+ if (checkedBoxes.length === 0) {
+ $editBtn.attr('disabled', true).attr('href', '#void');
+ $deleteBtn.attr('disabled', true).attr('href', '#void');
+ } else if (checkedBoxes.length === 1) {
+ var faqId = checkedBoxes.first().val();
+ var editUrl = $editBtn.data('link-edit').replace(':id', faqId);
+ var deleteUrl = $deleteBtn.data('link-delete').replace(':id', faqId);
+
+ $editBtn.attr('disabled', false).attr('href', editUrl);
+ $deleteBtn.attr('disabled', false).attr('href', deleteUrl);
+ } else {
+ $editBtn.attr('disabled', true).attr('href', '#void');
+ $deleteBtn.attr('disabled', false);
+ }
+ };
+
+ $('.delete_faq').on('click', function(e) {
+ e.preventDefault();
+
+ if ($(this).attr('disabled')) {
+ return false;
+ }
+
+ var checkedBoxes = $('.ckb_faq:checked');
+ if (checkedBoxes.length === 0) {
+ return false;
+ }
+
+ if (!confirm("#{t('faqs.index.confirm_delete', default: 'Tem certeza que deseja deletar esta(s) FAQ(s)?')}")) {
+ return false;
+ }
+
+ var faqIds = [];
+ checkedBoxes.each(function() {
+ faqIds.push($(this).val());
+ });
+
+ deleteFaqs(faqIds, checkedBoxes);
+ });
+
+ function deleteFaqs(faqIds, checkedBoxes) {
+ var deleteUrl = $('.delete_faq').data('link-delete');
+ var promises = [];
+
+ faqIds.forEach(function(faqId) {
+ var url = deleteUrl.replace(':id', faqId);
+ promises.push(
+ $.ajax({
+ url: url,
+ type: 'DELETE',
+ dataType: 'json',
+ headers: {
+ 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
+ }
+ })
+ );
+ });
+
+ $.when.apply($, promises).done(function() {
+ flash_message("#{t('faqs.success.deleted', default: 'FAQ(s) deletada(s) com sucesso!')}", 'notice');
+ checkedBoxes.closest('tr').fadeOut(function() {
+ $(this).remove();
+ update_tables_with_no_data('.tb_faqs', 'tbody>tr');
+ });
+ toggleActionButtons();
+ }).fail(function() {
+ flash_message("#{t('faqs.error.delete', default: 'Erro ao deletar FAQ(s)')}", 'alert');
+ });
+ }
+ });
+
+= javascript_include_tag 'faqs'
diff --git a/app/views/faqs/new.html.haml b/app/views/faqs/new.html.haml
new file mode 100644
index 000000000..3c55de36f
--- /dev/null
+++ b/app/views/faqs/new.html.haml
@@ -0,0 +1,2 @@
+= render 'form'
+
diff --git a/app/views/faqs/show.html.haml b/app/views/faqs/show.html.haml
new file mode 100644
index 000000000..4c9be3443
--- /dev/null
+++ b/app/views/faqs/show.html.haml
@@ -0,0 +1,35 @@
+%h1#lightBoxDialogTitle= t('faqs.show.title', default: 'Visualizar FAQ')
+
+.form-inputs.block_content.faq_box
+ .faq-info{style: 'margin-bottom: 20px;'}
+ %p
+ %strong #{t('activerecord.attributes.faq.order')}:
+ = @faq.order
+ %p
+ %strong #{t('activerecord.attributes.faq.active')}:
+ = @faq.active ? t(:yes, default: 'Sim') : t(:no, default: 'Não')
+
+ %hr
+
+ %h2{style: 'margin-top: 20px;'}= "🇧🇷 #{t('faqs.show.portuguese', default: 'Português (Brasil)')}"
+ .translation-content
+ %p
+ %strong #{t('activerecord.attributes.faq_translation.question')}:
+ = @faq.translation_pt&.question || t('faqs.index.no_translation', default: '(sem tradução)')
+ %p
+ %strong #{t('activerecord.attributes.faq_translation.answer')}:
+ .answer-content= raw(@faq.translation_pt&.answer || t('faqs.index.no_translation', default: '(sem tradução)'))
+
+ %hr
+
+ %h2{style: 'margin-top: 20px;'}= "🇺🇸 #{t('faqs.show.english', default: 'English (US)')}"
+ .translation-content
+ %p
+ %strong #{t('activerecord.attributes.faq_translation.question')}:
+ = @faq.translation_en&.question || t('faqs.index.no_translation', default: '(no translation)')
+ %p
+ %strong #{t('activerecord.attributes.faq_translation.answer')}:
+ .answer-content= raw(@faq.translation_en&.answer || t('faqs.index.no_translation', default: '(no translation)'))
+
+.form-actions.right_buttons
+ = button_tag t('faqs.show.close', default: 'Fechar'), type: 'button', onclick: "jQuery.fancybox.close()", class: 'btn btn_default btn_lightbox'
diff --git a/app/views/faqs/toggle_active.js.haml b/app/views/faqs/toggle_active.js.haml
new file mode 100644
index 000000000..b44752792
--- /dev/null
+++ b/app/views/faqs/toggle_active.js.haml
@@ -0,0 +1,27 @@
+- if @toggle_success
+ - # Salvar estado do checkbox antes de atualizar
+ var $row = $("tr.faq-row[data-faq-id='#{@faq.id}']");
+ var wasChecked = $row.find('.ckb_faq').is(':checked');
+
+ - # Esconder tooltip antes de atualizar
+ $row.find('.change_faq_status').qtip('hide');
+
+ - # Atualizar conteúdo da linha
+ $row.html('#{j render partial: 'faq_row', locals: { faq: @faq }}');
+
+ - # Restaurar estado do checkbox
+ if (wasChecked) { $row.find('.ckb_faq').prop('checked', true); }
+
+ - # Reativar event listeners para o novo checkbox
+ $row.find('.ckb_faq').on('change', function() { toggleActionButtons(); });
+
+ - # Re-inicializar fancybox no link de visualizar
+ $row.find('.link_show_faq').call_fancybox({ width: '70%' });
+
+ - # Atualizar botões de ação
+ if (typeof toggleActionButtons === 'function') { toggleActionButtons(); }
+
+ flash_message('#{t('faqs.success.status_updated', default: 'Status atualizado com sucesso!')}', 'notice');
+- else
+ - # Reverter o estado visual e mostrar erro
+ flash_message('#{t('faqs.error.toggle_status', default: 'Erro ao atualizar status')}: #{@toggle_errors}', 'alert');
diff --git a/app/views/pages/faq.html.haml b/app/views/pages/faq.html.haml
index a8c006e99..679fa16ed 100644
--- a/app/views/pages/faq.html.haml
+++ b/app/views/pages/faq.html.haml
@@ -11,231 +11,14 @@
= t('faq.search')
= text_field_tag :search_faq, nil, :'aria-label'=>t('faq.search')
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title=t('faq.questions.whats_solar')
- .invisible
- %p.title_child_first=raw t('faq.answers.whats_solar')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.whats_ava')
- .invisible
- %p.title_child_first= raw t('faq.answers.whats_ava')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.uab_forgot_login_password')
- .invisible
- %p.title_child_first= raw t('faq.answers.uab_forgot_login_password')
-
- .question
- = link_to '#', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.uab_selfregistration')
- .invisible
- %p.title_child_first= raw t('faq.answers.uab_selfregistration')
- .question
- = link_to '#', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.email_confirmation')
- .invisible
- %p.title_child_first= raw t('faq.answers.email_confirmation')
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.forgot_login_password_ma')
- .invisible
- %p.title_child_first= raw t('faq.answers.forgot_login_password_ma')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.forgot_login_password_sync1')
- .invisible
- %p.title_child_first= raw t('faq.answers.forgot_login_password_sync')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.forgot_login_password_sync2')
- .invisible
- %p.title_child_first= raw t('faq.answers.forgot_login_password_sync')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.forgot_login_password_sync3')
- .invisible
- %p.title_child_first= raw t('faq.answers.forgot_login_password_sync')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.forgot_login_password')
- .invisible
- %p.title_child_first= raw t('faq.answers.forgot_login_password')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.recovery_password_email')
- .invisible
- %p.title_child_first= raw t('faq.answers.recovery_password_email')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.verify_registration')
- .invisible
- %p.title_child_first= raw t('faq.answers.verify_registration')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.update_data')
- .invisible
- %h4.title_child_first= raw t('faq.answers.not_ma')
- %p.title_child_second= raw t('faq.answers.update_data')
- %h4.title_child_first= raw t('faq.answers.ma')
- %p.title_child_second=raw t('faq.answers.update_data_ma')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.update_data_ma_cant')
- .invisible
- %p.title_child_first= raw t('faq.answers.update_data_ma_cant')
- %h4.title_child_first= raw t('faq.answers.have_access')
- %p.title_child_second= raw t('faq.answers.update_data_ma')
- %h4.title_child_first= raw t('faq.answers.dont_have_access')
- %p.title_child_second=raw t('faq.answers.update_data_ma_cant2')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.invalid_token')
- .invisible
- %p.title_child_first= raw t('faq.answers.invalid_token')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.how_to_enroll')
- .invisible
- %p.title_child_first= raw t('faq.answers.how_to_enroll')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.cant_access_uc')
- .invisible
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_date')
- %p.title_child_second= raw t('faq.answers.cant_access_uc_date')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_too_many')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_too_many')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_canceled')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_canceled')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_deactivated')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_deactivated')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_javascript')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_javascript')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_what_else')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_what_else')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.activity')
- .invisible
- %h4.title_child_first= raw t('faq.questions.activity_date')
- %p.title_child_second= raw t('faq.answers.activity_date')
- %h4.title_child_first= raw t('faq.questions.activity_error')
- %p.title_child_second=raw t('faq.answers.activity_error')
- %h4.title_child_first= raw t('faq.questions.activity_no_error')
- %p.title_child_second=raw t('faq.answers.activity_no_error')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.activity_lost_date')
- .invisible
- %p.title_child_first= raw t('faq.answers.activity_lost_date')
-
- .question
- = link_to '#coid', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.maintenance')
- .invisible
- %p.title_child_first= raw t('faq.answers.maintenance')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.uc_profile')
- .invisible
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_date')
- %p.title_child_second= raw t('faq.answers.cant_access_uc_date')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_too_many')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_too_many')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_canceled')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_canceled')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_deactivated')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_deactivated')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_javascript')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_javascript')
- %h4.title_child_first= raw t('faq.questions.cant_access_uc_what_else')
- %p.title_child_second=raw t('faq.answers.cant_access_uc_what_else')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.lesson_notes')
- .invisible
- %h4.title_child_first= raw t('faq.questions.lesson_notes_inside')
- %p.title_child_second= raw t('faq.answers.lesson_notes_inside')
- %h4.title_child_first= raw t('faq.questions.lesson_notes_outside')
- %p.title_child_second=raw t('faq.answers.lesson_notes_outside')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.uc_document')
- .invisible
- %p.title_child_first= raw t('faq.answers.uc_document')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.course_document')
- .invisible
- %p.title_child_first= raw t('faq.answers.course_document')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.photo')
- .invisible
- %p.title_child_first= raw t('faq.answers.photo')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.nick_login')
- .invisible
- %p.title_child_first= raw t('faq.answers.nick_login')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.finished_ucs')
- .invisible
- %p.title_child_first= raw t('faq.answers.finished_ucs')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.idea')
- .invisible
- %p.title_child_first= raw t('faq.answers.idea')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.error')
- .invisible
- %p.title_child_first= raw t('faq.answers.error')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.still_pending')
- .invisible
- %p.title_child_first= raw t('faq.answers.still_pending')
- %h4.title_child_first= raw t('faq.answers.still_pending_automatic')
- %p.title_child_second= raw t('faq.answers.still_pending_automatic_details')
- %p.title_child_second= raw t('faq.answers.still_pending_automatic_details2')
- %h4.title_child_first= raw t('faq.answers.still_pending_manually')
- %p.title_child_second=raw t('faq.answers.still_pending_manually_details')
-
- .question
- = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
- %h4.title= t('faq.questions.cant_find_faq')
- .invisible
- %p.title_child_first= raw t('faq.answers.cant_find_faq')
+ - @faq_order.each do |faq|
+ - current_translation = faq.faq_translations.find_by(locale: I18n.locale.to_s)
+ - if current_translation.present?
+ .question
+ = link_to '#void', onkeydown: 'click_on_keypress(event, this);', onclick: 'slide_info(this, event)', class: 'title' do
+ %h4.title= current_translation.question
+ .invisible
+ %p.title_child_first= raw(current_translation.answer)
%h2= t(:video_tutorials)
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
index b8ef91e55..8ddf4faeb 100644
--- a/config/initializers/assets.rb
+++ b/config/initializers/assets.rb
@@ -1,4 +1,4 @@
# TODO: o sistema usa include_tags de js e css em varios lugares.
# E isso precisa ser corrigido. Enquanto isso segue um "workaround":
-Rails.application.config.assets.precompile += %w[academic_allocation_user.js administrations.js allocations.js application.js assignment_webconferences.js assignments.js audios.js autocomplete.js bibliographies.js bibliography_authors.js breadcrumb.js calendar.js chat_rooms.js ckeditor/init.js comments.js contextual_help/discussion.js contextual_help/discussion_posts.js contextual_help/home.js contextual_help/lessons.js contextual_help/subject.js contextual_help/support_material.js courses.js digital_classes.js discussions.js edition.js edition_discussions.js enrollments.js exams.js fullcalendar.js group_assignments.js groups.js groups_tags.js ie-warning.js ip.js jquery-3.3.1.min.js jquery-ui-1.8.6.js jquery-ui-timepicker-addon.js jquery-ui.js jquery.cookie.js jquery.dropdown.js jquery.fancybox3.min.js jquery.js jquery.mask.js jquery.qtip.min.js jquery.tokeninput.js jquery.ui.datepicker-en-US.js jquery.ui.datepicker-pt-BR.js jspanel.js jspdf.min.js lesson_files.js lesson_notes.js lessons.js login.js lte-ie7 lte-ie7.js messages.js multiple_file_upload.js notifications.js online_correction_files.js pagination.js pdfjs/pdf.js portlet_slider.js profiles.js questions.js registrations.js respond.min.js schedule_event_files.js schedule_events.js scores.js shortcut.js social_networks.js tableHeadFixer.js tablesorter.js tooltip.js user_blacklist.js webconferences.js zoom/jquery.zoom.js]
+Rails.application.config.assets.precompile += %w[academic_allocation_user.js administrations.js allocations.js application.js assignment_webconferences.js assignments.js audios.js autocomplete.js bibliographies.js bibliography_authors.js breadcrumb.js calendar.js chat_rooms.js ckeditor/init.js comments.js contextual_help/discussion.js contextual_help/discussion_posts.js contextual_help/home.js contextual_help/lessons.js contextual_help/subject.js contextual_help/support_material.js courses.js digital_classes.js discussions.js edition.js edition_discussions.js enrollments.js exams.js faqs.js fullcalendar.js group_assignments.js groups.js groups_tags.js ie-warning.js ip.js jquery-3.3.1.min.js jquery-ui-1.8.6.js jquery-ui-timepicker-addon.js jquery-ui.js jquery.cookie.js jquery.dropdown.js jquery.fancybox3.min.js jquery.js jquery.mask.js jquery.qtip.min.js jquery.tokeninput.js jquery.ui.datepicker-en-US.js jquery.ui.datepicker-pt-BR.js jspanel.js jspdf.min.js lesson_files.js lesson_notes.js lessons.js login.js lte-ie7 lte-ie7.js messages.js multiple_file_upload.js notifications.js online_correction_files.js pagination.js pdfjs/pdf.js portlet_slider.js profiles.js questions.js registrations.js respond.min.js schedule_event_files.js schedule_events.js scores.js shortcut.js social_networks.js tableHeadFixer.js tablesorter.js tooltip.js user_blacklist.js webconferences.js zoom/jquery.zoom.js]
Rails.application.config.assets.precompile += %w[themes/theme_blue.css themes/theme_red.css themes/theme_high_contrast.css autocomplete.css fancyBox.css fonts/fonts-ie.css fonts/fonts.css fonts/icons.css fullcalendar.css.css jquery-ui-timepicker-addon.css jquery.dropdown.css.css jquery.fancybox3.min.css jquery.qtip.min.css login.css misc/div_layout.css misc/facebook.css misc/ie7.css online_correction_files.css pdf.css ui.dynatree.custom.css viewer.css]
diff --git a/config/locales/en_US.yml b/config/locales/en_US.yml
index 3e2cd1afd..72563298a 100644
--- a/config/locales/en_US.yml
+++ b/config/locales/en_US.yml
@@ -214,6 +214,8 @@ en_US:
email: Email
supportmaterialfile: Support Material
schedule_event_file: Arquivo
+ faq: FAQ
+ faq_translation: FAQ Translation
attributes:
user:
password: "Password"
@@ -516,6 +518,13 @@ en_US:
attachment_content_type: ""
attachment_file_size: ""
attachment_file_name: ""
+ faq:
+ order: Order
+ active: Active
+ faq_translation:
+ locale: Language
+ question: Question
+ answer: Answer
errors:
uniqueness: "Record already exists in the system"
template:
@@ -590,6 +599,18 @@ en_US:
attributes:
attachment_content_type:
invalid_type: invalid
+ faq:
+ attributes:
+ order:
+ taken: is already in use by another active FAQ
+ active:
+ inclusion: must be selected
+ faq_translation:
+ attributes:
+ question:
+ blank: can't be blank
+ answer:
+ blank: can't be blank
all: "All"
of: "of"
@@ -1714,6 +1735,7 @@ en_US:
menu_admin_notifications: General notifications
menu_events: Events
menu_admin_report_webconference: UAB web conferencing report
+ menu_admin_faq: Frequently Asked Questions
places_nav_panel_course_hint: "Type the course's name or part of it"
places_nav_panel_semester_hint: "Type the semester or part of it"
@@ -5303,3 +5325,80 @@ en_US:
date_range_expired: It was not possible to execute action. Date range expired.
no_acu: Is not possible to create a comment to this student at this group.
must_have_comment: It is not possible to create a comment without a previous comment.
+
+ # FAQ Translations
+ faqs:
+ new: New FAQ
+ edit: Edit FAQ
+ show:
+ title: View FAQ
+ index:
+ title: Frequently Asked Questions (FAQ)
+ new: New FAQ
+ new_aria: Create new FAQ
+ edit: Edit
+ edit_aria: Edit selected FAQ
+ delete: Delete
+ delete_aria: Delete selected FAQ(s)
+ show: View
+ preview: Preview
+ order: Order
+ question: Question
+ answer: Answer
+ active: Active
+ no_translation: (no translation)
+ activate: Activate
+ deactivate: Deactivate
+ no_data: No FAQs registered
+ confirm_delete: Are you sure you want to delete this FAQ?
+ select_all_aria: Select all FAQs
+ up: Move up
+ down: Move down
+ up_aria: Move FAQ "%{question}" up
+ down_aria: Move FAQ "%{question}" down
+ reached_top: FAQ "%{question}" is already at the top of the list
+ reached_bottom: FAQ "%{question}" is already at the bottom of the list
+ change_position: FAQ "%{question}" moved to position %{row_position}
+ faq_row:
+ answer: Answer
+ no_translation: (no translation)
+ deactivate: Deactivate
+ deactivate_aria: Deactivate FAQ "%{question}"
+ activate: Activate
+ activate_aria: Activate FAQ "%{question}"
+ show: View
+ show_aria: View FAQ "%{question}"
+ select_faq_aria: Select FAQ "%{question}"
+ expand_answer: Expand answer
+ collapse_answer: Collapse answer
+ toggle_answer_aria: Click to expand or collapse the answer to the question "%{question}"
+ form:
+ translations: FAQ Translations
+ save: Save
+ save_aria: Save FAQ
+ cancel: Cancel
+ cancel_aria: Cancel and close form
+ add_language: Add another language
+ add_language_aria: Add new language translation
+ remove: Remove
+ remove_aria: Remove this translation
+ min_translations_alert: You must keep at least 2 translations (Portuguese and English).
+ success:
+ created: FAQ created successfully
+ updated: FAQ updated successfully
+ error:
+ order: Error updating FAQ order
+
+ simple_form:
+ labels:
+ faq:
+ order: Display order
+ active: FAQ active (visible on site)
+ faq_translation:
+ question: Question
+ answer: Answer
+ placeholders:
+ faq_translation:
+ question: Type the question...
+ answer: Type the answer...
+
diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml
index 93e40dd3f..c8e5aa485 100644
--- a/config/locales/pt_BR.yml
+++ b/config/locales/pt_BR.yml
@@ -249,6 +249,8 @@ pt_BR:
email: Email
supportmaterialfile: Material de Apoio
schedule_event_file: Arquivo
+ faq: FAQ
+ faq_translation: Tradução do FAQ
attributes:
user:
alternate_email: "E-mail alternativo"
@@ -581,6 +583,13 @@ pt_BR:
attachment_content_type: ""
attachment_file_size: ""
attachment_file_name: ""
+ faq:
+ order: Ordem
+ active: Ativo
+ faq_translation:
+ locale: Idioma
+ question: Pergunta
+ answer: Resposta
errors:
uniqueness: "Registro já existe no sistema"
template:
@@ -655,6 +664,18 @@ pt_BR:
attributes:
attachment_content_type:
invalid_type: inválido
+ faq:
+ attributes:
+ order:
+ taken: já está em uso por outro FAQ ativo
+ active:
+ inclusion: deve ser selecionado
+ faq_translation:
+ attributes:
+ question:
+ blank: não pode ficar em branco
+ answer:
+ blank: não pode ficar em branco
########### GERAL ###############
@@ -1982,7 +2003,8 @@ pt_BR:
menu_admin_notifications: Avisos Gerais
menu_events: "Eventos"
menu_admin_report_webconference: Relatório webconferências UAB
-
+ # FAQ adicionado
+ menu_admin_faq: FAQ
# Componente de filtro/busca de allocationTags (places_nav_panel)
places_nav_panel_course_hint: "Digite o nome do curso ou parte dele"
places_nav_panel_semester_hint: "Digite o semestre"
@@ -5287,6 +5309,7 @@ pt_BR:
idea: "Tenho uma ideia para o Solar, como posso sugerí-la para implementação?"
error: "Sou responsável por uma disciplina e um portfólio enviado pelo aluno aparece em branco. Pode ser erro do sistema?"
cant_find_faq: "Não encontrei minha dúvida neste FAQ?"
+ still_pending: "Discente alcançou frequências e notas satisfatórias para aprovação, mas o Resultado apresenta situação 'Pendente', o que fazer?"
uab_selfregistration: "O que é o autocadastro no Sigaa? Como posso realizar o autocadastro?"
email_confirmation: "Realizei meu autocadastro, como faço para utilizar o Solar?"
still_pending: "Discente alcançou frequências e notas satisfatórias para aprovação, mas o Resultado apresenta situação 'Pendente', o que fazer?"
@@ -5333,6 +5356,12 @@ pt_BR:
idea: "O Solar 2.0 dispõe de um botão de 'Sugestões para o Solar 2.0'. Para acessá-lo, basta realizar o login, que o botão ficará disponível no canto superior direito da tela logo abaixo do relógio.
Lá você poderá enviar sugestões, reclamações e similares."
error: "O Solar 2.0 não altera dados nem arquivos previamente enviados pelos usuários sem comunicá-los ou sem prévia autorização. Portanto, se o portfolio do aluno está em branco, sugerimos que entre em contato com ele para solicitar um re-envio do arquivo correto."
cant_find_faq: "Entre em contato com o atendimento@virtual.ufc.br relatando sua situação. Lembre-se de informar:
‣ Nome
‣ Cpf
‣ Email
‣ O maior número de informações sobre o ocorrido. Se possível, imagens (prints de tela) também."
+ still_pending: "Destacamos que só é possível definir a situação quando as atividades da turma e disciplina estão configuradas como avaliativas e/ou de frequência.
Caso a turma esteja devidamente configurada, você pode:"
+ still_pending_automatic: "‣ Aguardar a data de definição automática de situação"
+ still_pending_automatic_details: "Ao configurar as atividades que serão contabilizadas para média e frequência, o Solar define uma data para as situações serem definidas. Esta data é escolhida de acordo com a data de encerramento da última atividade avaliativa, que não seja AF. Portanto, as situações ficarão como 'Pendente' até que esta data chegue.
Exemplo: há as seguintes atividades em uma disciplina: