Skip to content

Commit

Permalink
Implement new withdrawal reasons report, interstitial page and new co…
Browse files Browse the repository at this point in the history
…ntent
  • Loading branch information
elceebee committed Jan 9, 2025
1 parent 21a1b2c commit 830d27f
Show file tree
Hide file tree
Showing 16 changed files with 404 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class WithdrawalReasonsReportsController < ProviderInterfaceController

def show
@provider = current_user.providers.find(provider_id)
@withdrawal_reason_report = ProviderInterface::CandidateWithdrawalReasonsDataByProvider.new(@provider)
end

private
Expand Down
1 change: 1 addition & 0 deletions app/frontend/styles/provider/_all.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
@import "user-card";
@import "email-preview";
@import "recruitment_performance_report";
@import "withdrawal_reasons_report";
34 changes: 34 additions & 0 deletions app/frontend/styles/provider/_withdrawal_reasons_report.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.withdrawal-reasons-report-table {
&__wrapper {
overflow-x: auto;
}

&__heading {
border-bottom: none;
}

&__cell--main-reason {
font-weight: $govuk-font-weight-bold;

background: govuk-colour("light-grey");
border-top: 2px solid $govuk-input-border-colour;
}

&__cell--second-level-reason {
padding-left: govuk-spacing(3);
}

&__cell--third-level-reason {
padding-left: govuk-spacing(5);
}

&__cell--second-level-with-nested-reasons {
padding-left: govuk-spacing(3);

background: govuk-tint(govuk-colour('light-grey'), 50);
}

&__cell--light-grey-background {
background: govuk-tint(govuk-colour('light-grey'), 50);
}
}
20 changes: 15 additions & 5 deletions app/models/withdrawal_reason.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ class WithdrawalReason < ApplicationRecord

