Module: ContactsHelper

Defined in:
app/helpers/contacts_helper.rb

Overview

View helper: contacts.

Instance Method Summary collapse

Instance Method Details

#build_contact_party_hash(contact) ⇒ Hash{String => Contact, Hash}

Builds a party-select hash keyed by display name for the contact and its customer.

Parameters:

  • contact (Contact)

    the contact to build the party options for

Returns:

  • (Hash{String => Contact, Hash})

    display name mapped to the contact,
    plus a { party:, collapsed: } hash for the customer when present



23
24
25
26
27
28
# File 'app/helpers/contacts_helper.rb', line 23

def build_contact_party_hash(contact)
  parties_hash = {}
  parties_hash[contact.full_name.to_s] = contact
  parties_hash["#{contact.customer.full_name} (Customer)"] = { party: contact.customer, collapsed: false } if contact.customer
  parties_hash
end

#contact_command_options(contact) ⇒ Array<String, Hash>

Builds the dropdown command options (edit, enrich, restore, delete/deactivate)
for a contact row or detail page.

Logic Details

The delete/deactivate entry degrades to plain explanatory text when the
contact participates in an open support case. The confirm message and label
vary with ok_to_delete? and support-case participation. The Lead
Enrichment entry is manager-only while the feature is in pilot.

Parameters:

  • contact (Contact)

    the contact the commands operate on

Returns:

  • (Array<String, Hash>)

    HTML link strings and/or disabled-item hashes



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'app/helpers/contacts_helper.rb', line 89

def contact_command_options(contact)
  [].tap do |links|
    links << link_to(fa_icon('wrench', text: 'Edit'), edit_contact_path(contact))
    # Lead Enrichment is manager-only while it's in pilot — same gate
    # as the Customer-side entry in customers_helper.rb.
    if contact.enrichable_via_research? && &.is_manager?
      links << link_to(fa_icon('wand-magic-sparkles', text: 'Enrich'),
                       new_contact_party_research_run_path(contact),
                       data: { turbo_frame: '_top' })
    end
    links << link_to('Restore', restore_contact_path(contact), data: { turbo_method: :put }) if contact.customer && contact.inactive?
    links << if contact.open_support_case_participant?
               { content: 'Cannot be deactivated because it is a participant of an open support case.', class: 'dropdown-item-text text-body-secondary' }
             else
               confirm_message = if contact.ok_to_delete?
                                   'Are you sure? This action will permanently delete the contact.'
                                 elsif contact.support_case_participant?
                                   'This contact is a support case participant and cannot be deleted. It will be marked as inactive and the contact login (if any) will be removed.'
                                 else
                                   'Are you sure? This action will mark the contact as inactive and remove the contact login (if any). It will also unassign any open opportunities, orders or services assigned to this contact.'
                                 end
               link_to(fa_icon('trash', text: (contact.ok_to_delete? ? 'Delete' : 'Deactivate')),
                       contact_path(contact),
                       data: { turbo_confirm: confirm_message, turbo_method: :delete })
             end
  end
end

Renders a link to the contact's visits index showing the visit count and
how long ago the most recent visit started.

Parameters:

  • contact (Contact)

    the contact with multiple visits

  • most_recent (Visit)

    the contact's most recent visit

Returns:

  • (String)

    HTML link markup

See Also:



63
64
65
66
# File 'app/helpers/contacts_helper.rb', line 63

def contact_multiple_visits_link(contact, most_recent)
  display_text = "#{contact.visits.size} visit(s) (Last was #{time_ago_in_words(most_recent.started_at)} ago)"
  link_to(fa_icon('magnifying-glass-plus', text: display_text), contact_visits_path(contact))
end

#contact_quick_info(contact) ⇒ Array<String>

Collects quick-info icons for a contact, currently the customer's primary sales rep.

Parameters:

  • contact (Contact)

    the contact whose customer is inspected

Returns:

  • (Array<String>)

    HTML-safe icon strings for display



34
35
36
37
38
# File 'app/helpers/contacts_helper.rb', line 34

def contact_quick_info(contact)
  info = []
  info << fa_icon('user-tie', text: contact.customer.primary_sales_rep.name_and_extension, title: 'Primary Sales Rep') if contact.customer.respond_to?(:primary_sales_rep) && contact.customer.primary_sales_rep
  info
end

Renders a link to a single visit showing how long ago it started.

Parameters:

  • most_recent (Visit)

    the contact's only visit

Returns:

  • (String)

    HTML link markup

See Also:



73
74
75
76
# File 'app/helpers/contacts_helper.rb', line 73

def contact_single_visit_link(most_recent)
  display_text = "#{time_ago_in_words(most_recent.started_at)} ago"
  link_to(fa_icon('magnifying-glass-plus', text: display_text), visit_path(most_recent))
end

#contact_tab_options(contact = @contact) ⇒ Hash{Symbol => Hash}

Builds the tab configuration hash for the contact detail page.

Logic Details

Supplier contacts omit the opportunities, topics, training, certifications,
orders, and merge tabs; contacts without a customer omit those customer-scoped
tabs as well.

Parameters:

  • contact (Contact) (defaults to: @contact)

    the contact whose tabs are configured (defaults to @contact)

Returns:

  • (Hash{Symbol => Hash})

    tab name mapped to its options
    (:remote_href, plus :counter / :counter_html / :title where applicable)



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'app/helpers/contacts_helper.rb', line 127

def contact_tab_options(contact = @contact)
  hsh = {}
  hsh[:main] = { remote_href: tab_main_contact_path(contact) }
  hsh[:contacts] = { remote_href: tab_contacts_contact_path(contact) }
  hsh[:activities] = { counter: contact.open_activities_counter, remote_href: contact_activities_path(contact, selected_activity: params[:selected_activity]) }
  hsh[:communications] = { remote_href: contact_communications_path(contact) }
  hsh[:sms] = { remote_href: contact_sms_messages_path(contact), counter: contact.sms_messages.where(unread: true).size }

  unless contact.supplier_contact?
    hsh[:opportunities] = { counter: contact.all_opportunities.open_opportunities.size,
                            remote_href: contact_opportunities_path(contact) }
  end
  hsh[:tickets] = { title: 'Tickets',
                    counter_html: tech_counter_badge(contact.support_cases),
                    remote_href: tab_tickets_contact_path(contact) }
  hsh[:attachments] = { counter: contact.all_uploads.size, remote_href: contact_uploads_path(contact) }
  if contact.customer && !contact.supplier_contact?
    hsh[:topics] = { remote_href: tab_profiling_contact_path(contact) }
    hsh[:training] = { remote_href: tab_training_contact_path(contact) }
    hsh[:certifications] = { remote_href: tab_certifications_contact_path(contact) }
    hsh[:orders] = { counter: contact.orders.non_credit.in_progress.size, remote_href: contact_orders_path(contact) }
    hsh[:orders_spiff] = { remote_href: tab_orders_spiff_contact_path(contact) }
    hsh[:merge] = { remote_href: tab_merge_contact_path(contact) }
  end
  hsh[:digital_assets] = { counter: contact.digital_assets.size, remote_href: tab_digital_assets_contact_path(contact) }
  hsh
end

Renders a link to the contact's most recent visit, or a summary link when
the contact has multiple visits.

Parameters:

  • contact (Contact)

    the contact whose visits are linked

Returns:

  • (String)

    HTML link markup, or '-' when the contact has no visits



45
46
47
48
49
50
51
52
53
54
# File 'app/helpers/contacts_helper.rb', line 45

def contact_visits_link(contact)
  most_recent = contact.visits.order(:started_at).reverse_order.first
  return '-' unless most_recent

  if contact.visits.size > 1
    contact_multiple_visits_link(contact, most_recent)
  else
    contact_single_visit_link(most_recent)
  end
end

#render_contact_info_bar(contact, role: nil, note: nil) ⇒ String?

Renders an info bar under a contact's name with customer, project role,
job title, and note icons.

Parameters:

  • contact (Contact)

    the contact to render the info bar for

  • role (String, nil) (defaults to: nil)

    optional project role to display

  • note (String, nil) (defaults to: nil)

    optional note to display

Returns:

  • (String, nil)

    HTML markup for the info bar, or nil when there is
    nothing to show



163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'app/helpers/contacts_helper.rb', line 163

def render_contact_info_bar(contact, role: nil, note: nil)
  list = []
  list << fa_icon('building', text: contact.customer.full_name) if contact.is_a?(Contact) && contact.customer

  list << fa_icon('diagram-project', text: role, title: 'Project Role') if role.present?

  list << fa_icon('user-tag', text: contact.job_title, title: 'Job Title') if contact.job_title.present? && contact.job_title != role

  list << fa_icon('note-sticky', text: note) if note.present?

  return if list.blank?

  (:ul, list.map { |e| (:span, e, class: 'text-body-secondary me-2') }.join.html_safe, class: 'list-unstyled')
end

#setup_contact(contact) ⇒ Contact

Ensures a contact has a built (unsaved) contact point for each standard
category so forms can render fields for all of them.

Parameters:

  • contact (Contact)

    the contact to prepare for form rendering

Returns:

  • (Contact)

    the same contact, with missing contact points built



9
10
11
12
13
14
15
16
# File 'app/helpers/contacts_helper.rb', line 9

def setup_contact(contact)
  contact.tap do |c|
    c.contact_points.build({ category: ContactPoint::PHONE }) if c.contact_points.find_by(category: ContactPoint::PHONE).nil?
    c.contact_points.build({ category: ContactPoint::CELL }) if c.contact_points.find_by(category: ContactPoint::CELL).nil?
    c.contact_points.build({ category: ContactPoint::FAX }) if c.contact_points.find_by(category: ContactPoint::FAX).nil?
    c.contact_points.build({ category: ContactPoint::EMAIL }) if c.contact_points.find_by(category: ContactPoint::EMAIL).nil?
  end
end