-
-
Notifications
You must be signed in to change notification settings - Fork 476
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
feat: [#5777] Add navigation buttons for steps in case contact form #5923
base: main
Are you sure you want to change the base?
feat: [#5777] Add navigation buttons for steps in case contact form #5923
Conversation
370cd63
to
8b76177
Compare
aria: { label: "Back step" }, | ||
disabled: !@nav_back do %> | ||
<% if @nav_back.present? %> | ||
<%= link_to @nav_back, title: "Back step", aria: { label: "Back step" } do %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chose to do a link within the button to have access to visible display of route/url on hover
@@ -0,0 +1,8 @@ | |||
# frozen_string_literal: true | |||
|
|||
class Form::StepNavigationComponent < ViewComponent::Base |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New component
<% if @navigable %> | ||
<%= render(@navigable) %> | ||
<% end %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional navigation buttons
<p class="col-auto"> | ||
<%= @steps_in_text %> | ||
</p> | ||
<div class="col"> | ||
<div class="progress"> | ||
<div class="progress-bar primary-bg" role="progressbar" style="width: <%= @progress %>%" aria-valuenow="<%= @progress %>" aria-valuemin="0" aria-valuemax="100"></div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No change - just indent
@@ -1,11 +1,12 @@ | |||
# frozen_string_literal: true | |||
|
|||
class Form::TitleComponent < ViewComponent::Base | |||
def initialize(title:, subtitle:, step: nil, total_steps: nil, notes: nil, autosave: false) | |||
def initialize(title:, subtitle:, step: nil, total_steps: nil, notes: nil, autosave: false, navigable: nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new optional param for navigating through form via buttons near progress bar
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ends up with suuuuper long call to render method. How about we just use a slot? https://viewcomponent.org/guide/slots.html#component-slots
@@ -9,29 +9,21 @@ class CaseContacts::FormController < ApplicationController | |||
|
|||
# wizard_path | |||
def show | |||
authorize @case_contact | |||
manage_form_step |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use helper for repeated behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving the authorize
call in the action is better. Whether current_user is allowed to show/edit/update records is unrelated to the form step (mostly), and I want to see that a record has been authorized for this action, in the common pattern. Moving it to set_case_contact
would make sense, but even that is too DRY for me, just leave it here.
render_wizard | ||
wizard_path | ||
end | ||
|
||
def update | ||
authorize @case_contact | ||
manage_form_step(step_navigation: true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use helper for repeated behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little confused what is happening here, seems like a lot of side effects are possible. also not clear how it interacts with some before_actions, which were already kind of a mess... does it make sense to check for steps in set_steps
for example?
else | ||
render_wizard @case_contact, {}, {case_contact_id: @case_contact.id} | ||
end | ||
manage_navigation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New navigation behavior necessary for validating then routing to appropriate step
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this because it doesn't look like a typical controller action, I'd like to see the response behavior in this method, instead of finding out what happens in manage_navigation...
What do you think of changing to smaller methods that are only responsible for setting variables, and leaving all the render/redirects logic in the action methods (show/update)?
@page = wizard_steps.index(step) + 1 | ||
@total_pages = steps.count |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This information is necessary for #update if you want to continue seeing the progress bar and navigation buttons after a form/validation error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't depend on any specific info, does it make more sense in a before action?
authorize @case_contact | ||
@page = wizard_steps.index(step) + 1 | ||
@total_pages = steps.count | ||
@nav_step = params[:nav_step] if step_navigation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New value
jump_to(@nav_step.split("/").last.to_sym) | ||
render_wizard @case_contact, {}, {case_contact_id: @case_contact.id} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used wicked jump_to
and then renders wizard to go to the specific step from navigation buttons
<div> | ||
<%= form_with(model: @case_contact, url: wizard_path(nil, case_contact_id: @case_contact.id), local: true, id: "casa-contact-form", class: "component-validated-form") do |form| %> | ||
<%= render(Form::TitleComponent.new(title: @case_contact.decorate.form_title, subtitle: "Contact details", step: @page, total_steps: @total_pages, navigable: Form::StepNavigationComponent.new(nav_back: nil, nav_next: next_wizard_path))) %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved render under form so submit
can catch
Added new parameter for navigable
|
||
require "rails_helper" | ||
|
||
RSpec.describe Form::StepNavigationComponent, type: :component do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing new component for ability to enable or disable the buttons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disabled makes sense.
Disabled makes sense.
Good call. Feel free to open an issue π
Good catch. I make a note and open an issue later. Or you can if you would like. And for context the previous design was multiple checkboxes but we got some feedback that there are too many (20+) in some orgs. |
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit confused. This controller was a mess before you got to it, so it makes all of this a little harder to reason through, not your fault! I also need to learn more about ViewComponents, but all of that side looks really good.
I think my major concerns are the indirection of manage_form_step
and the lack of clarity of what @nav_step
represents.
I may take a crack at refactoring this controller to clear it up and use more wizard helpers from the gem.
Let me know if you have any questions about my reviews!
# frozen_string_literal: true | ||
|
||
class Form::StepNavigationComponent < ViewComponent::Base | ||
def initialize(nav_back: nil, nav_next: nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def initialize(nav_back: nil, nav_next: nil) | |
def initialize(nav_back:, nav_next:) |
I don't think nil defaults make sense for most cases? This would allow passing nil in explicitly if needed, but remind devs they need to specify the actions if they've forgotten!
@@ -9,29 +9,21 @@ class CaseContacts::FormController < ApplicationController | |||
|
|||
# wizard_path | |||
def show | |||
authorize @case_contact | |||
manage_form_step |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving the authorize
call in the action is better. Whether current_user is allowed to show/edit/update records is unrelated to the form step (mostly), and I want to see that a record has been authorized for this action, in the common pattern. Moving it to set_case_contact
would make sense, but even that is too DRY for me, just leave it here.
<% if @nav_back.present? %> | ||
<%= link_to @nav_back, title: "Back step", aria: { label: "Back step" } do %> | ||
<i class="lni lni-chevron-left" alt="Chevron icon left"></i> | ||
<% end %> | ||
<% elsif %> | ||
<i class="lni lni-chevron-left" alt="Chevron icon left"></i> | ||
<% end %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
disabled attribute above should disable the link, if so this would do:
<% if @nav_back.present? %> | |
<%= link_to @nav_back, title: "Back step", aria: { label: "Back step" } do %> | |
<i class="lni lni-chevron-left" alt="Chevron icon left"></i> | |
<% end %> | |
<% elsif %> | |
<i class="lni lni-chevron-left" alt="Chevron icon left"></i> | |
<% end %> | |
<%= link_to "#{@nav_back || '#'}", title: "Back step", aria: { label: "Back step" } do %> | |
<i class="lni lni-chevron-left" alt="Chevron icon left"></i> | |
<% end %> |
value: @nav_back, | ||
class: "btn btn-link #{@nav_back.nil? ? 'disabled' : 'enabled'}", | ||
title: "Back step", | ||
aria: { label: "Back step" }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for included aria attributes!
aria: { label: "Back step" }, | |
aria: { label: "Back step", disabled: !@nav_back }, |
<%# Next navigation %> | ||
<%= button_tag type: :submit, | ||
name: :nav_step, | ||
value: @nav_forward, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value: @nav_forward, | |
value: @nav_next, |
right?
maybe back_path
next_path
are more descriptive names?
render_wizard | ||
wizard_path | ||
end | ||
|
||
def update | ||
authorize @case_contact | ||
manage_form_step(step_navigation: true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little confused what is happening here, seems like a lot of side effects are possible. also not clear how it interacts with some before_actions, which were already kind of a mess... does it make sense to check for steps in set_steps
for example?
else | ||
render_wizard @case_contact, {}, {case_contact_id: @case_contact.id} | ||
end | ||
manage_navigation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this because it doesn't look like a typical controller action, I'd like to see the response behavior in this method, instead of finding out what happens in manage_navigation...
What do you think of changing to smaller methods that are only responsible for setting variables, and leaving all the render/redirects logic in the action methods (show/update)?
@page = wizard_steps.index(step) + 1 | ||
@total_pages = steps.count |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't depend on any specific info, does it make more sense in a before action?
@@ -65,6 +64,17 @@ def get_cases_and_contact_types | |||
@selected_contact_type_ids = @case_contact.contact_type_ids | |||
end | |||
|
|||
def manage_navigation | |||
if @nav_step.present? | |||
jump_to(@nav_step.split("/").last.to_sym) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused what @nav_step is... why not make it correspond to a wizard step? Is it pulling double duty as a step and as a path?
This PR has been open for a long time without any pushes or comments! What's up? |
No longer applicable after #6048 ? |
What github issue is this PR for, if any?
Resolves #5777
π - This is my first contribution to this codebase, I am happy to make updates/change requests or discuss why I made certain decisions
β Open questions for a future PR:
What changed, and why?
How is this tested? (please write tests!) ππͺ
Note: if you see a flake in your test build in github actions, please post in slack #casa "Flaky test: " :) πͺ
Note: We love capybara tests! If you are writing both haml/js and ruby, please try to test your work with tests at every level including system tests like https://github.com/rubyforgood/casa/tree/main/spec/system
spec/components/form/step_navigation_component_spec.rb
Screenshots please :)
Run your local server and take a screenshot of your work! Try to include the URL of the page as well as the contents of the page.
Feelings gif (optional)
What gif best describes your feeling working on this issue? https://giphy.com/
How to embed: