-
-
Notifications
You must be signed in to change notification settings - Fork 503
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
[#4504] Add step-wise partner profile edit form #4766
[#4504] Add step-wise partner profile edit form #4766
Conversation
- Introduce feature flag to control rendering of new partner step forms. - Update controller edit and update actions to use feature flag. - Add accordion UI for expand/collapse of sections in step forms. - Build out partner step forms for each section. - Update partner profile validation to set errors at field level. - Add service to map profile field errors to sections they belong in. - Update accordion styles to render as open if they contain an error. - Replace bootstrap caret icons with saving indicator during form submission. - Add system tests for partner profile step-wise editing.
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.
Looks amazing! Please see a few questions/suggestions.
# sections_with_errors = service.call | ||
# # => ["media_information", "pick_up_person", "partner_settings"] | ||
# | ||
class SectionErrorService |
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.
Is this basically an overgrown hash lookup? I feel like this can be squished into a single class-level method.
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.
Updated with class method.
<div class="accordion mx-5 mt-3" id="accordionExample"> | ||
|
||
<%# Agency Information %> | ||
<div class="accordion-item"> | ||
<h2 class="accordion-header"> | ||
<button class="accordion-button <%= section_with_errors?('agency_information', @sections_with_errors) ? '' : 'collapsed' %>" type="button" data-bs-toggle="collapse" data-bs-target="#agency_information" aria-expanded="<%= section_with_errors?('agency_information', @sections_with_errors) %>" aria-controls="agency_information"> | ||
<div class='d-flex justify-content-between align-items-center w-100'> | ||
<div class='fs-4'> | ||
<i class="fa fa-edit mr-2"></i>Agency Information | ||
</div> | ||
</div> | ||
</button> | ||
</h2> | ||
<div id="agency_information" class="accordion-collapse collapse <%= section_with_errors?('agency_information', @sections_with_errors) ? 'show' : '' %>"> | ||
<div class="accordion-body"> | ||
<%= render 'partners/profiles/step/agency_information_form', f: f, partner: current_partner, profile: current_partner.profile %> | ||
</div> | ||
</div> | ||
</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.
Can this be extracted into a partial with relevant locals (name, partial ID etc.)? Partial renders can take blocks, so if you need specific HTML within the big skeleton you can do that if necessary.
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.
Extracted to partial.
end | ||
|
||
it "sets error at field level when feature flag enabled for partner step form" do | ||
allow(Flipper).to receive(:enabled?).with("partner_step_form").and_return(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.
Can you add the and_return(false)
to the previous method? It's always best to call out explicitly when you depend on a value to be true/false rather than relying on defaults.
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.
Done.
It's pretty nice! I need to think a bit about two things regarding a smooth passage through the process for the partners |
Hey @danielabar -- I would like to make the change so that we don't disable the submit for approval button on error. I'm still pondering whether we should only check the social media when submitting for approval -- I don't like that you can't save current progress without doing it, but there would be a side effect of essentially not checking that section properly as it goes through -- and I haven't landed on which is less desirable. |
@@ -0,0 +1,24 @@ | |||
<%# locals: (f:, partner:, section_id:, section_title:, icon_class:, partial_name:, sections_with_errors:) %> |
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.
🎉
Tech review passed. @cielf are there functional changes that have to happen? |
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 would like to make the change so that we don't disable the submit for approval button on error.
I also see, though, that on submit for approval with error, it's going to the view rather than returning to the edit -- it makes sense to me for it to return to the edit if there is an error.
@cielf To date, I've only made the technical changes on this PR, not any workflow changes, since earlier comment mentioned it requires further thought. The reason the Submit for Approval button is disabled on error state is from an earlier discussion on the issue. Don't recall which comment it was, but the idea was user shouldn't be able to Submit for Approval while form is in error. I could remove this logic if its no longer needed. When form initially loads, it is considered valid because the social media validation runs only on edit, and the profile is created in an invalid state. That's why you can initially Submit for Approval, even though its guaranteed to generate the social media error. Yes I see now that it goes to view rather than edit in this case, I'll look into that. To confirm, I'll make the following changes:
|
That sounds right, with the caveat that on most forms we disable the save /submit buttons during the round-trip to the server so that we don't get double-clicks. |
@cielf Forgot to mention - for Submit for Approval, there is additional logic to only display it if parter is Invited or Recertification Required, otherwise it doesn't render at all. Is that still needed or should the button be displayed at all times? Also fyi for this part "Submit for Approval + error -> return to edit", could be surprisingly thorny, requires modifications to the existing Approval Service which currently only seems to validate edit rules (i.e. only social media validation). I tried to change it (but should only change if step feature enabled), but strange things are happening. I still have to sort through it all but it will take more time. I think the issue is the Approval Service wasn't intended as a full update service, but now as of this feature, it needs to do two things: Update the profile, and then request approval. |
…h had modified the create service
An overall thought/possible future issue (don't want to scope creep this one): It seems like the complexity around social media validation and profile being invalid from the start is due to the existing PartnerCreateService which creates the profile in an invalid state: Partners::Profile.create!({
partner_id: @partner.id,
name: @partner.name,
enable_child_based_requests: organization.enable_child_based_requests,
enable_individual_requests: organization.enable_individual_requests,
enable_quantity_based_requests: organization.enable_quantity_based_requests
}) If the above was modified to add: no_social_media_presence: true Then the profile would be valid right from the start, and it wouldn't require If the intention of creating a profile invalid from the beginning was to remind the user that they should fill in at least one social media field, perhaps this could be handled as a gentle reminder with some JS in the edit form, rather than creating a validation error right from the start. |
"Then the profile would be valid right from the start, and it wouldn't require validate :check_social_media, on: :edit in the Profile model (could get rid of the on: :edit and other places like in Approval service where it needs to maintain awareness of edit state." We'd still need it because they could uncheck it, or am I missing something? I expect, though, that the intent was to make the partner think about it. Defaulting to none makes it easy to skip. Let me see if I can find the original ask. (or at least the issue for it) |
@cielf To clarify about the Submit for Approval. Currently it only validates the current state of the profile, but it's not a form submission, so if user made any other edits, they're not considered. Should it also be doing a save in case user made further edits, then clicked the Submit for Approval without first clicking Save Progress? i.e. it's really Save + Submit for Approval? Note that combining these two separate services (Update Profile, Submit for Approval) is complicated so it would be good to confirm that's really the requirement. @dorner Do you know if there's an example of a service that calls other services? I'm thinking of something like Organizer in the interactor gem, but for the custom service mixin that the existing services use. |
(Thinking) We have two ways we could go here. 1/ Save and submit for approval. 2/ Save and Review - taking them to the view screen, where they would then submit for approval (matching the current flow). Let me check in with one of our banks -- I believe we have a certain amount of partners not actually submitting for approval with the current model, but I want to confirm that. (Edit. The bank I was going to consult with doesn't have time today. Maybe tomorrow.) |
@danielabar Ok -- I've had a conversation with one of our main banks -- here's what we settled on: That gives the partners a final change to confirm that everything is right before submitting, but should also mitigate the problem of partners not actually submitting for approval. I can break out step 2 to be a separate issue if you want to keep it tight. Is that workable? |
@cielf I've changed:
I can look into the second part of the new requirement re: buttons at top and bottom of Partner Profile view. |
Observation, not sure if this is a bug or expected: I can only save one Additional Documents attachment. i.e. if I return to the edit view after adding a document and add another one, the new one replaces the old one. It seems to behave this way even with the feature flag disabled: Flipper.enable(:partner_step_form)
# OR
Flipper.disable(:partner_step_form) The has_many_attached :documents But when I attach a new one, there's an There may be an additional related bug that for the very first attachment, it doesn't get saved because the PurgeJob also runs. May require further investigation. |
@danielabar I know there are some problems around Additional Documents in the current incarnation. it's out of scope for this PR. I'll see if I can find the appropriate issue -- the PurgeJob information may be new to it. Oh -- you can add two documents at once -- just not add one, then add another one, but it's deleting the files if you edit again. Yup, that's no good. Confirmed - we have a "proto issue" for this (i.e. its in our backlog to be written up), i'll throw the info about PurgeJob into it. I think we might need a little design thought to make this right. |
@danielabar FYI, I'm probably not reviewing this today (severely underslept, and it needs a better brain than I have atm) |
I'm pretty happy with this. Do I think we might want a tweak or two once we see how it flies? Yes. Do I think it's good to go public? Also yes -- though we'll probably hold off enabling it until we have the equivalent page for the bank. |
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.
Looks good to me!
@cielf is this good to merge? |
@dorner Let me take a quick pass through with the flags off to make sure nothing broke. |
@danielabar: Your PR |
Resolves #4504
Description
This splits up the very long partner profile edit form into multiple collapsible sections, using the Bootstrap Accordion component. This project already uses Bootstrap so this does not introduce a new dependency.
The first attempt had a "Save and Next" button on each collapsible section, i.e. each one was a separate form that could be submitted individually. The original idea was to save one section and have the user returned to the edit view with the next section automatically opened for a kind of "guided" experience. It was also automatically saving work in progress edits as user collapsed/expanded sections. But this proved to be unworkable for a number of reasons. See #4504 comments for details.
So this solution simplifies things by only having a single form outside of the accordion section. User can click Save Progress which submits the entire form, or Submit for Approval. These action buttons appear both at the top and bottom of the accordion. If any validation errors occur, the user is returned to the edit view with all the sections that have error(s) expanded.
Type of change
New feature (non-breaking change which adds functionality)
How Has This Been Tested?
To exercise this feature, start by launching a Rails console
bin/rails c
and enable the new feature flag:Then with the Rails server running
bin/start
, navigate tohttp://localhost:3000
, login as an Org admin, create a new Partner Agency (eg:[email protected]
) and invite them. Then logout.A new browser tab should open with the invitation email sent to the new partner. Click on the accept invitation button in this email, and create a password for the new partner. Once logged in, click "Edit my Profile" from the left navigation. You should now see the new step-wise form.
Expand and collapse as many sections as you'd like, and click Save Progress as often as you'd like.
Notice that the bootstrap open/close caret icons change to the word "Saving..." when the form is being submitted. This is to prevent the user from opening further sections and trying to edit in the middle of an update.
To see what the form looks like with multiple validation errors, fill it out as follows, then click Save Progress.
[email protected], [email protected], [email protected], [email protected]
If the form renders with validation errors, then the Submit for Approval button should be disabled. Otherwise if partner is in Invited or Recertification status, then the Approval button is enabled. Otherwise the Approval button doesn't appear at all.
Also see system test for automated test:
spec/system/partners/profile_edit_system_spec.rb
Optionally, disable the feature flag in Rails console
Flipper.disable(:partner_step_form)
and run through the invitation flow again (or use the same partner you already created). In this case, it should behave exactly as it does currently with the very large form.Screenshots
Default rendering of step-wise edit form - all sections closed:
Multiple sections can be open/closed at once for editing:
Multiple sections open on validation errors: