-
-
Notifications
You must be signed in to change notification settings - Fork 528
feat(#6502): Filter for new case contact table #6942
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,13 @@ const defineCaseContactsTable = function () { | |
| ajax: { | ||
| url: $('table#case_contacts').data('source'), | ||
| type: 'POST', | ||
| data: function (d) { | ||
| const filters = collectCaseContactFilters() | ||
| if (Object.keys(filters).length > 0) { | ||
| d.additional_filters = filters | ||
| } | ||
| return d | ||
| }, | ||
| error: function (xhr, error, code) { | ||
| console.error('DataTable error:', error, code) | ||
| }, | ||
|
|
@@ -248,6 +255,43 @@ const defineCaseContactsTable = function () { | |
| success: () => table.ajax.reload(null, false) | ||
| }) | ||
| }) | ||
|
|
||
| $('#cc-filter-toggle').on('click', function () { | ||
| $('#cc-filter-panel').toggle() | ||
| }) | ||
|
|
||
| $('#cc-filter-apply').on('click', function () { | ||
| table.ajax.reload(null, false) | ||
| $('#cc-filter-panel').hide() | ||
| }) | ||
|
|
||
| $('#cc-filter-reset').on('click', function () { | ||
| $('#cc-filter-occurred-starting-at, #cc-filter-occurred-ending-at').val('') | ||
| $('#cc-filter-medium, #cc-filter-contact-made').val('') | ||
| $('.cc-filter-casa-case, .cc-filter-contact-type, #cc-filter-no-drafts').prop('checked', false) | ||
| table.ajax.reload(null, false) | ||
| }) | ||
| } | ||
|
|
||
| function collectCaseContactFilters () { | ||
| const filters = {} | ||
| const startDate = $('#cc-filter-occurred-starting-at').val() | ||
| const endDate = $('#cc-filter-occurred-ending-at').val() | ||
| const casaIds = $('.cc-filter-casa-case:checked').map((_, el) => el.value).get() | ||
| const contactTypeIds = $('.cc-filter-contact-type:checked').map((_, el) => el.value).get() | ||
| const medium = $('#cc-filter-medium').val() | ||
| const contactMade = $('#cc-filter-contact-made').val() | ||
| const noDrafts = $('#cc-filter-no-drafts').is(':checked') | ||
|
|
||
| if (startDate) filters.occurred_starting_at = startDate | ||
| if (endDate) filters.occurred_ending_at = endDate | ||
| if (casaIds.length > 0) filters.casa_case_ids = casaIds | ||
| if (contactTypeIds.length > 0) filters.contact_type_ids = contactTypeIds | ||
| if (medium) filters.contact_medium = medium | ||
| if (contactMade !== '') filters.contact_made = contactMade | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if (noDrafts) filters.no_drafts = '1' | ||
|
|
||
| return filters | ||
| } | ||
|
|
||
| $(() => { // JQuery's callback for the DOM loading | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,105 @@ | ||
| <div class="title-wrapper pt-30"> | ||
| <div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-30"> | ||
| <h1>Case Contacts</h1> | ||
| <h1 class="mb-20">Case Contacts</h1> | ||
|
|
||
| <div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3" id="cc-filter-toolbar"> | ||
| <button type="button" id="cc-filter-toggle" class="main-btn secondary-btn btn-sm btn-hover"> | ||
| <i class="lni lni-funnel mr-5" aria-hidden="true"></i> | ||
| Filter | ||
| </button> | ||
|
Comment on lines
+4
to
+8
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the color of this button be the same as the color of the New Case Contact button? The Figma has it as white with a dark blue icon and dark blue text. As coded:
In the Figma:
Here's my rationale for the current color: "New Case Contact" is the primary action on the page. The Filter button is a utility action, used less frequently and by a subset of users. Giving the primary action a filled, prominent style and the secondary action a less prominent style guides the eye to the most important action without hiding the secondary one. If they were the same colour, the two buttons would compete for attention equally, which would be visually noisy and would undermine the distinction between "the thing you're here to do" and "a tool to help you find things."
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is what it would look like with the Screen.Recording.2026-05-08.at.13.26.41.mov |
||
|
|
||
| <%= link_to new_case_contact_path, class: "main-btn primary-btn btn-sm btn-hover" do %> | ||
| <i class="lni lni-plus mr-10" aria-hidden="true"></i> | ||
| New Case Contact | ||
| <% end %> | ||
| </div> | ||
|
|
||
| <div id="cc-filter-panel" class="card-style mb-3" style="display: none;"> | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inline style rather than a CSS class is intentional here. The inline style takes effect immediately as the browser parses the HTML, before any JavaScript loads. A CSS class would leave a window where the panel is briefly visible while the JS bundle is still loading, causing a flash of unwanted content on page load. |
||
| <div class="card-content"> | ||
| <div class="row mb-3"> | ||
| <div class="col-12"><h5>Date of contact</h5></div> | ||
| <div class="col-sm-6 input-style-1"> | ||
| <label for="cc-filter-occurred-starting-at">Starting from</label> | ||
| <input type="date" id="cc-filter-occurred-starting-at" class="form-control" autocomplete="off"> | ||
| </div> | ||
| <div class="col-sm-6 input-style-1"> | ||
| <label for="cc-filter-occurred-ending-at">Ending at</label> | ||
| <input type="date" id="cc-filter-occurred-ending-at" class="form-control" autocomplete="off"> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="row mb-3"> | ||
| <div class="col-12"><h5>Case</h5></div> | ||
| <% current_organization.casa_cases.order(:case_number).each do |casa_case| %> | ||
| <div class="col-md-4"> | ||
| <div class="form-check"> | ||
| <input type="checkbox" | ||
| class="form-check-input cc-filter-casa-case" | ||
| id="cc-filter-case-<%= casa_case.id %>" | ||
| value="<%= casa_case.id %>"> | ||
| <label class="form-check-label" for="cc-filter-case-<%= casa_case.id %>"> | ||
| <%= casa_case.case_number %> | ||
| </label> | ||
| </div> | ||
| </div> | ||
| <% end %> | ||
| </div> | ||
|
|
||
| <div class="row mb-3"> | ||
| <div class="col-12"><h5>Relationship</h5></div> | ||
| <% @current_organization_groups.each do |group| %> | ||
| <div class="col-md-4"> | ||
| <h6><%= group.name %></h6> | ||
| <% group.contact_types.each do |contact_type| %> | ||
| <div class="form-check"> | ||
| <input type="checkbox" | ||
| class="form-check-input cc-filter-contact-type" | ||
| id="cc-filter-ct-<%= contact_type.id %>" | ||
| value="<%= contact_type.id %>"> | ||
| <label class="form-check-label" for="cc-filter-ct-<%= contact_type.id %>"> | ||
| <%= contact_type.name %> | ||
| </label> | ||
| </div> | ||
| <% end %> | ||
| </div> | ||
| <% end %> | ||
| </div> | ||
|
|
||
| <div class="row mb-3"> | ||
| <div class="col-md-4 select-style-1"> | ||
| <label for="cc-filter-medium">Medium</label> | ||
| <div class="select-position"> | ||
| <select id="cc-filter-medium" class="form-select"> | ||
| <option value="">Display all</option> | ||
| <% CaseContact::CONTACT_MEDIUMS.each do |medium| %> | ||
| <option value="<%= medium %>"><%= medium.titleize %></option> | ||
| <% end %> | ||
| </select> | ||
| </div> | ||
| </div> | ||
| <div class="col-md-4 select-style-1"> | ||
| <label for="cc-filter-contact-made">Contacted</label> | ||
| <div class="select-position"> | ||
| <select id="cc-filter-contact-made" class="form-select"> | ||
| <option value="">Display all</option> | ||
| <option value="true">Reached</option> | ||
| <option value="false">Not Reached</option> | ||
| </select> | ||
| </div> | ||
| </div> | ||
| <div class="col-md-4 d-flex align-items-end pb-2"> | ||
| <div class="form-check"> | ||
| <input type="checkbox" class="form-check-input" id="cc-filter-no-drafts"> | ||
| <label class="form-check-label" for="cc-filter-no-drafts">Hide drafts</label> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="d-flex gap-2"> | ||
| <button type="button" id="cc-filter-apply" class="main-btn primary-btn btn-sm btn-hover">Apply Filters</button> | ||
| <button type="button" id="cc-filter-reset" class="main-btn dark-btn-outline btn-sm btn-hover">Reset</button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="card-style mb-30"> | ||
|
|
||


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.
A new method rather than extending
search_filterbecause the two are fundamentally different in structure.search_filterbuilds a raw SQLWHEREclause that ORs conditions together against a single free-text string β merging AND-logic filter conditions into it would break both features.apply_additional_filterschains named ActiveRecord scopes instead, each adding an ANDedWHEREcondition, which is exactly the semantics filters need.