Skip to content

Commit 701a228

Browse files
authored
Merge pull request #6467 from MikeRose151/mikerose151/6462-new-case-contact-table-page
Set up new page for case contacts table
2 parents 1258e01 + 5fededf commit 701a228

File tree

10 files changed

+234
-44
lines changed

10 files changed

+234
-44
lines changed

.github/workflows/rspec.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,15 @@ jobs:
6868
bundle exec rake db:schema:load
6969
bundle exec rails assets:precompile
7070
71-
- name: Run rspec and upload code coverage
71+
- name: Run rspec
7272
env:
7373
DATABASE_HOST: localhost
7474
POSTGRES_USER: postgres
7575
CASA_DATABASE_PASSWORD: password
7676
POSTGRES_HOST_AUTH_METHOD: trust
7777
RUN_SIMPLECOV: true
78-
CC_TEST_REPORTER_ID: 31464536e34ab26588cb951d0fa6b5898abdf401dbe912fd47274df298e432ac
7978
run: |
80-
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
81-
chmod +x ./cc-test-reporter
82-
./cc-test-reporter before-build
8379
RUBYOPT='-W:no-deprecated -W:no-experimental' bundle exec rspec
84-
./cc-test-reporter after-build --exit-code $?
8580
8681
- name: Archive selenium screenshots
8782
if: ${{ failure() }}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class CaseContacts::CaseContactsNewDesignController < ApplicationController
2+
include LoadsCaseContacts
3+
4+
def index
5+
load_case_contacts
6+
end
7+
8+
def datatable
9+
authorize CaseContact
10+
case_contacts = policy_scope(current_organization.case_contacts)
11+
datatable = CaseContactDatatable.new case_contacts, params
12+
13+
render json: datatable
14+
end
15+
end

app/controllers/case_contacts_controller.rb

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,15 @@
11
# frozen_string_literal: true
22

33
class CaseContactsController < ApplicationController
4+
include LoadsCaseContacts
5+
46
before_action :set_case_contact, only: %i[edit destroy]
57
before_action :set_contact_types, only: %i[new edit create]
68
before_action :require_organization!
79
after_action :verify_authorized, except: %i[leave]
810

911
def index
10-
authorize CaseContact
11-
12-
@current_organization_groups = current_organization_groups
13-
14-
@filterrific = initialize_filterrific(
15-
all_case_contacts,
16-
params[:filterrific],
17-
select_options: {
18-
sorted_by: CaseContact.options_for_sorted_by
19-
}
20-
) || return
21-
22-
@pagy, @filtered_case_contacts = pagy(@filterrific.find)
23-
case_contacts = CaseContact.case_hash_from_cases(@filtered_case_contacts)
24-
case_contacts = case_contacts.select { |k, _v| current_user.casa_cases.pluck(:id).include?(k) } if current_user.volunteer?
25-
case_contacts = case_contacts.select { |k, _v| k == params[:casa_case_id].to_i } if params[:casa_case_id].present?
26-
27-
@presenter = CaseContactPresenter.new(case_contacts)
12+
load_case_contacts
2813
end
2914

3015
def drafts
@@ -96,24 +81,6 @@ def set_contact_types
9681
@contact_types = ContactType.for_organization(current_organization)
9782
end
9883

