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

5309 update contact type selection #5564

Merged
merged 23 commits into from
May 18, 2024

Conversation

afogel
Copy link
Contributor

@afogel afogel commented Mar 9, 2024

What github issue is this PR for, if any?

Resolves #5309

What changed, and why?

This code change an existing code dependency library to create a better UX when selecting contact types.

To accomplish this, I refactored an existing stimulus controller to allow for the instantiation a multi-select with option groups. The tomselect library provides all the requested functionality, though there are a few differences in UX from the figma spec (e.g., no checkboxes, once options are selected, they disappear from the dropdown options).

Though not explicitly requested in spec, the solution also provides highlighting to improve UX of search functionality.

This change also removes some custom JS (related to checkboxes) and view logic that seems unnecessary, given that this partial is only used in this form.

How will this affect user permissions?

  • Volunteer permissions: N/A
  • Supervisor permissions: N/A
  • Admin permissions: N/A

This code change is expressly focused on view logic.

How is this tested? (please write tests!) 💖💪

Since this is a change to view logic, the best testing is either manual QA or e2e tests.

User story for manual QA:
As a volunteer, I should be able to arrive on this form page.
Selecting the dropdown should allow me to see different options, grouped by contact group type.
I should be able to select and remove multiple contact types using the mouse.
I should be able to select and remove multiple contact types using the keyboard.
When I submit this stage of the contact wizard, I should be able to return and see that the contact types have persisted (those I selected are still there).

Screenshots please :)

Screenshot 2024-03-09 at 10 09 18 Screenshot 2024-03-09 at 10 09 30

Screenshot 2024-03-09 at 10 09 30

Feedback please? (optional)

Well scoped ticket, fun to work on. Well done!

@github-actions github-actions bot added javascript for use by Github Labeler to mark pull requests that update Javascript code erb labels Mar 9, 2024
},
item: function(data, escape) {
return `
<div class="badge rounded-pill primary-bg py-2 px-3 active form-check-label">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

custom badges of selected items

},
optgroup_header: function(data, escape) {
return `
<span class='d-flex optgroup-header'>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure that highlighting doesn't mess up spacing of optgroup header

option: function(data, escape) {
return `
<div class='d-flex gap-1'>
<span class='d-flex gap-1'>${escape(data.label)}</span>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b/c of a quirk w/ the highlighting implementation in tomselect, using gap-1 and d-flex to keep everything on the same line. My preference exists for maintaining spaces and adding one extra space to the right than removing spaces altogether.

I think this implementation is good enough, though if we choose to remove highlighting altogether, we would likely avoid this being a problem.

remove_button: {
title: 'Remove this item',
className: 'text-primary p-1 mx-2 deactive-bg rounded-circle',
label: `<i class="lni lni-close p-1"></i>`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

custom remove button, as per figma mockups

<div class="form-check checkbox-style mb-1">
<%=
contact_type_exists = default_checked ? true : @casa_case.contact_types.include?(contact_type)
contact_type_exists = false unless controller.controller_name == 'casa_cases'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm lacking the context here for what this view logic is doing, but when I grepped the code base, I couldn't find other circumstances in which this partial is reused, so I'm removing.

makes me feel icky to have a call based on controller name in my view, anyway 😬

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

following up -- I think this may be the context in which an admin is working with the file. this may require additional investigation.

</div>
</div>
<p>Choose from the available options below by searching or selecting from the dropdown menu.</p>
<% last_case = @casa_cases.sort_by(&:created_at).last %>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like there was already a convention of storing some of the view logic state in the partial before, so I stuck with it for speed. Would be happy to extract to a presenter or a decorator in order to encapsulate viewlogic here.

</div>
<script type="text/javascript">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dead code once we remove checkboxes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is still dead code.

@github-actions github-actions bot added ruby Pull requests that update Ruby code Tests! 🎉💖👏 labels Mar 9, 2024
@@ -51,7 +51,7 @@ def update

def get_cases_and_contact_types
@casa_cases = policy_scope(current_organization.casa_cases)
@casa_cases = @casa_cases.where(id: @case_contact.casa_case_id) if @case_contact.active?
@casa_cases = @casa_cases.find(@case_contact.casa_case_id) if @case_contact.active?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is wrong, will revert

@github-actions github-actions bot added the dependencies Pull requests that update a dependency file label Apr 6, 2024
@afogel afogel changed the base branch from main to lint April 6, 2024 13:46
@afogel afogel changed the base branch from lint to main April 6, 2024 13:47
@bcastillo32
Copy link
Collaborator

Hi @afogel thanks again for jamming on this. Are you still working on this or does it just need review? Happy to push that along if so :)

@afogel
Copy link
Contributor Author

afogel commented Apr 7, 2024

Hi @afogel thanks again for jamming on this. Are you still working on this or does it just need review? Happy to push that along if so :)

this still needs work wrt to tests. I've had less bandwidth over the last bit of time, but the core of the functionality is there.
Most of the remaining painful here is e2e test that are breaking b/c the functionality is no longer selected w/ checkboxes. Moreover, since I'm using tomselect (already in the existing codebase, but doesn't seem to be in e2e tests), the existing testing framework needs some custom helpers to modify the existing tests. In the event someone else can take this over, I'd be fine with it.

I do think there are some scenarios that may be caught by tests which aren't simply visual changes. That said, it's hard to gauge which are which as since most of the breaking tests are just brittle tests that don't catch real bugs.
If my schedule opens up a bit more, I'll try to take it on, but if not, I'd be fine with the rest of the work being taken over.

@bcastillo32
Copy link
Collaborator

Hi @afogel thanks again for jamming on this. Are you still working on this or does it just need review? Happy to push that along if so :)

this still needs work wrt to tests. I've had less bandwidth over the last bit of time, but the core of the functionality is there. Most of the remaining painful here is e2e test that are breaking b/c the functionality is no longer selected w/ checkboxes. Moreover, since I'm using tomselect (already in the existing codebase, but doesn't seem to be in e2e tests), the existing testing framework needs some custom helpers to modify the existing tests. In the event someone else can take this over, I'd be fine with it.

I do think there are some scenarios that may be caught by tests which aren't simply visual changes. That said, it's hard to gauge which are which as since most of the breaking tests are just brittle tests that don't catch real bugs. If my schedule opens up a bit more, I'll try to take it on, but if not, I'd be fine with the rest of the work being taken over.

thank you @afogel I'll see what I can do about getting help with tests :)

@@ -52,7 +52,6 @@ def user_org_learning_topic_enable?
# id :bigint not null, primary key
# duration_hours :integer not null
# duration_minutes :integer not null
# learning_type :integer default(5)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strange removal?

Copy link
Collaborator

@compwron compwron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's fix the tests and prove that it works :)

@afogel
Copy link
Contributor Author

afogel commented Apr 10, 2024

Let's fix the tests and prove that it works :)

I couldn't agree more that the tests should be fixed (though that's not what proves that it works 🙃 ); I'm just limited in the amount of time I have rn. I'll try to turn back to it, but may not be able to finish pushing it over the finish line for a bit.

Copy link
Collaborator

@elasticspoon elasticspoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems solid overall, that being said I don't have that much context. Most of my feedback is minor questions / suggestions so don't mind that there is a lot of it. 🙂

Only parts I would consider blockers would be the highlight styling, potentially unused code and whether or not contact types are required.

@@ -27,7 +27,7 @@ class CaseContact < ApplicationRecord
validate :draft_case_ids_not_empty, if: :active_or_details?

has_many :case_contact_contact_type
has_many :contact_types, through: :case_contact_contact_type, source: :contact_type
has_and_belongs_to_many :contact_types, join_table: "case_contact_contact_types"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure that habtm is more correct than many through? Cause the CaseContactContactType model exists.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general has_many, :through is preferred over HABTM.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverting

Comment on lines 98 to 101
def contact_types_as_hash_map
ContactType.joins(:contact_type_group).where(active: true, contact_type_group: {casa_org: self}).order(:name).map(&:hash_for_multiple_select)
end

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit of a nit:
I feel like having hash_for_multiple_select in a different class makes this harder to understand. I'm not sure what the shape of the data is and I need to find where that method lives to find out.

contact_types = query stuff
contact_types.map { |type| {hash: stuff}}

I think doing all the work in this method is easier to follow especially since hash_for_multiple_select isnt used anywhere else.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add some Rdoc here, but the hash_for_multiple_select is being used twice now and it acts upon the ContactType.

db/schema.rb Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes seem unrelated to PR?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this getting used?

Comment on lines 7 to 14
<template data-multiple-select-target="option">
<div class='d-flex gap-1'>
<span class='d-flex gap-1'>DATA_LABEL</span>
<% if @option_sub_text %>
<span class="fst-italic text-muted">DATA_SUB_TEXT</span>
<% end %>
</div>
</template>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, this look real funky with highlighting. You can do something like :

#parent_element_whatever_it_is {
  div {
    white-space: break-space;
  }
  
  span + span {
    margin-inline-start: 1.5rem;
  }
}

and get rid of the gap classes and it will get rid of the weird spacing around the highlights.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this getting used?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The select menu looks great! Two things worth considering (I don't have enough background on the issue to tell how much they matter):

  1. You got rid of the optgroups with group headings (CASA, family, etc). I think that makes it a bit unclear that you can use them to filter the search. like if I search for "CASA" its not clear to me why I get the results I do:
    image

I don't know if there were technical reasons for this but I think the optgroups were nice from a UX perspective.

  1. No clue if this is an improvement from a UX perspective but maybe the input should clear on selecting an item. That way if you do something like "father enter mother enter" you don't have to backspace out what you inputted.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Was part of the original ticket/Figma
  2. I like that, will investigate

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That totally fair, kinda assumed it was from original screenshots. My thoughts were that since they want "A user should be able to fuzzy search based on “Contact Type Groups” (see “Editing CASA Organization page in admin portal), ie searching “Family” would still display “Grandparent”

I think a user isn't gonna realize they can search by group without some sort of indication of it. Idk if that makes sense.

@@ -43,10 +43,8 @@ class CasaCase < ApplicationRecord
belongs_to :judge, optional: true
belongs_to :casa_org
validates :birth_month_year_youth, presence: true
validates_presence_of :casa_case_contact_types, message: ": At least one contact type must be selected", if: :validate_contact_type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the form
image it seems like either the validation should remain or that field should not marked with a *.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved back to has_many and re-added validation

Comment on lines 111 to 112
<!-- TODO - need to refactor this -->
<%= render "case_contacts/form/contact_types", form: form, options: @contact_type_options, selected_items: @contact_type_selected_items %>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a general comment. But like what even is the functionality on this page?
image

Selecting stuff there doesn't seem to affect future case contacts? What does contact_type selection even do there?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on talk to Linda. This should restrict the contact types available for a case. It currently does not seem to be working, if I pick a type of "CASA" for a case, then try to make a case contact for that case I see all the options available.

Also pretty sure this is related to a validation but I can update the case to not have no contact type set.

I also noticed that you can circumvent contact type restrictions but that is unrelated to the PR. #5605

@name = name
@options = options.to_json
@selected_items = selected_items
@option_sub_text = option_sub_text
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: maybe render_option_subtext? I initially thought this would be the text itself (I think the text is in the options hash right?).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it

@afogel afogel changed the base branch from main to lint April 12, 2024 09:00
@afogel afogel changed the base branch from lint to main April 12, 2024 09:00
@afogel
Copy link
Contributor Author

afogel commented Apr 12, 2024

Seems solid overall, that being said I don't have that much context. Most of my feedback is minor questions / suggestions so don't mind that there is a lot of it. 🙂

Only parts I would consider blockers would be the highlight styling, potentially unused code and whether or not contact types are required.

Awesome, appreciate the thorough review! I'll try to poke around over the next bit of time and respond. I've honestly lost much of the context since I worked on the ticket a month ago, and I was also lacking some of the context around use cases, so it'll take a bit of time to go through, but I appreciate the feedback!

@compwron
Copy link
Collaborator

compwron commented Apr 12, 2024

I am hearing worries from stakeholders Sarah Bosken and Jocie that this will remove the feature of "show how long since a particular contact type has been contacted" which they very much value. Because there should only people on the list who the volunteer is supposed to be contacting (because of the feature that lets us hide non-relevant parties)
Screenshot 2024-04-12 at 11 10 11 AM

Comment on lines 111 to 112
<!-- TODO - need to refactor this -->
<%= render "case_contacts/form/contact_types", form: form, options: @contact_type_options, selected_items: @contact_type_selected_items %>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on talk to Linda. This should restrict the contact types available for a case. It currently does not seem to be working, if I pick a type of "CASA" for a case, then try to make a case contact for that case I see all the options available.

Also pretty sure this is related to a validation but I can update the case to not have no contact type set.

I also noticed that you can circumvent contact type restrictions but that is unrelated to the PR. #5605

@schoork
Copy link
Collaborator

schoork commented Apr 12, 2024

I am hearing worries from stakeholders Sarah Bosken and Jocie that this will remove the feature of "show how long since a particular contact type has been contacted" which they very much value. Because there should only people on the list who the volunteer is supposed to be contacting (because of the feature that lets us hide non-relevant parties) Screenshot 2024-04-12 at 11 10 11 AM

Brandon reached out to some stakeholders (not sure who) at my request to determine what this functionality should look like. Some ways they might want it are harder than others. There are two pieces of functionality that are not related but might seem related to them:

  1. The time since the contact type has been used (ie. about a week)
  2. The showing of only those contact types tied to certain cases

1 is what Brandon was checking on. I think Mallory, Brandon, and I might have a discussion about the best user experience here. There's a thread in the Slack about it so far.

2 I initially pulled out, not quite understanding the context. Yuri rightfully pointed out after discussing with Linda that this is a much used feature. I will be putting it back in. Here's the Slack thread for that convo.

@schoork
Copy link
Collaborator

schoork commented Apr 12, 2024

Seems solid overall, that being said I don't have that much context. Most of my feedback is minor questions / suggestions so don't mind that there is a lot of it. 🙂
Only parts I would consider blockers would be the highlight styling, potentially unused code and whether or not contact types are required.

Awesome, appreciate the thorough review! I'll try to poke around over the next bit of time and respond. I've honestly lost much of the context since I worked on the ticket a month ago, and I was also lacking some of the context around use cases, so it'll take a bit of time to go through, but I appreciate the feedback!

It really was some cool work you did here @afogel. I did some extra stuff to try to get this over the line quickly, since you were busy. Very good bones here.

@afogel
Copy link
Contributor Author

afogel commented Apr 14, 2024

awesome, thanks! So sorry I'm strapped for time now 😬

@bcastillo32
Copy link
Collaborator

@afogel @schoork @elasticspoon - not sure if I ever gave the feedback here but volunteers wanted to keep the logic as is for the "show how long since a particular contact type has been contacted". Is this info what is needed to get this wrapped up? Sorry I have been so busy lately.

@schoork
Copy link
Collaborator

schoork commented May 17, 2024

@afogel @schoork @elasticspoon - not sure if I ever gave the feedback here but volunteers wanted to keep the logic as is for the "show how long since a particular contact type has been contacted". Is this info what is needed to get this wrapped up? Sorry I have been so busy lately.

Sorry, also been busy. Will take a look but pretty sure that's how I implemented it after some initial feedback

@schoork
Copy link
Collaborator

schoork commented May 18, 2024

@bcastillo32 This has the requested functionality.
Screenshot 2024-05-18 at 11 32 44 AM

@schoork schoork merged commit 582f436 into rubyforgood:main May 18, 2024
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependencies Pull requests that update a dependency file erb javascript for use by Github Labeler to mark pull requests that update Javascript code ruby Pull requests that update Ruby code Tests! 🎉💖👏
Projects
None yet
Development

Successfully merging this pull request may close these issues.

update "2. Select All Contact Types" section on Case Contact Form with Dropdown menu and new styling/copy
6 participants