-
-
Notifications
You must be signed in to change notification settings - Fork 529
Set up new page for case contacts table #6467
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
Changes from all commits
33a0050
33308a9
72d7c6d
007dbe1
8b2fa24
3cf13ba
b6185bb
ddc50ca
09475e3
a232762
706a1ea
32eb69d
6b080bb
bdde5f4
c6d4728
cc1a8f4
f3e49aa
f7b0bd2
7d23ef2
53a498a
92635a8
97b8597
aa7ec6f
f90061a
593c1a7
6531d8d
c5d1e2d
eed8539
0d4aeef
3dc8f06
31027c1
81aaf4b
5fededf
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 |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| class CaseContacts::CaseContactsNewDesignController < ApplicationController | ||
|
Collaborator
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. We will want to rename this someday :)
Contributor
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. Agreed :) the thinking was that this change would be a gradual roll out / feature flag, so have just gone with this name for the time being |
||
| include LoadsCaseContacts | ||
|
|
||
| def index | ||
| load_case_contacts | ||
| end | ||
|
|
||
| def datatable | ||
| authorize CaseContact | ||
| case_contacts = policy_scope(current_organization.case_contacts) | ||
| datatable = CaseContactDatatable.new case_contacts, params | ||
|
|
||
| render json: datatable | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| module LoadsCaseContacts | ||
|
Collaborator
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. nice reuse :) |
||
| extend ActiveSupport::Concern | ||
|
|
||
| private | ||
|
|
||
| def load_case_contacts | ||
| authorize CaseContact | ||
|
|
||
| @current_organization_groups = current_organization_groups | ||
|
|
||
| @filterrific = initialize_filterrific( | ||
| all_case_contacts, | ||
| params[:filterrific], | ||
| select_options: { | ||
| sorted_by: CaseContact.options_for_sorted_by | ||
| } | ||
| ) || return | ||
|
|
||
| @pagy, @filtered_case_contacts = pagy(@filterrific.find) | ||
| case_contacts = CaseContact.case_hash_from_cases(@filtered_case_contacts) | ||
| case_contacts = case_contacts.slice(*current_user.casa_cases.pluck(:id)) if current_user.volunteer? | ||
| case_contacts = case_contacts.select { |k, _v| k == params[:casa_case_id].to_i } if params[:casa_case_id].present? | ||
|
|
||
| @presenter = CaseContactPresenter.new(case_contacts) | ||
| end | ||
|
|
||
| def current_organization_groups | ||
| current_organization.contact_type_groups | ||
| .includes(:contact_types) | ||
| .joins(:contact_types) | ||
| .where(contact_types: {active: true}) | ||
| .uniq | ||
| end | ||
|
|
||
| def all_case_contacts | ||
| policy_scope(current_organization.case_contacts).preload( | ||
| :creator, | ||
| :followups, | ||
| contact_types: :contact_type_group, | ||
| contact_topic_answers: :contact_topic, | ||
| casa_case: :volunteers | ||
| ) | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,11 @@ const defineCaseContactsTable = function () { | |
| { | ||
| scrollX: true, | ||
| searching: false, | ||
| order: [[0, 'desc']] | ||
| order: [[2, 'desc']], | ||
|
Collaborator
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. will this affect existing functionality in addition to new functionality?
Contributor
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. I don't think it will affect existing functionality, as there isn't an existing case contacts table. Sorry it's been a few weeks since I was deeper into this but I believe that code block was left in from a similar table that used to exist. That old table can be seen in this PR: #1113, which is also the PR that this code block was added |
||
| columnDefs: [ | ||
| { type: 'date', targets: 2 }, | ||
| { orderable: false, targets: [0, 1, -1] } // disable sort on bell, chevron, vertical elipses menu | ||
| ] | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| <div class="title-wrapper pt-30"> | ||
| <div class="row align-items-center"> | ||
| <div class="title mb-30"> | ||
| <h1>Case Contacts</h1> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="card-style mb-30"> | ||
| <div class="table-wrapper"> | ||
| <table | ||
| id="case_contacts" | ||
| class="table" | ||
| data-source="<%= datatable_case_contacts_path format: :json %>"> | ||
| <thead> | ||
| <tr> | ||
| <th data-orderable="false"></th> | ||
| <th data-orderable="false"></th> | ||
| <th><h6>Date</h6></th> | ||
| <th><h6>Case</h6></th> | ||
| <th><h6>Relationship</h6></th> | ||
| <th><h6>Medium</h6></th> | ||
| <th><h6>Created By</h6></th> | ||
| <th><h6>Contacted</h6></th> | ||
| <th><h6>Topics</h6></th> | ||
| <th><h6>Draft</h6></th> | ||
| <th data-orderable="false"></th> | ||
| </tr> | ||
| <!-- end table row--> | ||
| </thead> | ||
| <tbody> | ||
| <% @presenter.case_contacts.each do |casa_case_id, case_contacts| %> | ||
| <% case_contacts.each do |case_contact| %> | ||
| <tr data-testid="case_contact-row"> | ||
| <td> | ||
| <i class='fas fa-bell'></i> | ||
| </td> | ||
| <td> | ||
| <i class="fa-solid fa-chevron-down"></i> | ||
| </td> | ||
| <td> | ||
| <%= I18n.l(case_contact[:occurred_at], format: :full) if case_contact[:occurred_at].present? %> | ||
| </td> | ||
| <td> | ||
| <%= @presenter.display_case_number(casa_case_id) %> | ||
| </td> | ||
| <td> | ||
| <%= case_contact.decorate.contact_types_comma_separated %> | ||
| </td> | ||
| <td> | ||
| <%= case_contact.medium_type&.capitalize %> | ||
| </td> | ||
| <td> | ||
| <% if policy(case_contact).edit? %> | ||
| <% if current_user.volunteer? %> | ||
| <%= case_contact.creator&.display_name %> | ||
| <% else %> | ||
| <% if case_contact.creator&.supervisor? %> | ||
| <%= link_to case_contact.creator&.display_name, edit_supervisor_path(case_contact.creator), data: { turbo: false } %> | ||
| <% elsif case_contact.creator&.casa_admin? %> | ||
| <%= link_to case_contact.creator&.display_name, edit_users_path, data: { turbo: false } %> | ||
| <% else %> | ||
| <%= link_to case_contact.creator&.display_name, edit_volunteer_path(case_contact.creator), data: { turbo: false } %> | ||
| <% end %> | ||
| <% end %> | ||
| <% else %> | ||
| <%= case_contact.creator&.display_name %> | ||
| <% end %> | ||
| </td> | ||
| <td> | ||
| <% if case_contact.contact_made %> | ||
| <i class="lni lni-checkmark-circle" style="color: green;"></i> | ||
|
||
| <% else %> | ||
| <i class="lni lni-cross-circle" style="color: orange;"></i> | ||
|
||
| <% end %> | ||
| <%= "(#{"%02d:%02d" % [case_contact.duration_minutes / 60, case_contact.duration_minutes % 60]})" if case_contact.duration_minutes %> | ||
| </td> | ||
| <td> | ||
| <%= case_contact.contact_topics.map(&:question).join(" | ") %> | ||
| </td> | ||
| <td> | ||
| <% if !case_contact.active? %> | ||
| <span class="badge badge-pill light-bg text-black" data-testid="draft-badge"> | ||
| Draft | ||
| </span> | ||
| <% end %> | ||
| </td> | ||
| <td> | ||
| <i class="fas fa-ellipsis-v"></i> | ||
| </td> | ||
| </tr> | ||
| <% end %> | ||
| <% end %> | ||
| </tbody> | ||
| </table> | ||
| <!-- end table --> | ||
| </div> | ||
| </div> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| require "rails_helper" | ||
|
|
||
| RSpec.describe LoadsCaseContacts do | ||
| let(:host) do | ||
| Class.new do | ||
| include LoadsCaseContacts | ||
| end | ||
| end | ||
|
|
||
| it "exists and defines private API" do | ||
| expect(described_class).to be_a(Module) | ||
| expect(host.private_instance_methods) | ||
| .to include(:load_case_contacts, :current_organization_groups, :all_case_contacts) | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| require "rails_helper" | ||
|
|
||
| RSpec.describe "/case_contacts_new_design", type: :request do | ||
| let(:organization) { create(:casa_org) } | ||
| let(:admin) { create(:casa_admin, casa_org: organization) } | ||
|
|
||
| before { sign_in admin } | ||
|
|
||
| describe "GET /index" do | ||
| subject(:request) do | ||
| get case_contacts_new_design_path | ||
|
|
||
| response | ||
| end | ||
|
|
||
| let!(:casa_case) { create(:casa_case, casa_org: organization) } | ||
| let!(:past_contact) { create(:case_contact, :active, casa_case: casa_case, occurred_at: 3.weeks.ago) } | ||
| let!(:recent_contact) { create(:case_contact, :active, casa_case: casa_case, occurred_at: 3.days.ago) } | ||
| let!(:draft_contact) { create(:case_contact, casa_case: casa_case, occurred_at: 5.days.ago, status: "started") } | ||
|
|
||
| it { is_expected.to have_http_status(:success) } | ||
|
|
||
| it "lists exactly two active contacts and one draft" do | ||
| doc = Nokogiri::HTML(request.body) | ||
| case_contact_rows = doc.css('[data-testid="case_contact-row"]') | ||
| expect(case_contact_rows.size).to eq(3) | ||
| end | ||
|
|
||
| it "shows the draft badge exactly once" do | ||
| doc = Nokogiri::HTML(request.body) | ||
| expect(doc.css('[data-testid="draft-badge"]').count).to eq(1) | ||
| end | ||
|
|
||
| it "orders contacts by occurred_at desc" do | ||
| body = request.body | ||
|
|
||
| recent_index = body.index(I18n.l(recent_contact.occurred_at, format: :full)) | ||
| past_index = body.index(I18n.l(past_contact.occurred_at, format: :full)) | ||
|
|
||
| expect(recent_index).to be < past_index | ||
| end | ||
| end | ||
| 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.
no more code coverage? I mean it does speed it up, but was this intended?
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.
ah I thought what I've done here is removing what we're doing with code climate, as per this slack thread: https://rubyforgood.slack.com/archives/CVB0QJGVD/p1757473365867509?thread_ts=1757356417.512309&cid=CVB0QJGVD
have I removed more than I was supposed to? 🫣