scope :by_level_one_reason, lambda { |level|
keys = get_reason_options(level).map do |key, value|
if value == {}
key
else
value.map { |val_key, _| "#{key}.#{val_key}" }
end
build_reason(key, value)
end&.flatten

where('reason LIKE ?', "#{level}%").sort do |a, b|
Expand Down Expand Up @@ -39,4 +35,18 @@ def self.get_reason_options(reason = '')
selectable_reasons.dig(*reason.split('.'))
end
end

def self.all_reasons
selectable_reasons.map do |key, value|
build_reason(key, value)
end&.flatten
end

def self.build_reason(key, value)
if value == {}
key
else
value.map { |k, v| build_reason("#{key}.#{k}", v) }
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
module ProviderInterface
class CandidateWithdrawalReasonsDataByProvider
def initialize(provider)
@provider = provider
end

ReasonRow = Struct.new(:reason, :before_accepting, :after_accepting, :total)

def show_report?
all_rows.any?
end

def all_rows
return [] if application_form_count < ProviderReports::MINIMUM_DATA_SIZE_REQUIRED

rows = []
nested_reasons.each_key do |level_one_reason|
rows << build_reason_row(level_one_reason, 'level_one')

nested_reasons[level_one_reason].each_key do |level_two_reason|
full_level_two_reason = [level_one_reason, level_two_reason].join('.')

if nested_reasons[level_one_reason][level_two_reason].present?
rows << build_reason_row(full_level_two_reason, 'level_two_with_nested_reasons')
nested_reasons[level_one_reason][level_two_reason].each_key do |level_three_reason|
full_level_three_reason = [level_one_reason, level_two_reason, level_three_reason].join('.')
rows << build_reason_row(full_level_three_reason, 'level_three')
end
else
rows << build_reason_row(full_level_two_reason, 'level_two')
end
end
end
rows
end

private

def build_reason_row(reason, level)
ReasonRow.new(
reason: {
text: translate(reason),
html_attributes: text_cell_attributes_for(level),
},
before_accepting: {
text: before_accepting_count(reason),
numeric: true,
html_attributes: numeric_cell_attributes_for(level),
},
after_accepting: {
text: after_accepting_count(reason),
numeric: true,
html_attributes: numeric_cell_attributes_for(level),
},
total: {
text: before_accepting_count(reason) + after_accepting_count(reason),
numeric: true,
html_attributes: numeric_cell_attributes_for(level),
},
)
end

def text_cell_attributes_for(level)
case level
when 'level_one'
{ class: 'withdrawal-reasons-report-table__cell--main-reason' }
when 'level_two'
{ class: 'withdrawal-reasons-report-table__cell--second-level-reason' }
when 'level_two_with_nested_reasons'
{ class: 'withdrawal-reasons-report-table__cell--second-level-with-nested-reasons' }
when 'level_three'
{ class: 'withdrawal-reasons-report-table__cell--third-level-reason' }
else
{}
end
end

def numeric_cell_attributes_for(level)
case level
when 'level_one'
{ class: 'withdrawal-reasons-report-table__cell--main-reason' }
when 'level_two_with_nested_reasons'
{ class: 'withdrawal-reasons-report-table__cell--light-grey-background' }
else
{}
end
end

def translate(string)
translation_string = string.dup.gsub('-', '_')
I18n.t("candidate_interface.withdrawal_reasons.reasons.#{translation_string}.label")
end

def before_accepting_count(reason)
withdrawal_reasons_before_acceptance.filter { |r| r.starts_with?(reason) }.length
end

def after_accepting_count(reason)
withdrawal_reasons_after_acceptance.filter { |r| r.starts_with?(reason) }.length
end

def nested_reasons
@nested_reasons ||= WithdrawalReason.selectable_reasons
end

def withdrawal_reasons_before_acceptance
@withdrawal_reasons_before_acceptance ||=
withdrawal_reasons
.where(application_choices: { accepted_at: nil })
.uniq
.pluck(:reason)
end

def withdrawal_reasons_after_acceptance
@withdrawal_reasons_after_acceptance ||=
withdrawal_reasons
.where.not(application_choices: { accepted_at: nil })
.uniq
.pluck(:reason)
end

def withdrawal_reasons
@withdrawal_reasons ||=
WithdrawalReason
.joins(:application_choice)
.published
.where('application_choices.provider_ids @> ARRAY[?]::bigint[]', @provider.id)
.where(application_choices: { current_recruitment_cycle_year: RecruitmentCycle.current_year })
end

def application_form_count
withdrawal_reasons.select('application_choices.application_form_id').distinct.count
end
end
end
6 changes: 5 additions & 1 deletion app/views/provider_interface/reports/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@
<%= govuk_link_to t('page_titles.provider.diversity_report'), provider_interface_reports_provider_diversity_report_path(provider_id: provider) %>
</li>
<li>
<%= govuk_link_to t('page_titles.provider.withdrawal_report'), provider_interface_reports_withdrawal_reports_path %>
<% if FeatureFlag.active? :new_candidate_withdrawal_reasons %>
<%= govuk_link_to t('page_titles.provider.withdrawal_report'), provider_interface_reports_withdrawal_reports_path %>
<% else %>
<%= govuk_link_to t('page_titles.provider.withdrawal_report'), provider_interface_reports_provider_withdrawal_report_path(provider_id: provider) %>
<% end %>
</li>
</ul>
<% end %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,47 @@
<span class="govuk-caption-l"> <%= @provider.name %></span>
<%= t('page_titles.provider.withdrawal_reasons_report') %>
</h1>
<% if @withdrawal_reason_report.show_report? %>
<p class="govuk-body">
<%= t('.report_description') %>
</p>
<% else %>
<%= t('.report_not_visible_html', link: govuk_link_to(t('.withdrawal_report_link_text'), provider_interface_reports_provider_withdrawal_report_path(@provider))) %>
<% end %>
</div>

<% if @withdrawal_reason_report.show_report? %>
<div class="govuk-grid-column-full">
<div class="withdrawal-reasons-report-table__wrapper">
<%= govuk_table do |table| %>
<%= table.with_caption(text: t('.table_caption'), html_attributes: { class: 'govuk-visually-hidden' }) %>
<%= table.with_head do |head| %>
<%= head.with_row do |row| %>
<%= row.with_cell(
text: t('.withdrawal_reason'),
html_attributes: { class: 'withdrawal-reasons-report-table__heading' },
) %>
<% %w[before_accepting after_accepting total].each do |heading| %>
<%= row.with_cell(
text: t(".#{heading}"),
numeric: true,
html_attributes: { class: 'withdrawal-reasons-report-table__heading' },
) %>
<% end %>
<% end %>
<% end %>
<%= table.with_body do |body| %>
<% @withdrawal_reason_report.all_rows.each do |reason_row| %>
<%= body.with_row do |row| %>
<%= row.with_cell(**reason_row.reason) %>
<%= row.with_cell(**reason_row.before_accepting) %>
<%= row.with_cell(**reason_row.after_accepting) %>
<%= row.with_cell(**reason_row.total) %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
<%= content_for :before_content, breadcrumbs(t('page_titles.provider.reports') => provider_interface_reports_path,
t('page_titles.provider.withdrawal_reports') => nil) %>


<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l"><%= t('page_titles.provider.withdrawal_reports') %></h1>

<p class="govuk-body">
TBD, some text about why there are two different reports
</p>
<%= t('.description_html') %>

<% @providers.each do |provider| %>
<% if @providers.many? %>
Expand All @@ -18,23 +15,19 @@
<ul class="govuk-list govuk-list--spaced">
<li>
<%= govuk_link_to(
t('page_titles.provider.legacy_withdrawal_report'),
t('.legacy_withdrawal_report'),
provider_interface_reports_provider_withdrawal_report_path(provider),
no_visited_state: true,
) %>
</li>
<li>
<%= govuk_link_to(
t('page_titles.provider.withdrawal_reasons_report'),
t('.withdrawal_reasons_report'),
provider_interface_reports_provider_withdrawal_reasons_report_path(provider),
no_visited_state: true
no_visited_state: true,
) %>
</li>
</ul>

<% end %>



</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,22 @@
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l">
<span class="govuk-caption-l"> <%= @provider.name %></span>
<%= t('page_titles.provider.withdrawal_report') %>
<%= t('.heading') %>
</h1>

<% if @submitted_withdrawal_reason_count < ProviderReports::MINIMUM_DATA_SIZE_REQUIRED %>
<p class="govuk-body">
You will be able to see this report once it contains data from at least <%= ProviderReports::MINIMUM_DATA_SIZE_REQUIRED %> candidates. This is to protect the privacy of candidates.
</p>
<p class="govuk-body">
The report shows data from candidates who withdrew their application and selected their reason from a set list. This is an optional question. Data for this report has only been collected from 11 April 2023.
</p>
<% else %>
<p class="govuk-body">Candidates who withdraw their application are asked to select their reasons for withdrawing. This is an optional question.</p>
<p class="govuk-body">Candidates are asked this question when they withdraw:</p>
<ul class="govuk-list govuk-list--bullet">
<li>before a decision on their application is made</li>
<li>after accepting an offer</li>
</ul>
<p class="govuk-body">
Candidates who have received an offer are not able to withdraw – they have to either accept or decline instead.
</p>
<h2 class="govuk-heading-m">Applications withdrawn in the <%= RecruitmentCycle.cycle_name %> recruitment cycle</h2>
<p class="govuk-body">
Candidates can select multiple reasons, so the numbers in each column may not match the ‘Total’ number.
</p>
<p class="govuk-body">
This data has only been collected from 11 April 2023.
</p>
<%= t('.description_html', link: govuk_link_to(t('.withdrawal_reasons_report_link_text'), provider_interface_reports_provider_withdrawal_reasons_report_path(@provider))) %>
</div>
</div>

<% if @submitted_withdrawal_reason_count >= ProviderReports::MINIMUM_DATA_SIZE_REQUIRED %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-full">

<%= render ProviderInterface::ReportTableComponent.new(headers: ['Reason',
'Withdrawn before a decision',
'Withdrawn after accepting',
'Total'],
rows: @withdrawal_data,
show_footer: true,
bold_row_headers: false) %>

<% end %>
</div>
</div>
</div>
<% end %>
1 change: 0 additions & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,6 @@ en:
diversity_report: Sex, disability, ethnicity and age of candidates
withdrawal_report: Withdrawals
withdrawal_reports: Withdrawal reports
legacy_withdrawal_report: Old reasons for withdrawal report
withdrawal_reasons_report: Withdrawal reasons
start_apply_again: Do you want to apply again?
start_carry_over: Continue your application
Expand Down
Loading

0 comments on commit 830d27f

Please sign in to comment.