Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feedback button #527

Merged
merged 65 commits into from Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
e7796d2
Init Feedback model
Splines Jun 4, 2023
9c66595
Add Feedback modal view and corresponding controller
Splines Jun 4, 2023
dfe9036
Merge branch 'mampf-next' into feature/feedback-button
Splines Jul 3, 2023
d41365e
Migrate feedback form to Bootstrap v5
Splines Jul 3, 2023
5836422
Add basic styling to Feedback form
Splines Jul 3, 2023
56c4741
Add "allow contact via mail" checkbox
Splines Jul 5, 2023
90d044e
Toggle "allow email contact" by default
Splines Jul 5, 2023
f8dcdd1
Merge branch 'mampf-next' into feature/feedback-button
Splines Aug 7, 2023
cd057ed
Improve submit button handler (outsource to function)
Splines Aug 7, 2023
27e49b9
Init feedback mailer
Splines Aug 7, 2023
58f4389
Adjust feedback mail in views
Splines Aug 7, 2023
8d8e2b2
Implement success/error flow with toast messages
Splines Aug 22, 2023
1ec66e2
Add missing database field "can_contact"
Splines Aug 22, 2023
2021b98
Add internationalization to feedback error/success
Splines Aug 22, 2023
5310512
Lint some files
Splines Aug 22, 2023
352543b
Set feedback text field as required with min 10 chars
Splines Aug 22, 2023
aa3b359
Add "optional" to title in email
Splines Aug 22, 2023
2fbab06
Adjust spacing around feedback button
Splines Aug 22, 2023
c31a6f1
Internationalize tooltip
Splines Aug 22, 2023
bef5016
Delete console log
Splines Aug 22, 2023
92a0b2c
Add comment describing hidden submit button handler
Splines Aug 22, 2023
86eaa8d
Delete default test specs
Splines Aug 22, 2023
4fbe953
Add proper validation for Feedback body
Splines Aug 26, 2023
d8a34f5
Merge branch 'mampf-next' into feature/feedback-button
Splines Aug 26, 2023
0d43345
Merge branch 'mampf-next' into feature/feedback-button
Splines Aug 26, 2023
ace2b08
Default `can_contact` to false in backend
Splines Aug 27, 2023
5cd1af2
Update bootstrap to v5.3.1
Splines Aug 27, 2023
4ed0757
Revert "Update bootstrap to v5.3.1" in favor of PR #537
Splines Aug 27, 2023
b348061
Submit form via Ctrl + Enter when modal is opened
Splines Aug 28, 2023
696a395
Remove default nil value from ENV.fetch()
Splines Aug 28, 2023
d7f0462
Merge branch 'mampf-next' into feature/feedback-button
Splines Oct 17, 2023
1261706
Revert "Remove default nil value from ENV.fetch()"
Splines Oct 17, 2023
dab8b3b
Rename button to 'Send' (not 'Save')
Splines Oct 17, 2023
6e8c769
Check if should register feedback event handlers
Splines Oct 22, 2023
7f60853
Make feedback button ID more specific
Splines Oct 22, 2023
26f9ae8
Fix line wrapping (code style)
Splines Oct 22, 2023
2b02a48
Use delete on cascade to be able to delete a user
Splines Oct 22, 2023
3a215fc
Move Send button before Cancel button
Splines Oct 30, 2023
07ba509
Replace "on delete cascade" with "dependent destroy"
Splines Oct 30, 2023
8884707
Add cypress rules to ESLint & ignore some patterns
Splines Dec 19, 2023
d1593f1
Allow usage of tempusDominus global variable
Splines Dec 20, 2023
144135e
Ignore JS files with Sprocket syntax
Splines Dec 20, 2023
19342f7
Further improve rules, e.g. allow common globals
Splines Jan 3, 2024
70dbfed
Ignore sprocket syntax in cable.js
Splines Jan 3, 2024
9b9c082
Autofix all `.js` and `.js.erb` files
Splines Jan 3, 2024
cedd0c4
Fix variables in turbolink fix
Splines Jan 3, 2024
f8366ab
Prepend unused variables with "_"
Splines Jan 3, 2024
bc87b65
Get rid of unused widget variable
Splines Jan 3, 2024
a8fc972
Fix specs comment tab alignment
Splines Jan 3, 2024
47b7cc6
Merge branch 'lint/eslint-all' into feature/feedback-button
Splines Jan 3, 2024
f636d0f
Warn about too long GitHub commit messages (#586)
Splines Jan 11, 2024
eb9484a
Fix comment status (#585)
Splines Jan 16, 2024
475fc04
Migrate `unread_comments` flag (fix inconsistencies) (#587)
Splines Jan 17, 2024
92d48d4
Use `warn` log level for migration (#588)
Splines Jan 19, 2024
13d685d
Merge branch 'dev' into feature/feedback-button
Splines Jan 25, 2024
ca14be2
Fix linting in feedback.js
Splines Jan 25, 2024
aaf9d37
Fix RuboCop errors
Splines Jan 25, 2024
db8173e
Fix remaining ESLint errors
Splines Jan 25, 2024
be140b5
Update timestamp of feedback migration
Splines Jan 25, 2024
5374cb2
Add missing Feedback email to prod docker.env
Splines Jan 25, 2024
4952d6e
Merge branch 'dev' into feature/feedback-button
Splines Mar 19, 2024
da0b409
Remove unnecessary Feedback env variables
Splines Mar 19, 2024
ebf95cb
Add validation message for empty body
Splines Mar 19, 2024
d5c2e0c
Change `const` to `var` to avoid "redefined" errors
Splines Mar 19, 2024
a36cf52
Update timestamp of feedback migration (again)
Splines Mar 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions app/assets/javascripts/feedback.js
@@ -0,0 +1,24 @@
$(document).on('turbolinks:load', () => {
registerToasts();
registerSubmitButtonHandler();
});

TOAST_OPTIONS = {
animation: true,
autohide: true,
delay: 6000 // autohide after ... milliseconds
};

function registerToasts() {
const toastElements = document.querySelectorAll('.toast');
const toastList = [...toastElements].map(toast => {
new bootstrap.Toast(toast, TOAST_OPTIONS);
});
}

function registerSubmitButtonHandler() {
$('#submit-form-btn-outside').click(() => {
// Invoke the hidden submit button inside the actual Rails form
$('#submit-form-btn').click();
});
}
2 changes: 2 additions & 0 deletions app/assets/javascripts/lectures.coffee
Expand Up @@ -217,6 +217,7 @@ $(document).on 'turbolinks:load', ->
$('#secondnav').show()
$('#lecturesDropdown').appendTo($('#secondnav'))
$('#notificationDropdown').appendTo($('#secondnav'))
$('#feedback-btn').appendTo($('#secondnav'))
$('#searchField').appendTo($('#secondnav'))
$('#second-admin-nav').show()
$('#adminDetails').appendTo($('#second-admin-nav'))
Expand All @@ -239,6 +240,7 @@ $(document).on 'turbolinks:load', ->
$('#secondnav').hide()
$('#lecturesDropdown').appendTo($('#firstnav'))
$('#notificationDropdown').appendTo($('#firstnav'))
$('#feedback-btn').appendTo($('#firstnav'))
$('#searchField').appendTo($('#firstnav'))
$('#second-admin-nav').hide()
$('#teachableDrop').appendTo($('#first-admin-nav'))
Expand Down
6 changes: 5 additions & 1 deletion app/assets/stylesheets/application.scss
Expand Up @@ -302,4 +302,8 @@ a {
&:hover {
text-decoration: underline;
}
}
}

.toast {
background-color: white;
}
11 changes: 11 additions & 0 deletions app/assets/stylesheets/feedback.scss
@@ -0,0 +1,11 @@
#feedback-btn {
color: white;

&:focus {
box-shadow: none;
}

&:hover {
color: #ffc107;
}
}
21 changes: 21 additions & 0 deletions app/controllers/feedbacks_controller.rb
@@ -0,0 +1,21 @@
class FeedbacksController < ApplicationController
authorize_resource except: [:create]

def create
feedback = Feedback.new(feedback_params)
feedback.user_id = current_user.id
@feedback_success = feedback.save

if @feedback_success
FeedbackMailer.with(feedback: feedback).new_user_feedback_email.deliver_later
end

respond_to(&:js)
end

private

def feedback_params
params.require(:feedback).permit(:title, :feedback, :can_contact)
end
end
15 changes: 15 additions & 0 deletions app/mailers/feedback_mailer.rb
@@ -0,0 +1,15 @@
class FeedbackMailer < ApplicationMailer
default from: DefaultSetting::FEEDBACK_EMAIL
layout false

# Mail to the MaMpf developers including the new feedback of a user.
def new_user_feedback_email
@feedback = params[:feedback]
reply_to_mail = @feedback.can_contact ? @feedback.user.email : ''
subject = "Feedback: #{@feedback.title}"
mail(to: DefaultSetting::FEEDBACK_EMAIL,
subject: subject,
content_type: 'text/plain',
reply_to: reply_to_mail)
end
end
3 changes: 3 additions & 0 deletions app/models/feedback.rb
@@ -0,0 +1,3 @@
class Feedback < ApplicationRecord
belongs_to :user
end
13 changes: 13 additions & 0 deletions app/views/feedback_mailer/new_user_feedback_email.text.erb
@@ -0,0 +1,13 @@
# Title (optional)
<%= @feedback.title %>

# Feedback
<%= @feedback.feedback %>


-----
<% if @feedback.can_contact %>
Reply to this mail to contact the user.
<% else %>
User did not give permission to contact them regarding their feedback, so we cannot reply to this mail.
<% end %>
Splines marked this conversation as resolved.
Show resolved Hide resolved
44 changes: 44 additions & 0 deletions app/views/feedbacks/_feedback.html.erb
@@ -0,0 +1,44 @@
<%= stylesheet_link_tag 'feedback' %>

<%# Main Modal %>
<div id="submit-feedback" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="Submit feedback" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content p-4">
<%= render partial: 'feedbacks/feedback_form' %>
</div>
</div>
</div>

<%# Messages toasts %>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<%# Error %>
<div role="alert" aria-live="assertive" aria-atomic="true"
class="toast" id="toast-could-not-send">

<div class="toast-header text-danger">
<i class="bi bi-x-square-fill pe-1"></i>
<strong class="me-auto"> <%= t('feedback.error_short') %></strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>

<div class="toast-body">
<%= t('feedback.error') %>
</div>
</div>

<%# Success %>
<div role="alert" aria-live="assertive" aria-atomic="true"
class="toast" id="toast-successfully-sent">

<div class="toast-header text-success">
<i class="bi bi-check-square-fill pe-1"></i>
<strong class="me-auto"> <%= t('feedback.success_short') %></strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>

<div class="toast-body">
<%= t('feedback.success') %>
</div>
</div>

</div>
8 changes: 8 additions & 0 deletions app/views/feedbacks/_feedback_button.html.erb
@@ -0,0 +1,8 @@
<%= stylesheet_link_tag 'feedback' %>

<%# Feedback button %>
<button type="button" id="feedback-btn" class="btn ms-1 me-1" title="<%= t('feedback.tooltip') %>"
data-bs-toggle="modal"
data-bs-target="#submit-feedback">
<i class="bi bi-star-fill"></i>
</button>
59 changes: 59 additions & 0 deletions app/views/feedbacks/_feedback_form.html.erb
@@ -0,0 +1,59 @@
<%= javascript_include_tag :feedback %>

<div class="modal-header">
<i class="bi bi-star-fill me-3"></i>
<h1 class="modal-title fs-5"><%= t('feedback.modal_title') %></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
</button>
</div>

<div class="modal-body">
<%= t('feedback.description_html',
github_mampf: link_to('GitHub', 'https://github.com/MaMpf-HD/mampf/issues', {target: '_blank'}),
feedback_mail: mail_to(DefaultSetting::FEEDBACK_EMAIL, t('basics.mail_noun'))) %>

<%= form_with model: Feedback.new, remote: true do |f| %>
<%# Title %>
<div class="form-floating mb-3">
<%= f.text_field :title, class: 'form-control', placeholder: '_' %>
<%= f.label :title, t('feedback.title') %>
</div>

<%# Comment %>
<div class="form-floating mb-3">
<%= f.text_area :feedback,
class: 'form-control',
placeholder: '_',
style: 'height: 200px',
required: '',
minlength: '10' %>
<%= f.label :feedback, t('feedback.comment') %>
</div>

<%# Email contact %>
<div class="form-check">
<%= f.check_box :can_contact,
checked: 'checked',
class: 'form-check-input' %>
<%= f.label :can_contact,
t('feedback.mail_checkbox', user_mail: @current_user.email),
class: 'form-check-label' %>
</div>

<%# Submit %>
<%# Dummy submit button, the actual submit button is in the modal footer %>
<%= f.submit 'Submit', id: 'submit-form-btn', style: 'display: none;' %>
<% end %>
</div>

<div class="modal-footer">
<%# Cancel %>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
<%= t('buttons.cancel') %>
</button>

<%# Submit %>
<button type="button" id="submit-form-btn-outside" class="btn btn-primary">
<%= t('buttons.save') %>
</button>
</div>
7 changes: 7 additions & 0 deletions app/views/feedbacks/create.js.erb
@@ -0,0 +1,7 @@
<% if @feedback_success %>
$('#submit-feedback').modal('hide');
$('#submit-feedback').find('form').trigger('reset'); // clear form
$('#toast-successfully-sent').toast('show');
<% else %>
$('#toast-could-not-send').toast('show');
<% end %>
4 changes: 2 additions & 2 deletions app/views/shared/_dropdown_notifications.html.erb
@@ -1,7 +1,7 @@
<% relevant_notifications = current_user.notifications
.sort_by(&:created_at).reverse %>
<% if relevant_notifications.present? %>
<ul class="navbar-nav me-3"
<ul class="navbar-nav"
id="notificationDropdown">
<li class="nav-item">
<div class="btn-group">
Expand Down Expand Up @@ -49,4 +49,4 @@
</div>
</li>
</ul>
<% end %>
<% end %>
2 changes: 1 addition & 1 deletion app/views/shared/_footer.html.erb
Expand Up @@ -46,7 +46,7 @@
bugs: link_to(t('here'),
'https://github.com/MaMpf-HD/mampf/issues',
target: :_blank),
feedback: mail_to(DefaultSetting::PROJECT_EMAIL, nil),
feedback: mail_to(DefaultSetting::FEEDBACK_EMAIL, nil),
background_photo_credit: link_to('Junpeng Ouyang',
'https://unsplash.com/photos/nGs0d1dGFng',
target: :_blank)) %>
Expand Down
15 changes: 8 additions & 7 deletions app/views/shared/_navbar.html.erb
@@ -1,5 +1,8 @@
<% I18n.with_locale(current_user.try(:locale)) do %>
<%= stylesheet_link_tag 'navbar' %>

<%= render partial: 'feedbacks/feedback' %>

<div class="navbars-container">
<nav class="navbar navbar-expand" id="firstnav">
<%= link_to image_tag('MaMpf-Logo.svg',
Expand Down Expand Up @@ -30,7 +33,6 @@
</a>
</li>


<% if current_user.admin || current_user.editor? || current_user.teacher? %>
<li class="nav-item">
<a href="<%= administration_path %>"
Expand All @@ -41,7 +43,6 @@
</li>
<% end %>


<li class="nav-item">
<a href="<%= watchlists_path %>"
id="watchlistsIcon"
Expand All @@ -51,7 +52,6 @@
</a>
</li>


<li class="nav-item">
<a href="<%= comments_path %>"
id="commentsIcon"
Expand All @@ -63,7 +63,6 @@
</a>
</li>


<li class="nav-item">
<a href="<%= news_path %>"
class="nav-link bi bi-megaphone-fill <%= get_class_for_path(news_path()) %>"
Expand All @@ -72,7 +71,6 @@
</a>
</li>


<li class="nav-item">
<a href="<%= DefaultSetting::BLOG_LINK %>"
class="nav-link bi bi-newspaper"
Expand All @@ -81,7 +79,6 @@
</a>
</li>


<li class="nav-item">
<a href="<%= destroy_user_session_path(params: { locale: current_user.locale }) %>"
class="nav-link bi bi-box-arrow-right"
Expand All @@ -96,7 +93,11 @@
<%= render partial: 'shared/dropdown_lectures',
locals: { lecture: @lecture || current_lecture } %>
</ul>
<%= render partial: 'shared/dropdown_notifications'%>

<%= render partial: 'shared/dropdown_notifications' %>

<%= render partial: 'feedbacks/feedback_button' %>

<%= form_tag(search_index_path,
method: 'get',
class: 'form-inline mt-2 mt-md-0',
Expand Down
13 changes: 7 additions & 6 deletions config/initializers/default_setting.rb
Splines marked this conversation as resolved.
Show resolved Hide resolved
@@ -1,10 +1,11 @@
class DefaultSetting
ERDBEERE_LINK = ENV['ERDBEERE_SERVER']
MUESLI_LINK = ENV['MUESLI_SERVER']
PROJECT_EMAIL = ENV['PROJECT_EMAIL']
PROJECT_NOTIFICATION_EMAIL = ENV['PROJECT_NOTIFICATION_EMAIL']
BLOG_LINK = ENV['BLOG']
URL_HOST_SHORT = ENV['URL_HOST_SHORT']
ERDBEERE_LINK = ENV.fetch('ERDBEERE_SERVER', nil)
MUESLI_LINK = ENV.fetch('MUESLI_SERVER', nil)
PROJECT_EMAIL = ENV.fetch('PROJECT_EMAIL', nil)
FEEDBACK_EMAIL = ENV.fetch('FEEDBACK_EMAIL', nil)
PROJECT_NOTIFICATION_EMAIL = ENV.fetch('PROJECT_NOTIFICATION_EMAIL', nil)
BLOG_LINK = ENV.fetch('BLOG', nil)
URL_HOST_SHORT = ENV.fetch('URL_HOST_SHORT', nil)
RESEARCHGATE_LINK = 'https://www.researchgate.net/project/MaMpf-Mathematische-Medienplattform'
TOUR_LINK = 'https://mampf.blog/ueber-mampf/'
RESOURCES_LINK = 'https://mampf.blog/ressourcen-fur-editorinnen/'
Expand Down
25 changes: 25 additions & 0 deletions config/locales/de.yml
Expand Up @@ -3162,6 +3162,7 @@ de:
course_editors: 'ModuleditorInnen'
lecture_editors: 'zusätzliche VeranstaltungseditorInnen'
display_name: 'Anzeigename'
mail_noun: 'E-Mail'
email: 'E-Mail-Adresse'
preferences: 'Einstellungen'
language: 'Sprache'
Expand Down Expand Up @@ -3792,3 +3793,27 @@ de:
name:
taken:
'Eine Watchlist mit diesem Namen existiert bereits.'
feedback:
tooltip: Feedback geben
modal_title: Feedback geben
title: Titel (optional)
comment: Dein Kommentar
description_html: >
<p>Wir freuen uns über Dein Feedack zu MaMpf, sei es Lob, Kritik oder
Anregungen, wie wir als Entwickler:innen-Team die Plattform voranbringen
können. Falls Du einen Bug gefunden hast und einen GitHub-Account hast,
dann erstelle am besten direkt auf %{github_mampf} ein Issue. Ansonsten
gerne auch über dieses Formular oder direkt per %{feedback_mail}.</p>
mail_checkbox: >
Erlaube es uns, Dich per E-Mail (%{user_mail}) zu kontaktieren, falls es
Rückfragen zu Deinem Feedback gibt.
success_short: >
Feedback erfolgreich gesendet
success: >
Vielen Dank für Dein Feedback! Wir werden es in Kürze bearbeiten.
error_short: >
Fehler beim Senden des Feedbacks
error: >
Entschuldigung, leider ist beim Speichern ein Fehler aufgetreten.
Bitte speichere Dein Feedback händisch, indem Du es kopierst,
und versuche es später noch einmal.