podemos-info/census

View on GitHub
app/admin/dashboard.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

ActiveAdmin.register_page "Dashboard" do
  menu priority: 1, label: proc { I18n.t("active_admin.dashboard") }

  content title: proc { I18n.t("active_admin.dashboard") } do
    Chartkick.options = {
      download: true,
      legend: :bottom
    }

    page_policy = policy(ActiveAdmin::Page)

    if page_policy.procedures_stats?
      panel helpers.model_name(Procedure, count: 2), id: "procedures_stats" do
        columns do
          column span: 2 do
            h4 "Creados"
            div line_chart dashboard_procedures_stats_path(format: :json, interval: controller.interval)
          end
          column do
            h4 "Pendientes"
            div id: "pending_procedures" do
              div pie_chart controller.pending_procedures_stats_data, donut: true

              controller.process_path_link(self) do
                div controller.pending_procedures_stats_data.values.sum
                span t("census.procedures.process"), class: "button"
              end
            end
          end
        end
      end
    end

    if page_policy.people_stats?
      panel helpers.model_name(Person, count: 2), id: "people_stats" do
        line_chart dashboard_people_stats_path(format: :json, interval: controller.interval)
      end
    end

    if page_policy.admins_stats?
      panel helpers.model_name(Admin, count: 2), id: "admins_stats" do
        line_chart dashboard_admins_stats_path(format: :json, interval: controller.interval)
      end
    end

    if page_policy.orders_stats?
      panel helpers.model_name(Order, count: 2), id: "orders_stats" do
        line_chart dashboard_orders_stats_path(format: :json, interval: controller.interval)
      end
    end
  end

  action_item :interval_selector do
    select onchange: "location.replace(this.value)", class: "default-select" do
      [:day, :week, :month, :year].each do |interval|
        option(value: "/?interval=#{interval}", selected: controller.interval == interval) do
          t("census.dashboard.intervals.#{interval}")
        end
      end
    end
  end

  page_action :people_stats do
    render json: people_stats_data, type: "application/json"
  end

  page_action :procedures_stats do
    render json: procedures_stats_data, type: "application/json"
  end

  page_action :orders_stats do
    render json: orders_stats_data, type: "application/json"
  end

  page_action :admins_stats do
    render json: admins_stats_data, type: "application/json"
  end

  controller do
    before_action :do_not_track_page_view, except: [:index]

    def people_stats_data
      [
        { name: helpers.state_name(Person, :state, :pending).capitalize,
          data: Person.where(created_at: dates_interval).pending.send(group_by, :created_at).count,
          color: :orange },
        { name: helpers.state_name(Person, :state, :enabled).capitalize,
          data: Person.where(created_at: dates_interval).enabled.send(group_by, :created_at).count,
          color: :green },
        { name: helpers.state_name(Person, :membership_level, :member).capitalize,
          data: Person.where(created_at: dates_interval).enabled.member.send(group_by, :created_at).count,
          color: "#683064" },
        { name: helpers.state_name(Person, :state, :cancelled).capitalize,
          data: Person.where(discarded_at: dates_interval).cancelled.send(group_by, :discarded_at).count,
          color: :red },
        { name: helpers.state_name(Person, :state, :trashed).capitalize,
          data: Person.where(discarded_at: dates_interval).trashed.send(group_by, :discarded_at).count,
          color: :gray }
      ]
    end

    def procedures_stats_data
      format_data(Procedure.where(created_at: dates_interval).group(:type).send(group_by, :created_at).count) do |name, _|
        helpers.model_name(name)
      end
    end

    def pending_procedures_stats_data
      @pending_procedures_stats_data ||= {
        t("active_admin.resources.procedure.scopes.without_open_issues") => Procedure.pending.without_open_issues.count,
        t("active_admin.resources.procedure.scopes.with_open_issues") => Procedure.pending.with_open_issues.count
      }
    end

    def orders_stats_data
      format_data(Order.where(created_at: dates_interval).group(:state).send(group_by, :created_at).count) do |name, _|
        helpers.state_name(Order, :state, name)
      end
    end

    def admins_stats_data
      format_data(*prefetch_admins(Event.where(time: dates_interval).group(:admin_id).send(group_by, :time).count)) do |name, context|
        context.dig(:admins, name) || t("census.dashboard.admins.unknown")
      end
    end

    def interval
      @interval = params[:interval]&.to_sym.presence || :week
    end

    def dates_interval
      case interval
      when :day then 1.day.ago..1.day.from_now
      when :week then 1.week.ago..1.day.from_now
      when :month then 1.month.ago..1.day.from_now
      when :year then 1.year.ago..1.day.from_now
      end
    end

    def group_by
      case interval
      when :day then :group_by_hour
      when :week then :group_by_day
      when :month then :group_by_week
      when :year then :group_by_month
      end
    end

    def format_data(raw_data, context: {})
      raw_data.group_by { |key, _| key[0] } .map do |name, series|
        {
          name: yield(name, context),
          data: Hash[series.map { |key2, value| [key2[1], value] }]
        }
      end
    end

    def prefetch_admins(raw_data)
      [raw_data, context: { admins: Hash[Admin.where(id: raw_data.map(&:first).map(&:first)).pluck(:id, :username)] }]
    end

    def process_path_link(context)
      options = if policy(Procedure).process?
                  { href: next_document_verification_procedures_path }
                else
                  { class: "hide_buttons" }
                end

      context.a(options) { yield }
    end
  end
end