99-
def current_organization_groups
100-
current_organization.contact_type_groups
101-
.includes(:contact_types)
102-
.joins(:contact_types)
103-
.where(contact_types: {active: true})
104-
.uniq
105-
end
106-
107-
def all_case_contacts
108-
policy_scope(current_organization.case_contacts).preload(
109-
:creator,
110-
:followups,
111-
contact_types: :contact_type_group,
112-
contact_topic_answers: :contact_topic,
113-
casa_case: :volunteers
114-
)
115-
end
116-
11784
def additional_expense_params
11885
@additional_expense_params ||= AdditionalExpenseParamsService.new(params).calculate
11986
end
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module LoadsCaseContacts
2+
extend ActiveSupport::Concern
3+
4+
private
5+
6+
def load_case_contacts
7+
authorize CaseContact
8+
9+
@current_organization_groups = current_organization_groups
10+
11+
@filterrific = initialize_filterrific(
12+
all_case_contacts,
13+
params[:filterrific],
14+
select_options: {
15+
sorted_by: CaseContact.options_for_sorted_by
16+
}
17+
) || return
18+
19+
@pagy, @filtered_case_contacts = pagy(@filterrific.find)
20+
case_contacts = CaseContact.case_hash_from_cases(@filtered_case_contacts)
21+
case_contacts = case_contacts.slice(*current_user.casa_cases.pluck(:id)) if current_user.volunteer?
22+
case_contacts = case_contacts.select { |k, _v| k == params[:casa_case_id].to_i } if params[:casa_case_id].present?
23+
24+
@presenter = CaseContactPresenter.new(case_contacts)
25+
end
26+
27+
def current_organization_groups
28+
current_organization.contact_type_groups
29+
.includes(:contact_types)
30+
.joins(:contact_types)
31+
.where(contact_types: {active: true})
32+
.uniq
33+
end
34+
35+
def all_case_contacts
36+
policy_scope(current_organization.case_contacts).preload(
37+
:creator,
38+
:followups,
39+
contact_types: :contact_type_group,
40+
contact_topic_answers: :contact_topic,
41+
casa_case: :volunteers
42+
)
43+
end
44+
end

app/decorators/case_contact_decorator.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ def contact_types
6161
end
6262
end
6363

64+
def contact_types_comma_separated
65+
if object.contact_types.any?
66+
object.contact_types&.map { |ct| ct.name }&.join(", ")
67+
else
68+
"No contact type specified"
69+
end
70+
end
71+
6472
def report_contact_types
6573
object.contact_types&.map { |ct| ct.name }&.join("|")
6674
end

app/javascript/src/dashboard.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ const defineCaseContactsTable = function () {
88
{
99
scrollX: true,
1010
searching: false,
11-
order: [[0, 'desc']]
11+
order: [[2, 'desc']],
12+
columnDefs: [
13+
{ type: 'date', targets: 2 },
14+
{ orderable: false, targets: [0, 1, -1] } // disable sort on bell, chevron, vertical elipses menu
15+
]
1216
}
1317
)
1418
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<div class="title-wrapper pt-30">
2+
<div class="row align-items-center">
3+
<div class="title mb-30">
4+
<h1>Case Contacts</h1>
5+
</div>
6+
</div>
7+
</div>
8+
9+
<div class="card-style mb-30">
10+
<div class="table-wrapper">
11+
<table
12+
id="case_contacts"
13+
class="table"
14+
data-source="<%= datatable_case_contacts_path format: :json %>">
15+
<thead>
16+
<tr>
17+
<th data-orderable="false"></th>
18+
<th data-orderable="false"></th>
19+
<th><h6>Date</h6></th>
20+
<th><h6>Case</h6></th>
21+
<th><h6>Relationship</h6></th>
22+
<th><h6>Medium</h6></th>
23+
<th><h6>Created By</h6></th>
24+
<th><h6>Contacted</h6></th>
25+
<th><h6>Topics</h6></th>
26+
<th><h6>Draft</h6></th>
27+
<th data-orderable="false"></th>
28+
</tr>
29+
<!-- end table row-->
30+
</thead>
31+
<tbody>
32+
<% @presenter.case_contacts.each do |casa_case_id, case_contacts| %>
33+
<% case_contacts.each do |case_contact| %>
34+
<tr data-testid="case_contact-row">
35+
<td>
36+
<i class='fas fa-bell'></i>
37+
</td>
38+
<td>
39+
<i class="fa-solid fa-chevron-down"></i>
40+
</td>
41+
<td>
42+
<%= I18n.l(case_contact[:occurred_at], format: :full) if case_contact[:occurred_at].present? %>
43+
</td>
44+
<td>
45+
<%= @presenter.display_case_number(casa_case_id) %>
46+
</td>
47+
<td>
48+
<%= case_contact.decorate.contact_types_comma_separated %>
49+
</td>
50+
<td>
51+
<%= case_contact.medium_type&.capitalize %>
52+
</td>
53+
<td>
54+
<% if policy(case_contact).edit? %>
55+
<% if current_user.volunteer? %>
56+
<%= case_contact.creator&.display_name %>
57+
<% else %>
58+
<% if case_contact.creator&.supervisor? %>
59+
<%= link_to case_contact.creator&.display_name, edit_supervisor_path(case_contact.creator), data: { turbo: false } %>
60+
<% elsif case_contact.creator&.casa_admin? %>
61+
<%= link_to case_contact.creator&.display_name, edit_users_path, data: { turbo: false } %>
62+
<% else %>
63+
<%= link_to case_contact.creator&.display_name, edit_volunteer_path(case_contact.creator), data: { turbo: false } %>
64+
<% end %>
65+
<% end %>
66+
<% else %>
67+
<%= case_contact.creator&.display_name %>
68+
<% end %>
69+
</td>
70+
<td>
71+
<% if case_contact.contact_made %>
72+
<i class="lni lni-checkmark-circle" style="color: green;"></i>
73+
<% else %>
74+
<i class="lni lni-cross-circle" style="color: orange;"></i>
75+
<% end %>
76+
<%= "(#{"%02d:%02d" % [case_contact.duration_minutes / 60, case_contact.duration_minutes % 60]})" if case_contact.duration_minutes %>
77+
</td>
78+
<td>
79+
<%= case_contact.contact_topics.map(&:question).join(" | ") %>
80+
</td>
81+
<td>
82+
<% if !case_contact.active? %>
83+
<span class="badge badge-pill light-bg text-black" data-testid="draft-badge">
84+
Draft
85+
</span>
86+
<% end %>
87+
</td>
88+
<td>
89+
<i class="fas fa-ellipsis-v"></i>
90+
</td>
91+
</tr>
92+
<% end %>
93+
<% end %>
94+
</tbody>
95+
</table>
96+
<!-- end table -->
97+
</div>
98+
</div>

