Module: HrLite::ApplicationHelper

Defined in:
app/helpers/hr_lite/application_helper.rb

Constant Summary collapse

[
  { label: "Home",       path: :root_path,           match: [ "/" ] },
  { label: "Attendance", path: :attendance_path,     match: [ "/attendance", "/regularization_requests" ] },
  { label: "Leaves",     path: :leave_requests_path, match: [ "/leave_requests", "/leave_balances", "/comp_off_requests" ] },
  { label: "Team",       path: :team_path,           match: [ "/team" ] },
  { label: "Calendar",   path: :calendar_path,       match: [ "/calendar", "/holidays" ] },
  # After Calendar deliberately: the phone tab bar shows the first four
  # and this screen is empty for everybody who is not an approver, so it
  # belongs in "More" rather than displacing something everybody uses.
  # Employee tier all the same — holding an approval IS the authorisation,
  # so a manager and a stand-in covering for one reach the same screen.
  { label: "Approvals",  path: :approvals_path,      match: [ "/approvals" ] },
  { label: "Expenses",   path: :expenses_path,       match: [ "/expenses" ] },
  { label: "Benefits",   path: :benefits_path,       match: [ "/benefits" ] },
  { label: "Policies",   path: :policies_path,       match: [ "/policies" ] },
  { label: "Ask HR",     path: :hr_requests_path,    match: [ "/hr_requests" ] },
  { label: "Org",        path: :org_path,            match: [ "/org" ] },
  { label: "Kudos",      path: :kudos_path,          match: [ "/kudos" ] },
  { label: "Slips",      path: :salary_slips_path,   match: [ "/salary_slips" ] },
  { label: "Career",     path: :career_path,         match: [ "/career", "/appraisals", "/profile" ] },
  { label: "Documents",  path: :documents_path,      match: [ "/documents" ] },
  { label: "Tax",        path: :tax_declaration_path, match: [ "/tax_declaration" ] },
  { label: "Loans",      path: :loans_path,          match: [ "/loans" ] }
].freeze
ADMIN_NAV_ITEMS =
[
  { label: "Overview",        path: :admin_overview_path,        match: [ "/admin/overview" ] },
  { label: "Team attendance", path: :admin_attendances_path,     match: [ "/admin/attendances" ] },
  { label: "Approvals",       path: :admin_leave_requests_path,  match: [ "/admin/leave_requests", "/admin/leave_balances", "/admin/comp_off_requests", "/admin/regularization_requests" ] },
  { label: "Reports",         path: :admin_reports_path,         match: [ "/admin/reports" ] },
  { label: "Claims",          path: :admin_expenses_path,        match: [ "/admin/expenses" ] },
  { label: "Help desk",       path: :admin_hr_requests_path,     match: [ "/admin/hr_requests" ] },
  { label: "Assets",          path: :admin_assets_path,          match: [ "/admin/assets" ] },
  { label: "Joining & exits", path: :admin_checklists_path,      match: [ "/admin/checklists" ] }
].freeze
LEADERSHIP_NAV_ITEMS =
[
  { label: "Employees", path: :admin_employees_path,        match: [ "/admin/employees" ] },
  { label: "Settings",  path: :admin_leave_types_path,      match: [ "/admin/leave_types", "/admin/office_locations", "/admin/holidays", "/admin/setting" ] },
  { label: "Audit",     path: :admin_audit_logs_path,       match: [ "/admin/audit_logs" ] },
  { label: "Documents", path: :admin_documents_path,        match: [ "/admin/documents" ] }
].freeze
SUPERADMIN_NAV_ITEMS =

Money screens, plus role management: granting somebody payroll is the same act as holding it, so it sits with the pay rather than with the other governing screens.

[
  { label: "Payroll", path: :admin_payroll_runs_path, match: [ "/admin/payroll_runs", "/admin/salary_slips" ] },
  { label: "Roles",   path: :admin_roles_path,        match: [ "/admin/roles" ] },
  { label: "Rates",   path: :admin_statutory_rate_cards_path, match: [ "/admin/statutory_rate_cards" ] },
  { label: "Tax",     path: :admin_tax_declarations_path, match: [ "/admin/tax_declarations" ] },
  { label: "Loans",   path: :admin_loans_path,        match: [ "/admin/loans" ] }
].freeze
APPROVAL_PATHS =

Where an approval row actually leads. Each subject type has its own decision screen; the inbox only gathers them.

{
  "HrLite::LeaveRequest" => :admin_leave_request_path,
  "HrLite::CompOffRequest" => :admin_comp_off_request_path,
  "HrLite::RegularizationRequest" => :admin_regularization_request_path
}.freeze

Instance Method Summary collapse

Instance Method Details

#hr_lite_route?(helper_name) ⇒ Boolean

Returns:

  • (Boolean)


62
63
64
# File 'app/helpers/hr_lite/application_helper.rb', line 62

def hr_lite_route?(helper_name)
  hr_lite.respond_to?(helper_name)
end

#hrl_amount_in_words(amount) ⇒ Object

Indian-system amount in words for the slip footer. Delegates to the PORO so host-rendered templates (config.render_pdf) work too.



121
122
123
# File 'app/helpers/hr_lite/application_helper.rb', line 121

def hrl_amount_in_words(amount)
  HrLite::AmountInWords.words(amount)
end

#hrl_approval_path(approval) ⇒ Object



103
104
105
106
107
108
# File 'app/helpers/hr_lite/application_helper.rb', line 103

def hrl_approval_path(approval)
  helper = APPROVAL_PATHS[approval.subject_type]
  return nil unless helper && hr_lite_route?(helper)

  hr_lite.public_send(helper, approval.subject_id)
end

#hrl_duration(seconds) ⇒ Object



125
126
127
128
129
130
# File 'app/helpers/hr_lite/application_helper.rb', line 125

def hrl_duration(seconds)
  return "\u2014" if seconds.nil?

  total = seconds.to_i
  format("%dh %02dm", total / 3600, (total % 3600) / 60)
end

#hrl_money(amount) ⇒ Object

Delegates to the PORO so the host-rendered slip PDF formats identically.



115
116
117
# File 'app/helpers/hr_lite/application_helper.rb', line 115

def hrl_money(amount)
  HrLite::Money.format(amount)
end

#hrl_nav_items(items) ⇒ Object

Only items whose routes exist yet (the nav grows with each phase).



58
59
60
# File 'app/helpers/hr_lite/application_helper.rb', line 58

def hrl_nav_items(items)
  items.select { |item| hr_lite_route?(item[:path]) }
end


66
67
68
69
70
71
72
# File 'app/helpers/hr_lite/application_helper.rb', line 66

def hrl_nav_link(item)
  href = hr_lite.public_send(item[:path])
  active = item[:match].any? do |prefix|
    prefix == "/" ? request.path == href : request.path.start_with?("#{hr_lite.root_path.chomp('/')}#{prefix}")
  end
  link_to item[:label], href, class: "hrl-nav__link #{'hrl-nav__link--active' if active}"
end

#hrl_paginationObject



110
111
112
# File 'app/helpers/hr_lite/application_helper.rb', line 110

def hrl_pagination
  render "hr_lite/shared/pagination"
end

#hrl_request_status_badge(status) ⇒ Object

Status pill for a request lifecycle string — one colour map for every list and show screen.



157
158
159
160
161
# File 'app/helpers/hr_lite/application_helper.rb', line 157

def hrl_request_status_badge(status)
  css = { "approved" => "hrl-badge--ok", "rejected" => "hrl-badge--bad",
          "cancelled" => "hrl-badge--muted" }[status]
  (:span, status.humanize, class: "hrl-badge #{css}")
end

#hrl_team_status(row) ⇒ Object

Status badge for a TeamDay row — punch times over vague labels.



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'app/helpers/hr_lite/application_helper.rb', line 133

def hrl_team_status(row)
  case row.kind
  when :holiday then hrl_status_badge("Holiday", "hrl-badge--muted", worked_hint(row))
  when :weekend then hrl_status_badge("Weekend", "hrl-badge--muted", worked_hint(row))
  when :leave then hrl_status_badge("On leave (#{row.leave.leave_type.code})", "hrl-badge--warn")
  when :half_day_leave then hrl_status_badge("Half-day leave (#{row.leave.leave_type.code})", "hrl-badge--warn", worked_hint(row))
  when :upcoming then hrl_status_badge("\u2014", "hrl-badge--muted")
  when :absent
    label = row.date_today? ? "Not in yet" : "Absent"
    hrl_status_badge(label, "hrl-badge--bad")
  else # :present / :half_day punch
    record = row.record
    if record.check_out_at
      hrl_status_badge("Done #{record.check_in_at.strftime('%H:%M')}\u2013#{record.check_out_at.strftime('%H:%M')}", "hrl-badge--ok")
    elsif row.date_today?
      hrl_status_badge("In since #{record.check_in_at.strftime('%H:%M')}", "hrl-badge--ok")
    else
      hrl_status_badge("In #{record.check_in_at.strftime('%H:%M')}, no check-out", "hrl-badge--warn")
    end
  end
end

#render_kudo_message(kudo) ⇒ Object

Mention-marker-aware, XSS-safe kudos message rendering. Every literal chunk is escaped; only markers whose id has a mention row become highlighted chips (with the CURRENT display name — stale-name safe).



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'app/helpers/hr_lite/application_helper.rb', line 77

def render_kudo_message(kudo)
  mentioned = kudo.kudo_mentions.index_by(&:user_id)
  out = +""
  rest = kudo.message.to_s
  while (m = HrLite::MentionParser::MARKER.match(rest))
    out << ERB::Util.html_escape(m.pre_match)
    mention = mentioned[m[2].to_i]
    if mention
      out << %(<span class="hrl-mention">@#{ERB::Util.html_escape(HrLite.display_name(mention.user))}</span>)
    else
      out << ERB::Util.html_escape("@#{m[1]}")
    end
    rest = m.post_match
  end
  out << ERB::Util.html_escape(rest)
  out.html_safe
end