diff --git a/app/assets/images/icons/warning.svg b/app/assets/images/icons/warning.svg new file mode 100644 index 0000000000..9dc44a252e --- /dev/null +++ b/app/assets/images/icons/warning.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/stylesheets/pages/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss index 2e8983d863..852d883db5 100644 --- a/app/assets/stylesheets/pages/dashboard.scss +++ b/app/assets/stylesheets/pages/dashboard.scss @@ -1,13 +1,74 @@ .dashboard-show-page-body{ .card{ - border: 1px solid #757575; + border: 0.1rem solid #757575; } select.select__element{ - border: 1px solid #CFC5BF; - border-radius: 5px; + border: 0.1rem solid #CFC5BF; + border-radius: 0.5rem; background-image: image-url('dropdown.svg'); background-repeat: no-repeat; - background-position: right 10px center; + background-position: right 1rem center; + } + + .capacity { + table { + border-collapse: collapse; + border-spacing: 0; + width: 100%; + + tr th { + font-weight: normal; + color: #757575; + text-align: left; + padding: 1.2rem 0; + } + + tr { + border-bottom: 0.1rem solid #BEBEBE; + td { + padding: 1.2rem 0; + } + td:last-child { + font-weight: bold; + } + } + + tr:last-child { + border-bottom: none; + } + + .organization-link { + color: #000; + text-decoration: none; + } + + .controls>div { + display: flex; + align-items: center; + gap: 0.5rem; + img { + width: 1.8rem; + height: 1.8rem; + } + } + + .under-capacity { + color: #07866C; + } + + .at-capacity { + } + + .over-capacity { + color: #D73D02; + } + } + } + + .paging { + display: flex; + justify-content: flex-end; + gap: 2rem; } } diff --git a/app/controllers/hub/dashboard_controller.rb b/app/controllers/hub/dashboard_controller.rb index 37f67348c2..3d8ace7f8c 100644 --- a/app/controllers/hub/dashboard_controller.rb +++ b/app/controllers/hub/dashboard_controller.rb @@ -3,6 +3,8 @@ class DashboardController < Hub::BaseController layout "hub" before_action :require_dashboard_user before_action :load_filter_options, only: [:index, :show] + helper_method :capacity_css_class + helper_method :capacity_count def index model = @filter_options.first.model @@ -13,6 +15,7 @@ def show @selected_value = "#{params[:type]}/#{params[:id]}" selected_option = @filter_options.find{ |option| option.value == @selected_value } @selected = selected_option.model + load_capacity end private @@ -92,5 +95,38 @@ def self.flatten_filter_options(filter_options, result) DashboardFilterOption = Struct.new(:value, :model, :children, :has_parent) + def load_capacity + return if @selected.instance_of? Site + if @selected.instance_of? Coalition + @capacity = @selected.organizations.filter(&:capacity_limit) + @capacity.sort! do |a, b| + sort_a = (a.active_client_count.to_f / a.capacity_limit) + sort_b = (b.active_client_count.to_f / b.capacity_limit) + sort_b <=> sort_a + end + elsif @selected.instance_of?(Organization) && @selected.capacity_limit + @capacity = [@selected] + end + end + + def capacity_css_class(organization) + if organization.active_client_count > (organization.capacity_limit || 0) + "over-capacity" + elsif organization.active_client_count < (organization.capacity_limit || 0) + "under-capacity" + else + "at-capacity" + end + end + + def capacity_count + if @selected.instance_of? Coalition + @selected.organizations.count(&:capacity_limit) + elsif @selected.instance_of?(Organization) && @selected.capacity_limit + 1 + else + 0 + end + end end end \ No newline at end of file diff --git a/app/views/hub/dashboard/_capacity.html.erb b/app/views/hub/dashboard/_capacity.html.erb index 4ec7e85407..ef9194749f 100644 --- a/app/views/hub/dashboard/_capacity.html.erb +++ b/app/views/hub/dashboard/_capacity.html.erb @@ -1,4 +1,37 @@ -
-

Capacity

-

TODO: Implement

+
+

<%= I18n.t("hub.dashboard.show.capacity") %>

+ + + + + + + + + <% @capacity[..3].each do |organization| %> + + + + + <% end %> + +
<%= I18n.t("hub.dashboard.show.org_name") %><%= I18n.t("hub.dashboard.show.current_capacity") %>
+ <%= link_to "#{organization.name}", + can?(:edit, organization) ? edit_hub_organization_path(id: organization) : hub_organization_path(id: organization), + class: "organization-link" + %> + +
+
<%= organization.active_client_count %>/<%= organization.capacity_limit %>
+ <% if organization.active_client_count.to_f / organization.capacity_limit > 1 %> + <%= image_tag('icons/warning.svg', alt: "") %> + <% end %> +
+
+ <% if @selected.instance_of? Coalition %> +
+
<%= @capacity.length %> of <%= capacity_count %>
+ <%= link_to I18n.t("hub.dashboard.show.view_all"), hub_organizations_path %> +
+ <% end %>
\ No newline at end of file diff --git a/app/views/hub/dashboard/show.html.erb b/app/views/hub/dashboard/show.html.erb index 8d5f51236a..6e17e8f529 100644 --- a/app/views/hub/dashboard/show.html.erb +++ b/app/views/hub/dashboard/show.html.erb @@ -15,7 +15,7 @@
<%= render "hub/dashboard/service_level_agreements_notifications" %> - <% if [Coalition, Organization].include?(@selected.class) %> + <% if @capacity.present? %> <%= render "hub/dashboard/capacity" %> <% end %> <%= render "hub/dashboard/returns_by_status" %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 7d9daf1c09..1b432ead2c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -961,7 +961,11 @@ en: title: Add a new CTC client dashboard: show: + capacity: Capacity + current_capacity: Current Capacity + org_name: Organization Name title: Dashboard + view_all: View All documents: confirm: text: Is this a %{document_type} for %{client_name}'s %{filing_year} tax return? diff --git a/config/locales/es.yml b/config/locales/es.yml index 5d2e187be5..16e0fe733f 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -970,7 +970,11 @@ es: title: Agregar un nuevo cliente dashboard: show: + capacity: Capacidad + current_capacity: Capacidad actual + org_name: Nombre de la Organización title: Panel + view_all: Ver todo documents: confirm: text: "¿Es esta una %{document_type} para la declaración de impuestos %{filing_year} de %{client_name}?" diff --git a/spec/controllers/hub/dashboard_controller_spec.rb b/spec/controllers/hub/dashboard_controller_spec.rb index bbdf5c2957..68c7482fc3 100644 --- a/spec/controllers/hub/dashboard_controller_spec.rb +++ b/spec/controllers/hub/dashboard_controller_spec.rb @@ -16,6 +16,30 @@ model = VitaPartner.first expect(response).to redirect_to "/en/hub/dashboard/#{model.class.name.downcase}/#{model.id}" end + + context "with a nested set of Coalitions and Organizations" do + let(:coalition) { create :coalition } + let(:user) { create(:user, role: create(:coalition_lead_role, coalition: coalition)) } + let(:orgs) do + [ + create(:organization, coalition: coalition), + create(:organization, coalition: coalition), + create(:organization, coalition: coalition) + ] + end + + it "sets filter options correctly" do + expected_filter_options = [ + "coalition/#{coalition.id}", + "organization/#{orgs[0].id}", + "organization/#{orgs[1].id}", + "organization/#{orgs[2].id}" + ] + get :index + expect(assigns(:filter_options).length).to eq 4 + expect(assigns(:filter_options).map{|option| option.value }).to eq expected_filter_options + end + end end end @@ -33,6 +57,18 @@ expect(assigns(:filter_options).length).to eq 1 expect(assigns(:filter_options)[0].model).to eq model end + + it "shows the capacity panel" do + model = VitaPartner.first + get :show, params: { id: model.id, type: model.class.name.downcase } + expect(response.body).to have_text I18n.t('hub.dashboard.show.capacity') + expect(response.body).to have_text I18n.t('hub.dashboard.show.org_name') + expect(response.body).to have_text Organization.first.name + # Count instances of substring - note: string.count doesn't do this! + expect(response.body.scan(/organization-link/).length).to eq(1) + end end end end + +