From 4d55119c32bd6fac284e9830f923fb032ffd39f4 Mon Sep 17 00:00:00 2001 From: Felix Eckhofer <felix@eckhofer.com> Date: Fri, 27 Dec 2024 17:54:01 +0100 Subject: [PATCH] Add leaderboard --- app/controllers/users_controller.rb | 3 +++ app/models/session.rb | 4 ++++ app/models/user.rb | 21 +++++++++++++++++++++ app/views/users/leaderboard.html.erb | 22 ++++++++++++++++++++++ config/routes.rb | 1 + 5 files changed, 51 insertions(+) create mode 100644 app/views/users/leaderboard.html.erb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3e74dea..2a1503d 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 bfc2247..3f4ff84 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 aa06e39..1652be2 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 0000000..fb22a0c --- /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 b66d9e1..a2c4b39 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. -- GitLab