Module: PhonesHelper

Defined in:
app/helpers/phones_helper.rb

Overview

View helper: phones.

Constant Summary collapse

PRESENCE_DOT_CLASSES =

Presence dot classes.

%w[
  presence-dot-available
  presence-dot-available-home-office
  presence-dot-available-non-queue
  presence-dot-dnd
  presence-dot-away
  presence-dot-unknown
].freeze
QUEUE_STRATEGY_LABELS =

Human labels for Switchvox queue ring strategies (the PBX sends the
machine tokens).

{
  'ringall' => 'Ring All',
  'rrmemory' => 'Round Robin',
  'leastrecent' => 'Least Recently Called',
  'fewestcalls' => 'Fewest Calls',
  'random' => 'Random',
  'inorder' => 'In Order'
}.freeze

Instance Method Summary collapse

Instance Method Details

#combined_presence(presence, sub_presence = nil) ⇒ Object



139
140
141
142
143
144
# File 'app/helpers/phones_helper.rb', line 139

def combined_presence(presence, sub_presence = nil)
  # {'_forwarding' if sub_presence.present?}"
  cp = [presence]
  cp << sub_presence if sub_presence
  cp.join('-').parameterize
end

#icon_for_presence(status, sub_presence = nil) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'app/helpers/phones_helper.rb', line 79

def icon_for_presence(status, sub_presence = nil)
  normalized_sub = normalize_sub_presence(sub_presence)
  case status.try(:to_sym)
  when :available
    case normalized_sub
    when 'home_office'  then 'house-laptop'
    when 'non_queue'    then 'user-check'
    when 'call_block'   then 'phone-slash'
    else                     'circle-user'
    end
  when :dnd
    case normalized_sub
    when 'lunch'         then 'utensils'
    when 'meeting'       then 'people-group'
    when 'with_customer' then 'handshake'
    else                      'circle-minus'
    end
  when :away
    'ban'
  else
    'question'
  end
end

#moved_ring_order(member_ids, index, delta) ⇒ Array<String>

The ring order with one member moved one position toward the front
(+delta+ -1) or the back (+1). Backs the keyboard-accessible move buttons
in the queue-order editor. Out-of-range moves return the order unchanged.

Parameters:

  • member_ids (Array<String>)

    current ring order

  • index (Integer)

    position of the member to move

  • delta (Integer)

    -1 (up) or +1 (down)

Returns:

  • (Array<String>)


71
72
73
74
75
76
77
# File 'app/helpers/phones_helper.rb', line 71

def moved_ring_order(member_ids, index, delta)
  ids = member_ids.map(&:to_s)
  target = index + delta
  return ids unless index.between?(0, ids.size - 1) && target.between?(0, ids.size - 1)

  ids.insert(target, ids.delete_at(index))
end

#my_status_labelObject



109
110
111
112
113
# File 'app/helpers/phones_helper.rb', line 109

def my_status_label
  current_status = current_user.employee_phone_status
  icon_name = icon_for_presence(current_status&.presence, current_status&.sub_presence)
  fa_icon(icon_name, class: 'status-icon', text: current_user.full_name)
end

#my_status_mobile_labelObject



115
116
117
118
119
# File 'app/helpers/phones_helper.rb', line 115

def my_status_mobile_label
  current_status = current_user.employee_phone_status
  icon_name = icon_for_presence(current_status&.presence, current_status&.sub_presence)
  fa_icon(icon_name, class: 'status-icon')
end


146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'app/helpers/phones_helper.rb', line 146

def navbar_presence_dot_class(presence, sub_presence = nil)
  normalized_sub = normalize_sub_presence(sub_presence)

  case presence.to_s.downcase
  when 'available'
    case normalized_sub
    when 'home_office' then 'presence-dot-available-home-office'
    when 'non_queue'   then 'presence-dot-available-non-queue'
    else                    'presence-dot-available'
    end
  when 'dnd'   then 'presence-dot-dnd'
  when 'away'  then 'presence-dot-away'
  else              'presence-dot-unknown'
  end
end

#order_change_source_badge(change) ⇒ ActiveSupport::SafeBuffer

Badge for one PhoneQueueOrderChange row: teal for a manual switchboard
drag, gray for the weekly rotation, amber for a direct Switchvox edit.

Parameters:

Returns:

  • (ActiveSupport::SafeBuffer)


52
53
54
55
56
57
58
59
60
61
# File 'app/helpers/phones_helper.rb', line 52

def order_change_source_badge(change)
  css = if change.worker?
          'text-bg-secondary'
        elsif change.external?
          'text-bg-warning'
        else
          'text-bg-info'
        end
  tag.span(change.source_label, class: "badge #{css}")
end

#queue_strategy_label(strategy) ⇒ String

Returns human label; the humanized token when unknown.

Parameters:

  • strategy (String)

    the Switchvox strategy token

Returns:

  • (String)

    human label; the humanized token when unknown



28
29
30
# File 'app/helpers/phones_helper.rb', line 28

def queue_strategy_label(strategy)
  QUEUE_STRATEGY_LABELS.fetch(strategy.to_s, strategy.to_s.humanize)
end


162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'app/helpers/phones_helper.rb', line 162

def render_presence_change_link(employee, presence, sub_presence, include_time_in_status: nil)
  include_time_in_status = true if include_time_in_status.nil?
  selected = (employee.presence.to_s == presence.to_s and employee.sub_presence.to_s == sub_presence.to_s)
  icon_name = icon_for_presence(presence, sub_presence)
  display_name = fa_icon(icon_name, class: 'status-icon') + status_title(presence, sub_presence, selected)
  if include_time_in_status
    # `time_by_status` is only consumed when this row IS the currently
    # selected duration-tracked row (DND or Available - Non Queue), so gate
    # the report call on that predicate. Without this gate,
    # render_presence_options' loop calls the report once per presence option
    # (9+ per employee card), each time running an EmployeePhoneStatusChange +
    # EmployeePhoneStatus query — pure N+1 since the result is discarded in
    # every iteration except one.
    if selected && status_tracks_duration?(presence, sub_presence)
      time_by_status = Report::StatusTimelineReport.get_last_status_by_employee(employee.id)
      if time_by_status.present?
        current_type = [presence, sub_presence].compact.join(' - ')
        last_entry = time_by_status.rfind { |ts| ts[:type] == current_type }
        if last_entry
          time_text = Heatwave::Duration.humanize(last_entry[:time], format: :short, limit_to_hours: true, units: 2)
          time_text = time_text.present? ? time_text.delete(' ') : ''
          display_name << (:span, time_text.html_safe, style: 'margin-left:10px')
        end
      end
    end
    display_name << fa_icon('clock', text: "#{employee.auto_away_after} CST", style: 'margin-left:5px') if (presence.to_s == 'away') && employee.employee_phone_status.auto_away_after
  end
  link_to display_name,
          update_unified_status_employee_phone_statuses_path(employee_id: employee,
                                                             presence: presence,
                                                             sub_presence: sub_presence),
          class: "change-presence #{'selected' if selected}",
          data: {
            turbo_method: :patch,
            turbo_stream: true,
            presence: presence.to_s.parameterize,
            sub_presence: sub_presence.to_s.parameterize,
            combined_presence: combined_presence(presence, sub_presence)
          }
end

#render_presence_options(employee, options = {}) ⇒ String?

Renders the presence change menu items for an employee.

Parameters:

  • employee (Employee)

    the employee whose curated presence list is rendered

  • options (Hash) (defaults to: {})

    rendering options

Options Hash (options):

  • include_time_in_status (Boolean)

    include the time in the status link label

  • is_dropdown (Boolean)

    render items with the dropdown-item CSS class

Returns:

  • (String, nil)

    HTML list items, or nil when the employee has no phone status



127
128
129
130
131
132
133
134
135
136
137
# File 'app/helpers/phones_helper.rb', line 127

def render_presence_options(employee, options = {})
  return unless employee.employee_phone_status

  employee.employee_phone_status.curated_presence_list.map do |opts|
    (:li, render_presence_change_link(employee,
                                                 opts[:presence],
                                                 opts[:sub_presence],
                                                 include_time_in_status: options[:include_time_in_status]),
                class: options[:is_dropdown].to_b ? 'dropdown-item' : nil)
  end.join.html_safe
end

#ring_order_list(member_ids, names_by_account_id) ⇒ ActiveSupport::SafeBuffer

Numbered ring-order list for the order-change audit trail: member names in
position order, falling back to the raw Switchvox account id for members
no longer mapped to a CRM employee.

Parameters:

  • member_ids (Array<String>)

    Switchvox member account ids in ring order

  • names_by_account_id (Hash{String => String})

    account id => full name

Returns:

  • (ActiveSupport::SafeBuffer)


39
40
41
42
43
44
45
# File 'app/helpers/phones_helper.rb', line 39

def ring_order_list(member_ids, )
  return tag.span('', class: 'text-muted') if member_ids.blank?

  tag.ol(class: 'mb-0 ps-3') do
    safe_join(member_ids.map { |id| tag.li([id.to_s] || id.to_s) })
  end
end

#status_title(presence, sub_presence, _selected = false) ⇒ Object



103
104
105
106
107
# File 'app/helpers/phones_helper.rb', line 103

def status_title(presence, sub_presence, _selected = false)
  res = presence.titleize
  res << " - #{sub_presence}" if sub_presence.present?
  (:span, res.html_safe, class: 'status-title')
end