Skip to content

Commit de5e668

Browse files
authored
Merge pull request #6215 from alex-yi37/issue-6187-admin-new-case-contacts
Issue 6187 admin new case contacts
2 parents 0810494 + a6fab58 commit de5e668

File tree

6 files changed

+110
-26
lines changed

6 files changed

+110
-26
lines changed

app/components/form/multiple_select_component.html.erb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
data-multiple-select-options-value="<%= @options %>"
44
data-multiple-select-selected-items-value="<%= @selected_items %>"
55
data-multiple-select-placeholder-term-value="<%= @placeholder_term %>"
6+
data-multiple-select-show-all-option-value="<%= @show_all_option %>"
67
data-multiple-select-with-options-value="true">
78

89
<template data-multiple-select-target="option">
@@ -18,6 +19,19 @@
1819
<div class="badge rounded-pill bg-primary active px-3">DATA_LABEL</div>
1920
</template>
2021

22+
<%# not needed, but want to be explicit when including this markup %>
23+
<% if @show_all_option %>
24+
<template data-multiple-select-target="hiddenItem">
25+
<div class="d-none"></div>
26+
</template>
27+
28+
<template data-multiple-select-target="selectAllOption">
29+
<div class="d-flex align-items-baseline">
30+
<span data-test="select-all-input" class='mr-5'>DATA_LABEL</span>
31+
</div>
32+
</template>
33+
<% end %>
34+
2135
<%= @form.select @name, {}, { multiple: true } , {
2236
data: { "multiple-select-target": "select", } , class: "form-control-lg form-select form-select-lg input-group-lg"
2337
} %>
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# frozen_string_literal: true
22

33
class Form::MultipleSelectComponent < ViewComponent::Base
4-
def initialize(form:, name:, options:, selected_items:, render_option_subtext: false, placeholder_term: nil)
4+
def initialize(form:, name:, options:, selected_items:, render_option_subtext: false, placeholder_term: nil, show_all_option: false)
55
@form = form
66
@name = name
77
@options = options.to_json
88
@selected_items = selected_items
99
@render_option_subtext = render_option_subtext
1010
@placeholder_term = placeholder_term
11+
@show_all_option = show_all_option
1112
end
1213
end

app/javascript/controllers/multiple_select_controller.js

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ import { Controller } from '@hotwired/stimulus'
22
import TomSelect from 'tom-select'
33

44
export default class extends Controller {
5-
static targets = ['select', 'option', 'item']
5+
static targets = ['select', 'option', 'item', 'hiddenItem', 'selectAllOption']
66
static values = {
77
options: Array,
88
selectedItems: Array,
99
withOptions: Boolean,
1010
placeholderTerm: {
1111
type: String,
1212
default: 'contact(s)'
13-
}
13+
},
14+
showAllOption: Boolean
1415
}
1516

