Skip to content

Commit

Permalink
Merge pull request rubyforgood#5564 from afogel/5309_update_contact_t…
Browse files Browse the repository at this point in the history
…ype_selection

5309 update contact type selection
  • Loading branch information
schoork authored May 18, 2024
2 parents 2cfec2f + e19b646 commit 582f436
Show file tree
Hide file tree
Showing 41 changed files with 302 additions and 290 deletions.
1 change: 0 additions & 1 deletion app/assets/fonts/fa-solid-900.ttf

This file was deleted.

Binary file added app/assets/fonts/fa-solid-900.ttf
Binary file not shown.
1 change: 0 additions & 1 deletion app/assets/fonts/fa-solid-900.woff2

This file was deleted.

Binary file added app/assets/fonts/fa-solid-900.woff2
Binary file not shown.
1 change: 0 additions & 1 deletion app/assets/webfonts/fa-solid-900.ttf

This file was deleted.

Binary file added app/assets/webfonts/fa-solid-900.ttf
Binary file not shown.
1 change: 0 additions & 1 deletion app/assets/webfonts/fa-solid-900.woff2

This file was deleted.

Binary file added app/assets/webfonts/fa-solid-900.woff2
Binary file not shown.
3 changes: 3 additions & 0 deletions app/components/form/multiple_select/item_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="badge rounded-pill bg-primary active px-3">
${escape(data.text)}
</div>
5 changes: 5 additions & 0 deletions app/components/form/multiple_select/item_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class Form::MultipleSelect::ItemComponent < ViewComponent::Base
strip_trailing_whitespace
end
23 changes: 23 additions & 0 deletions app/components/form/multiple_select_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="select-style-1 mr-8"
data-controller="multiple-select"
data-multiple-select-options-value="<%= @options %>"
data-multiple-select-selected-items-value="<%= @selected_items %>"
data-multiple-select-with-options-value="true">

<template data-multiple-select-target="option">
<div class="d-flex align-items-baseline">
<span class='mr-5'>DATA_LABEL</span>
<% if @render_option_subtext %>
<small class="fst-italic fw-lighter"><em>DATA_SUB_TEXT</em></small>
<% end %>
</div>
</template>

<template data-multiple-select-target="item">
<div class="badge rounded-pill bg-primary active px-3">DATA_LABEL</div>
</template>

<%= @form.select @name, {}, { multiple: true } , {
data: { "multiple-select-target": "select", } , class: "form-control-lg form-select form-select-lg input-group-lg"
} %>
</div>
11 changes: 11 additions & 0 deletions app/components/form/multiple_select_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class Form::MultipleSelectComponent < ViewComponent::Base
def initialize(form:, name:, options:, selected_items:, render_option_subtext: false)
@form = form
@name = name
@options = options.to_json
@selected_items = selected_items
@render_option_subtext = render_option_subtext
end
end
5 changes: 3 additions & 2 deletions app/controllers/casa_cases_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def casa_case_params
:date_in_care,
:court_report_due_date,
:empty_court_date,
casa_case_contact_types_attributes: [:contact_type_id],
contact_type_ids: [],
court_dates_attributes: [:date]
)
end
Expand All @@ -175,7 +175,8 @@ def casa_case_update_params
end

def set_contact_types
@contact_types = ContactType.for_organization(current_organization)
@contact_types = current_organization.contact_types
@selected_contact_type_ids = (!@casa_case.nil?) ? @casa_case.contact_type_ids : []
end

def case_contact_csv_name(case_contacts)
Expand Down
21 changes: 10 additions & 11 deletions app/controllers/case_contacts/form_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,13 @@ 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?

@selected_case_contact_types = @casa_cases.flat_map(&:contact_types)
@contact_types = ContactType.joins(:casa_case_contact_types).where(casa_case_contact_types: {casa_case_id: @casa_cases.pluck(:id)})
unless @contact_types.present?
@contact_types = current_organization.contact_types
end
@contact_types.order(name: :asc)

@current_organization_groups =
if @selected_case_contact_types.present?
@selected_case_contact_types.map(&:contact_type_group).uniq
else
current_organization.contact_types_by_group
end
@selected_contact_type_ids = @case_contact.contact_type_ids
end

def finish_editing
Expand Down Expand Up @@ -107,8 +106,8 @@ def create_additional_case_contacts(case_contact)
new_case_contact.status = "active"
new_case_contact.draft_case_ids = [casa_case_id]
new_case_contact.casa_case_id = casa_case_id
case_contact.case_contact_contact_type.each do |ccct|
new_case_contact.case_contact_contact_type.new(contact_type_id: ccct.contact_type_id)
case_contact.case_contact_contact_types.each do |ccct|
new_case_contact.case_contact_contact_types.new(contact_type_id: ccct.contact_type_id)
end
case_contact.additional_expenses.each do |ae|
new_case_contact.additional_expenses.new(
Expand All @@ -131,8 +130,8 @@ def case_contact_params
# Deletes the current associations (from the join table) only if the submitted form body has the parameters for
# the contact_type ids.
def remove_unwanted_contact_types
if params.dig(:case_contact, :case_contact_contact_type_attributes)
@case_contact.case_contact_contact_type.destroy_all
if params.dig(:case_contact, :contact_type_ids)
@case_contact.contact_types.clear
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/reimbursements_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def apply_occurred_at_filter(key, query)
def fetch_reimbursements
case_contacts = CaseContact.joins(:casa_case).includes(
:creator,
:case_contact_contact_type,
:case_contact_contact_types,
contact_types: [:contact_type_group]
).preload(:casa_case)
policy_scope(case_contacts, policy_scope_class: ReimbursementPolicy::Scope)
Expand Down
18 changes: 18 additions & 0 deletions app/decorators/contact_type_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class ContactTypeDecorator < Draper::Decorator
include ActionView::Helpers::DateHelper
delegate_all

def hash_for_multi_select_with_cases(casa_case_ids)
if casa_case_ids.nil?
casa_case_ids = []
end

{value: object.id, text: object.name, group: object.contact_type_group.name, subtext: last_time_used_with_cases(casa_case_ids)}
end

def last_time_used_with_cases(casa_case_ids)
last_contact = CaseContact.joins(:contact_types).where(casa_case_id: casa_case_ids, contact_types: {id: object.id}).order(occurred_at: :desc).first

last_contact.nil? ? "never" : "#{time_ago_in_words(last_contact.occurred_at)} ago"
end
end
19 changes: 0 additions & 19 deletions app/helpers/contact_types_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,4 @@ module ContactTypesHelper
def set_group_options
@group_options = ContactTypeGroup.for_organization(current_organization).collect { |group| [group.name, group.id] }
end

def time_ago_of_last_contact_made_of(contact_type_name, casa_case)
contact = last_contact_made_of(contact_type_name, casa_case)

return "never" if contact.nil?

"#{time_ago_in_words(contact.occurred_at)} ago"
end

def last_contact_made_of(contact_type_name, casa_case)
return unless casa_case

casa_case
.case_contacts
.joins(:contact_types)
.where(contact_types: {name: contact_type_name})
.order(occurred_at: :desc)
.first
end
end
54 changes: 53 additions & 1 deletion app/javascript/controllers/multiple_select_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,22 @@ import { Controller } from '@hotwired/stimulus'
import TomSelect from 'tom-select'

export default class extends Controller {
static targets = ['select']
static targets = ['select', 'option', 'item']
static values = {
options: Array,
selectedItems: Array,
withOptions: Boolean
}

connect () {
if (this.withOptionsValue) {
this.createMultiSelectWithOptionGroups()
} else {
this.createBasicMultiSelect()
}
}

createBasicMultiSelect () {
/* eslint-disable no-new */
new TomSelect(this.selectTarget, {
plugins: {
Expand All @@ -14,4 +27,43 @@ export default class extends Controller {
}
})
}

createMultiSelectWithOptionGroups () {
const optionTemplate = this.optionTarget.innerHTML
const itemTemplate = this.itemTarget.innerHTML

/* eslint-disable no-new */
new TomSelect(this.selectTarget, {
onItemAdd: function () {
this.setTextboxValue('')
this.refreshOptions()
},
plugins: {
remove_button: {
title: 'Remove this item',
className: 'btn text-white rounded-circle',
label: '<i class="lni lni-cross-circle"></i>'
},
checkbox_options: {
checkedClassNames: ['form-check-input'],
uncheckedClassNames: ['form-check-input']
}
},
options: this.optionsValue,
items: this.selectedItemsValue,
placeholder: 'Select or search for contacts',
hidePlaceholder: true,
searchField: ['text', 'group'],
render: {
option: function (data, escape) {
let html = optionTemplate.replace(/DATA_LABEL/g, escape(data.text))
html = html.replace(/DATA_SUB_TEXT/g, escape(data.subtext))
return html
},
item: function (data, escape) {
return itemTemplate.replace(/DATA_LABEL/g, escape(data.text))
}
}
})
}
}
7 changes: 4 additions & 3 deletions app/models/casa_case.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ 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
has_many :casa_case_contact_types
has_many :contact_types, through: :casa_case_contact_types, source: :contact_type
has_many :contact_types, through: :casa_case_contact_types
accepts_nested_attributes_for :casa_case_contact_types
validates_presence_of :casa_case_contact_types, message: ": At least one contact type must be selected",
if: :validate_contact_type
accepts_nested_attributes_for :court_dates
accepts_nested_attributes_for :volunteers

Expand Down Expand Up @@ -188,7 +189,7 @@ def update_cleaning_contact_types(args)
return false unless errors.messages.empty?

transaction do
casa_case_contact_types.destroy_all
contact_types.clear
update!(args)
rescue ActiveRecord::RecordInvalid
raise ActiveRecord::Rollback
Expand Down
6 changes: 6 additions & 0 deletions app/models/casa_org.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ def contact_types_by_group
contact_type_groups.joins(:contact_types).where(contact_types: {active: true}).alphabetically.uniq
end

# Returns contact types that are active and tied to the CasaOrg as a an array of hashes that can be used by the multiple select component
# @return [ActiveRecord::Relation<ContactType>]
def contact_types
ContactType.joins(:contact_type_group).where(active: true, contact_type_group: {casa_org: self}).order(:name)
end

# Given a specific date, returns the active mileage rate.
# If more than one mileage rate is active for a given date, assumes the rate for the most recent date takes precedence.
# For instance, given two mileage rates that are active, one set on January 1, 1970 and one set on January 3, 1970:
Expand Down
7 changes: 3 additions & 4 deletions app/models/case_contact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class CaseContact < ApplicationRecord
validates :casa_case_id, presence: true, if: :active?
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_many :case_contact_contact_types
has_many :contact_types, through: :case_contact_contact_types

has_many :additional_expenses
has_many :contact_topic_answers, dependent: :destroy
Expand All @@ -48,7 +48,6 @@ def active_or_expenses?
accepts_nested_attributes_for :additional_expenses, reject_if: :all_blank
validates_associated :additional_expenses

accepts_nested_attributes_for :case_contact_contact_type
accepts_nested_attributes_for :casa_case
accepts_nested_attributes_for :contact_topic_answers, update_only: true

Expand Down Expand Up @@ -164,7 +163,7 @@ def active_or_expenses?

def update_cleaning_contact_types(args)
transaction do
case_contact_contact_type.destroy_all
contact_types.clear
update(args)
end
end
Expand Down
3 changes: 3 additions & 0 deletions app/models/contact_type.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
class ContactType < ApplicationRecord
belongs_to :contact_type_group

has_many :casa_case_contact_types
has_many :casa_cases, through: :casa_case_contact_types

validates :name, presence: true, uniqueness: {scope: :contact_type_group_id,
message: "should be unique per contact type group"}

Expand Down
2 changes: 1 addition & 1 deletion app/policies/casa_case_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def permitted_attributes
common_attrs = [
:court_report_submitted,
:court_report_status,
casa_case_contact_types_attributes: [:contact_type_id]
contact_type_ids: []
]

case @user
Expand Down
2 changes: 1 addition & 1 deletion app/values/case_contact_parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ def initialize(params)
:notes,
:status,
:volunteer_address,
contact_type_ids: [],
draft_case_ids: [],
case_contact_contact_type_attributes: [:contact_type_id],
additional_expenses_attributes: %i[id other_expense_amount other_expenses_describe],
contact_topic_answers_attributes: %i[id value selected]
)
Expand Down
8 changes: 2 additions & 6 deletions app/views/casa_cases/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,8 @@
</div>
<% end %>
<% if Pundit.policy(current_user, casa_case).update_contact_types? %>
<%= render "case_contacts/form/contact_types",
form: form,
model: casa_case,
contact_type_groups: @contact_types.map(&:contact_type_group).sort_by(&:name).uniq,
selected_case_contact_types: [],
checkbox_tag_name: "casa_case[casa_case_contact_types_attributes][][contact_type_id]" %>
<label for="casa_case_contact_type_ids">Contact Types</label>
<%= render "case_contacts/form/contact_types", form: form, options: @contact_types, selected_items: @selected_contact_type_ids, casa_cases: [@casa_case] %>
<% end %>
<br>
<div class="actions-cc">
Expand Down
Loading

0 comments on commit 582f436

Please sign in to comment.