Skip to content

Commit

Permalink
Feature: Provide loading feedback when completing a lesson on a slow …
Browse files Browse the repository at this point in the history
…connection

Because:
- The complete button will appear to "hang" on slower connections.

This commit:
- Adds loading spinners to the complete button on lesson and course pages, that will only appear when toggling complete and the connection is slow.
- Bumps turbo-rails to latest patch version so we can use the :morph option when replacing content with turbo streams and avoid hover flashes on buttons as the content is replaced.
- Switch the complete button on course pages from links to buttons as they are not making GET requests.
- Removes some old Stimulus JS hooks for a complete controller that has been removed long ago.
  • Loading branch information
KevinMulhern committed Feb 21, 2025
1 parent 4869899 commit 7719e15
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 16 deletions.
9 changes: 4 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ GEM
netrc (0.11.0)
newrelic_rpm (9.16.0)
nio4r (2.7.3)
nokogiri (1.18.2)
nokogiri (1.18.3)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
noticed (1.6.3)
Expand Down Expand Up @@ -562,12 +562,11 @@ GEM
statsd-ruby (1.5.0)
stimulus-rails (1.3.3)
railties (>= 6.0.0)
stringio (3.1.2)
stringio (3.1.5)
thor (1.3.2)
timeout (0.4.3)
turbo-rails (2.0.6)
turbo-rails (2.0.11)
actionpack (>= 6.0.0)
activejob (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -599,7 +598,7 @@ GEM
xpath (3.2.0)
nokogiri (~> 1.8)
yard (0.9.37)
zeitwerk (2.7.1)
zeitwerk (2.7.2)

PLATFORMS
ruby
Expand Down
16 changes: 12 additions & 4 deletions app/components/complete/button_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@

<div id="complete-button" class="flex items-center justify-center">
<% if lesson.completed? %>
<%= button_to lesson_completion_path(lesson.id), form_class: 'w-full h-full', method: :delete, data: { test_id: 'complete-button' }, class: 'button button--primary h-[54px] sm:h-full w-full md:w-60 hover:bg-teal-700' do %>
<span class="flex items-center">
<%= button_to lesson_completion_path(lesson.id), form_class: 'w-full h-full group', method: :delete, data: { test_id: 'complete-button' }, class: 'button button--primary relative h-[54px] sm:h-full w-full md:w-60' do %>
<span class="flex items-center group-aria-busy:opacity-0 transition-opacity delay-100">
<%= inline_svg_tag 'icons/checkmark-circle-solid.svg', class: "h-6 pr-2 #{'pulse-once' if animate}", aria: true, title: 'check', desc: 'checkmark icon' %>
<span>Lesson Completed</span>
</span>

<div class="group-aria-busy:opacity-100 opacity-0 absolute inset-0 flex items-center justify-center transition-opacity delay-100">
<%= inline_svg_tag 'icons/spinner.svg', class: 'h-6 w-6 animate-spin text-white', aria: true %>
</div>
<% end %>
<% else %>
<%= button_to lesson_completion_path(lesson.id), form_class: 'w-full h-full', data: { test_id: 'complete-button'}, class: 'button button--primary h-[54px] sm:h-full w-full md:w-60 hover:bg-teal-700' do %>
<span> Mark Complete </span>
<%= button_to lesson_completion_path(lesson.id), form_class: 'w-full h-full group', data: { test_id: 'complete-button'}, class: 'button button--primary relative h-[54px] sm:h-full w-full md:w-60' do %>
<span class="group-aria-busy:opacity-0 transition-opacity delay-100"> Mark Complete </span>

<div class="group-aria-busy:opacity-100 opacity-0 absolute inset-0 flex items-center justify-center transition-opacity delay-100">
<%= inline_svg_tag 'icons/spinner.svg', class: 'h-6 w-6 animate-spin text-white', aria: true %>
</div>
<% end %>
<% end %>
</div>
23 changes: 18 additions & 5 deletions app/components/complete/icon_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
<%= tag.turbo_frame(id: dom_id(lesson, 'complete-button'), data: { controller: 'complete' }) do %>
<%= tag.div(id: dom_id(lesson, 'complete-button')) do %>
<% if lesson.completed? %>
<%= link_to lesson_completion_path(lesson.id, icon_only: true), data: { turbo_method: :delete, complete: @lesson.completed?, test_id: 'complete-button', action: 'click->complete#updateProgress' } do %>
<%= inline_svg_tag 'icons/checkmark-circle-solid.svg', class: "h-7 sm:h-8 text-teal-600 #{animation_class}", aria: true, title: 'check', desc: 'checkmark icon' %>
<%= button_to lesson_completion_path(lesson.id, icon_only: true), method: :delete, form_class: 'group', class: 'relative hover:cursor-pointer', data: { complete: @lesson.completed?, test_id: 'complete-button' } do %>
<span class="group-aria-busy:opacity-0 transition-opacity delay-100">
<%= inline_svg_tag 'icons/checkmark-circle-solid.svg', class: "h-7 sm:h-8 text-teal-600 #{animation_class}", aria: true, title: 'check', desc: 'checkmark icon' %>
</span>

<span class="group-aria-busy:opacity-100 opacity-0 absolute inset-0 flex items-center justify-center transition-opacity delay-100">
<%= inline_svg_tag 'icons/spinner.svg', class: 'h-6 sm:h-7 animate-spin text-gray-400', aria: true %>
</span>
<% end %>
<% else %>
<%= link_to lesson_completion_path(lesson.id, icon_only: true), data: { turbo_method: :post, complete: @lesson.completed?, test_id: 'complete-button', action: 'click->complete#updateProgress' } do %>
<%= inline_svg_tag 'icons/checkmark-circle-solid.svg', class: 'h-7 sm:h-8 text-gray-400 dark:text-gray-600', aria: true, title: 'check', desc: 'checkmark icon' %>
<%= button_to lesson_completion_path(lesson.id, icon_only: true), form_class: 'group', class: 'relative hover:cursor-pointer', data: { complete: @lesson.completed?, test_id: 'complete-button' } do %>

<span class="group-aria-busy:opacity-0 transition-opacity delay-100">
<%= inline_svg_tag 'icons/checkmark-circle-solid.svg', class: 'h-7 sm:h-8 text-gray-400 dark:text-gray-600', aria: true, title: 'check', desc: 'checkmark icon' %>
</span>

<span class="group-aria-busy:opacity-100 opacity-0 absolute inset-0 flex items-center justify-center transition-opacity delay-100">
<%= inline_svg_tag 'icons/spinner.svg', class: 'h-6 sm:h-7 animate-spin text-gray-400', aria: true %>
</span>
<% end %>
<% end %>
<% end %>
4 changes: 2 additions & 2 deletions app/views/lessons/completions/create.turbo_stream.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<% if params[:icon_only] %>
<%= turbo_stream.replace dom_id(@lesson, 'complete-button') do %>
<%= turbo_stream.replace dom_id(@lesson, 'complete-button'), method: :morph do %>
<% @lesson.completed? %>
<%= render Complete::IconComponent.new(lesson: @lesson, current_user:, animate: true) %>
<% end %>
<% else %>
<%= turbo_stream.replace 'complete-button' do %>
<%= turbo_stream.replace 'complete-button', method: :morph do %>
<%= render Complete::ButtonComponent.new(lesson: @lesson, animate: true) %>
<% end %>
<% end %>
Expand Down

0 comments on commit 7719e15

Please sign in to comment.