1617
connect () {
@@ -37,11 +38,44 @@ export default class extends Controller {
3738
const itemTemplate = this.itemTarget.innerHTML
3839
const placeholder = `Select or search ${this.placeholderTermValue}`
3940

41+
const showAllOptionCheck = this.showAllOptionValue
42+
const hiddenItemTemplate = showAllOptionCheck && this.hiddenItemTarget && this.hiddenItemTarget.innerHTML
43+
const showAllOptionTemplate = showAllOptionCheck && this.selectAllOptionTarget && this.selectAllOptionTarget.innerHTML
44+
45+
// orderedOptionVals is of type (" " | number)[] - the " " could appear
46+
// because using it as the value for the select/unselect all option
47+
let orderedOptionVals = this.optionsValue.map(opt => opt.value)
48+
if (showAllOptionCheck) {
49+
// using " " as value instead of "" bc tom-select doesn't init the "" in the item list
50+
orderedOptionVals = [' '].concat(orderedOptionVals)
51+
}
52+
53+
const hasInitialItems = Array.isArray(this.selectedItemsValue) && this.selectedItemsValue.length
54+
// initItems: number[], possibly empty
55+
let initItems = this.selectedItemsValue
56+
if (showAllOptionCheck) {
57+
const emptyItem = [' ']
58+
initItems = hasInitialItems ? emptyItem.concat(this.selectedItemsValue) : orderedOptionVals
59+
}
60+
61+
const dropdownOptions = showAllOptionCheck
62+
? [{ text: 'Select/Unselect all', subtext: '', value: ' ', group: '' }].concat(this.optionsValue)
63+
: this.optionsValue
64+
4065
/* eslint-disable no-new */
4166
new TomSelect(this.selectTarget, {
42-
onItemAdd: function () {
67+
onItemRemove: function (value) {
68+
if (value === ' ') {
69+
this.clear()
70+
}
71+
},
72+
onItemAdd: function (value) {
4373
this.setTextboxValue('')
4474
this.refreshOptions()
75+
76+
if (value === ' ') {
77+
this.addItems(orderedOptionVals)
78+
}
4579
},
4680
plugins: {
4781
remove_button: {
@@ -54,19 +88,25 @@ export default class extends Controller {
5488
uncheckedClassNames: ['form-check-input']
5589
}
5690
},
57-
options: this.optionsValue,
58-
items: this.selectedItemsValue,
91+
options: dropdownOptions,
92+
items: initItems,
5993
placeholder,
6094
hidePlaceholder: true,
6195
searchField: ['text', 'group'],
6296
render: {
6397
option: function (data, escape) {
64-
let html = optionTemplate.replace(/DATA_LABEL/g, escape(data.text))
65-
html = html.replace(/DATA_SUB_TEXT/g, escape(data.subtext))
98+
let html
99+
100+
if (showAllOptionCheck && data && data.value === ' ') {
101+
html = showAllOptionTemplate.replace(/DATA_LABEL/g, escape(data.text))
102+
} else {
103+
html = optionTemplate.replace(/DATA_LABEL/g, escape(data.text))
104+
html = html.replace(/DATA_SUB_TEXT/g, escape(data.subtext))
105+
}
66106
return html
67107
},
68108
item: function (data, escape) {
69-
return itemTemplate.replace(/DATA_LABEL/g, escape(data.text))
109+
return showAllOptionCheck && data.value === ' ' ? hiddenItemTemplate : itemTemplate.replace(/DATA_LABEL/g, escape(data.text))
70110
}
71111
}
72112
})

app/views/case_contacts/form/_contact_types.html.erb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
name: :contact_type_ids,
66
options: options.decorate.map { |ct| ct.hash_for_multi_select_with_cases(casa_cases&.pluck(:id)) },
77
selected_items: selected_items,
8-
render_option_subtext: true
8+
render_option_subtext: true,
9+
show_all_option: true,
910
)) %>
1011
</div>

spec/system/casa_cases/edit_spec.rb

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
let(:contact_type_group) { create(:contact_type_group, casa_org: organization) }
1313
let(:other_org_contact_type_group) { create(:contact_type_group, casa_org: other_organization) }
1414
let!(:contact_type) { create(:contact_type, contact_type_group: contact_type_group) }
15+
let!(:another_contact_type) { create(:contact_type, contact_type_group: contact_type_group) }
16+
let!(:saved_case_contact_type) { create(:casa_case_contact_type, casa_case: casa_case, contact_type: contact_type) }
1517
let!(:other_org_contact_type) { create(:contact_type, contact_type_group: other_org_contact_type_group) }
1618
let!(:siblings_casa_cases) do
1719
create(:casa_case, :with_one_court_order, casa_org: organization)
@@ -41,6 +43,20 @@
4143
select "Submitted", from: "casa_case_court_report_status"
4244

4345
find(".ts-control").click
46+
47+
ts_checkboxes = page.all(".ts-dropdown-content input")
48+
49+
select_all_el = page.find("span[data-test=select-all-input]")
50+
# uncheck all contact type options
51+
select_all_el.click
52+
ts_checkboxes.each do |el|
53+
expect(el).not_to be_checked
54+
end
55+
# check all contact type options
56+
select_all_el.click
57+
expect(ts_checkboxes).to all(be_checked)
58+
59+
# unselect contact_type from dropdown
4460
find("span", text: contact_type.name).click
4561

4662
page.find('button[data-action="court-order-form#add"]').click
@@ -57,7 +73,7 @@
5773
expect(page).to have_text("Court Order Text One")
5874
expect(page).not_to have_text("Deactivate Case")
5975

60-
expect(casa_case.contact_types).to eq [contact_type]
76+
expect(casa_case.contact_types).to eq [another_contact_type]
6177
has_checked_field? contact_type.name
6278
end
6379

@@ -222,9 +238,19 @@
222238
expect(page).to have_text("Set Implementation Status")
223239

224240
find(".ts-control").click
225-
find("span", text: "Youth").click
226-
227-
within ".actions-cc" do
241+
ts_checkboxes = page.all(".ts-dropdown-content input")
242+
243+
select_all_el = page.find("span[data-test=select-all-input]")
244+
# uncheck all contact type options
245+
select_all_el.click
246+
ts_checkboxes.each do |el|
247+
expect(el).not_to be_checked
248+
end
249+
# check all contact type options
250+
select_all_el.click
251+
expect(ts_checkboxes).to all(be_checked)
252+
# since all contact type options checked, don't need to select one
253+
within ".top-page-actions" do
228254
click_on "Update CASA Case"
229255
end
230256
has_checked_field? "Youth"

spec/system/casa_cases/new_spec.rb

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,17 @@
3333
select "Submitted", from: "casa_case_court_report_status"
3434

3535
find(".ts-control").click
36-
find("span", text: contact_type.name).click
37-
find(".ts-control").click
36+
37+
ts_checkboxes = page.all(".ts-dropdown-content input")
38+
select_all_el = page.find("span[data-test=select-all-input]")
39+
# uncheck all contact type options
40+
select_all_el.click
41+
ts_checkboxes.each do |el|
42+
expect(el).not_to be_checked
43+
end
44+
# check all contact type options
45+
select_all_el.click
46+
expect(ts_checkboxes).to all(be_checked)
3847

3948
select "Test User", from: "casa_case[case_assignments_attributes][0][volunteer_id]"
4049

@@ -57,7 +66,7 @@
5766
casa_org = build(:casa_org)
5867
admin = create(:casa_admin, casa_org: casa_org)
5968
contact_type_group = create(:contact_type_group, casa_org: casa_org)
60-
contact_type = create(:contact_type, contact_type_group: contact_type_group)
69+
create(:contact_type, contact_type_group: contact_type_group)
6170
case_number = "12345"
6271

6372
sign_in admin
@@ -69,9 +78,6 @@
6978
select "March", from: "casa_case_birth_month_year_youth_2i"
7079
select five_years, from: "casa_case_birth_month_year_youth_1i"
7180

72-
find(".ts-control").click
73-
find("span", text: contact_type.name).click
74-
7581
within ".actions-cc" do
7682
click_on "Create CASA Case"
7783
end
@@ -109,7 +115,7 @@
109115
casa_org = build(:casa_org)
110116
admin = create(:casa_admin, casa_org: casa_org)
111117
contact_type_group = create(:contact_type_group, casa_org: casa_org)
112-
contact_type = create(:contact_type, contact_type_group: contact_type_group)
118+
create(:contact_type, contact_type_group: contact_type_group)
113119
case_number = "12345"
114120

115121
sign_in admin
@@ -121,9 +127,6 @@
121127
select five_years, from: "casa_case_birth_month_year_youth_1i"
122128
check "casa_case_empty_court_date"
123129

124-
find(".ts-control").click
125-
find("span", text: contact_type.name).click
126-
127130
within ".actions-cc" do
128131
click_on "Create CASA Case"
129132
end
@@ -152,8 +155,7 @@
152155
select "March", from: "casa_case_birth_month_year_youth_2i"
153156
select five_years, from: "casa_case_birth_month_year_youth_1i"
154157

155-
find(".ts-control").click
156-
find("span", text: contact_type.name).click
158+
# 2/14/2025 - by default, all contact types are selected on page load so don't need to manually select
157159

158160
within ".actions-cc" do
159161
click_on "Create CASA Case"

0 commit comments

Comments
 (0)