config/routes.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@
9292

9393
get "case_contacts/leave", to: "case_contacts#leave", as: "leave_case_contacts_form"
9494
get "case_contacts/drafts", to: "case_contacts#drafts"
95-
resources :case_contacts, except: %i[create update show] do
95+
get "case_contacts/new_design", to: "case_contacts/case_contacts_new_design#index"
96+
resources :case_contacts, except: %i[create update show], concerns: %i[with_datatable] do
9697
member do
9798
post :restore
9899
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
require "rails_helper"
2+
3+
RSpec.describe LoadsCaseContacts do
4+
let(:host) do
5+
Class.new do
6+
include LoadsCaseContacts
7+
end
8+
end
9+
10+
it "exists and defines private API" do
11+
expect(described_class).to be_a(Module)
12+
expect(host.private_instance_methods)
13+
.to include(:load_case_contacts, :current_organization_groups, :all_case_contacts)
14+
end
15+
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
require "rails_helper"
2+
3+
RSpec.describe "/case_contacts_new_design", type: :request do
4+
let(:organization) { create(:casa_org) }
5+
let(:admin) { create(:casa_admin, casa_org: organization) }
6+
7+
before { sign_in admin }
8+
9+
describe "GET /index" do
10+
subject(:request) do
11+
get case_contacts_new_design_path
12+
13+
response
14+
end
15+
16+
let!(:casa_case) { create(:casa_case, casa_org: organization) }
17+
let!(:past_contact) { create(:case_contact, :active, casa_case: casa_case, occurred_at: 3.weeks.ago) }
18+
let!(:recent_contact) { create(:case_contact, :active, casa_case: casa_case, occurred_at: 3.days.ago) }
19+
let!(:draft_contact) { create(:case_contact, casa_case: casa_case, occurred_at: 5.days.ago, status: "started") }
20+
21+
it { is_expected.to have_http_status(:success) }
22+
23+
it "lists exactly two active contacts and one draft" do
24+
doc = Nokogiri::HTML(request.body)
25+
case_contact_rows = doc.css('[data-testid="case_contact-row"]')
26+
expect(case_contact_rows.size).to eq(3)
27+
end
28+
29+
it "shows the draft badge exactly once" do
30+
doc = Nokogiri::HTML(request.body)
31+
expect(doc.css('[data-testid="draft-badge"]').count).to eq(1)
32+
end
33+
34+
it "orders contacts by occurred_at desc" do
35+
body = request.body
36+
37+
recent_index = body.index(I18n.l(recent_contact.occurred_at, format: :full))
38+
past_index = body.index(I18n.l(past_contact.occurred_at, format: :full))
39+
40+
expect(recent_index).to be < past_index
41+
end
42+
end
43+
end

0 commit comments

Comments
 (0)