diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3e74dea87f6c1d4315d3f8120bb87b404d13a14d..2a1503d2e27d4c281241ce225ffc38cc73e4c184 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,2 +1,5 @@ class UsersController < ApplicationController + def leaderboard + @workload_data = User.leaderboard + end end diff --git a/app/models/session.rb b/app/models/session.rb index bfc22477df2618024727a5b4fab557e3d781fcf7..3f4ff8406e3b18ec632fa6ee359cdac77ee15527 100644 --- a/app/models/session.rb +++ b/app/models/session.rb @@ -56,6 +56,10 @@ class Session < ApplicationRecord return filedrop_files.exists? || filedrop_comments.exists? end + def duration_minutes + return (ends_at - starts_at) / 60.0 + end + private def notify_if_changed diff --git a/app/models/user.rb b/app/models/user.rb index aa06e39cb5cd512b3601619c98cc73fb57c99336..1652be201b8e4276a2f034f57975d1d063d06e39 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -30,6 +30,23 @@ class User < ApplicationRecord end end + def self.leaderboard + all.map { |u| [u.name, u.workload_minutes] } + .sort_by { |_, workload| -workload } + .reject { |_, workload| workload.zero? } + .to_h + end + + class Session < ApplicationRecord + has_many :assignments + + def workload_minutes + # Logic to calculate workload in minutes + 60 # This is just a placeholder + end + end + + def errors super.tap { |errors| errors.delete(:password, :blank) if password.nil? } end @@ -66,6 +83,10 @@ class User < ApplicationRecord self.avatar_color = "##{r.to_s(16).rjust(2, '0')}#{g.to_s(16).rjust(2, '0')}#{b.to_s(16).rjust(2, '0')}" end + def workload_minutes + Assignment.includes(:session).where(user: self).sum { | a | a.session.duration_minutes } + end + private def valid_invitation_token diff --git a/app/views/users/leaderboard.html.erb b/app/views/users/leaderboard.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..fb22a0c21453eb21c290e475ac826bd3d53613c8 --- /dev/null +++ b/app/views/users/leaderboard.html.erb @@ -0,0 +1,22 @@ +<div class="w-full"> + <h1 class="text-xl my-4">Leaderboard</h1> + <dl class="w-full max-w-4xl mx-auto"> + <% top_workload = @workload_data.values.max %> + <% @workload_data.each_with_index do |(username, workload), index| %> + <% hours, minutes = workload.divmod(60) %> + <div class="bg-gray-50 px-4 py-2 sm:flex sm:items-center sm:gap-4"> + <dt class="text-sm font-medium text-gray-500 flex-none w-1/4 sm:w-1/6"><%= username %><%= " 👑" if index == 0 %></dt> + <dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:flex-1"> + <div class="relative pt-1"> + <div class="overflow-hidden h-2 mb-1 text-xs flex rounded bg-green-200"> + <div style="width:<%= (100 * workload / top_workload).round %>%;" class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-500"></div> + </div> + <span class="text-xs font-semibold inline-block py-1 px-2 uppercase rounded text-green-600 bg-green-200 last:mr-0 mr-1"> + <%= hours > 0 ? "#{hours}h #{minutes.round}m" : "#{minutes.round} minutes" %> + </span> + </div> + </dd> + </div> + <% end %> + </dl> +</div> diff --git a/config/routes.rb b/config/routes.rb index b66d9e15c7db2e780ff88600e404ba616f812299..a2c4b3993e8283c6abca2c9b63e955e615dd6e76 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,6 +4,7 @@ Rails.application.routes.draw do mount ActionCable.server => '/cable' get 'speakers/show' + get 'users/leaderboard' # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Can be used by load balancers and uptime monitors to verify that the app is live.