mirror of
https://github.com/System-End/hackatime.git
synced 2026-04-20 00:35:22 +00:00
slight updates for weekly leaderboards
This commit is contained in:
parent
fd6b4ea720
commit
fa416b3842
5 changed files with 102 additions and 14 deletions
|
|
@ -52,4 +52,31 @@
|
|||
margin: -4px 0;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.period-toggle {
|
||||
display: inline-flex;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 999px;
|
||||
padding: 4px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.period-toggle-btn {
|
||||
padding: 8px 16px;
|
||||
border-radius: 999px;
|
||||
text-decoration: none;
|
||||
color: #444;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.period-toggle-btn.active {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.period-toggle-btn:hover:not(.active) {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,22 @@
|
|||
class LeaderboardsController < ApplicationController
|
||||
def index
|
||||
@leaderboard = Leaderboard.find_by(start_date: Date.current, deleted_at: nil)
|
||||
@period_type = (params[:period_type] || 'daily').to_sym
|
||||
@period_type = :daily unless [:daily, :weekly].include?(@period_type)
|
||||
|
||||
start_date = if @period_type == :weekly
|
||||
Date.current.beginning_of_week
|
||||
else
|
||||
Date.current
|
||||
end
|
||||
|
||||
@leaderboard = Leaderboard.find_by(
|
||||
start_date: start_date,
|
||||
period_type: @period_type,
|
||||
deleted_at: nil
|
||||
)
|
||||
|
||||
if @leaderboard.nil?
|
||||
LeaderboardUpdateJob.perform_later
|
||||
LeaderboardUpdateJob.perform_later(start_date, @period_type)
|
||||
flash.now[:notice] = "Leaderboard is being updated..."
|
||||
else
|
||||
@entries = @leaderboard.entries
|
||||
|
|
@ -14,9 +27,14 @@ class LeaderboardsController < ApplicationController
|
|||
|
||||
@user_on_leaderboard = current_user && tracked_user_ids.include?(current_user.id)
|
||||
unless @user_on_leaderboard
|
||||
today = Time.current
|
||||
time_range = if @period_type == :weekly
|
||||
(start_date.beginning_of_day...(start_date + 7.days).beginning_of_day)
|
||||
else
|
||||
Time.current
|
||||
end
|
||||
|
||||
@untracked_entries = Hackatime::Heartbeat
|
||||
.where(time: today.beginning_of_day..today.end_of_day)
|
||||
.where(time: time_range)
|
||||
.distinct
|
||||
.pluck(:user_id)
|
||||
.count { |user_id| !tracked_user_ids.include?(user_id) }
|
||||
|
|
|
|||
|
|
@ -6,25 +6,40 @@ class LeaderboardUpdateJob < ApplicationJob
|
|||
|
||||
# Limits concurrency to 1 job per date
|
||||
good_job_control_concurrency_with(
|
||||
key: -> { arguments.first || Date.current.to_s },
|
||||
key: -> { "#{arguments[0] || Date.current.to_s}_#{arguments[1] || 'daily'}" },
|
||||
total: 1,
|
||||
drop: true
|
||||
)
|
||||
|
||||
def perform(date = Date.current)
|
||||
def perform(date = Date.current, period_type = :daily)
|
||||
parsed_date = date.is_a?(Date) ? date : Date.parse(date.to_s)
|
||||
leaderboard = Leaderboard.create!(start_date: parsed_date)
|
||||
period_type = period_type.to_sym
|
||||
|
||||
if period_type == :weekly
|
||||
parsed_date = parsed_date.beginning_of_week
|
||||
end
|
||||
|
||||
leaderboard = Leaderboard.create!(
|
||||
start_date: parsed_date,
|
||||
period_type: period_type
|
||||
)
|
||||
|
||||
# Get list of valid user IDs from our database
|
||||
valid_user_ids = User.pluck(:id)
|
||||
return if valid_user_ids.empty?
|
||||
|
||||
date_range = if period_type == :weekly
|
||||
(parsed_date.beginning_of_day...(parsed_date + 7.days).beginning_of_day)
|
||||
else
|
||||
parsed_date.all_day
|
||||
end
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
valid_user_ids.each_slice(BATCH_SIZE) do |batch_user_ids|
|
||||
entries_data = Heartbeat.where(user_id: batch_user_ids)
|
||||
.where(time: parsed_date.all_day)
|
||||
.group(:user_id)
|
||||
.duration_seconds
|
||||
.where(time: date_range)
|
||||
.group(:user_id)
|
||||
.duration_seconds
|
||||
|
||||
entries_data = entries_data.filter { |_, total_seconds| total_seconds > 60 }
|
||||
|
||||
|
|
@ -45,8 +60,10 @@ class LeaderboardUpdateJob < ApplicationJob
|
|||
leaderboard.finished_generating_at = Time.current
|
||||
leaderboard.save!
|
||||
|
||||
# Delete previous leaderboard entries from today
|
||||
Leaderboard.where.not(id: leaderboard.id).where(start_date: parsed_date).where(deleted_at: nil).update_all(deleted_at: Time.current)
|
||||
Leaderboard.where.not(id: leaderboard.id)
|
||||
.where(start_date: parsed_date, period_type: period_type)
|
||||
.where(deleted_at: nil)
|
||||
.update_all(deleted_at: Time.current)
|
||||
rescue => e
|
||||
Rails.logger.error "Failed to update current leaderboard: #{e.message}"
|
||||
raise
|
||||
|
|
|
|||
|
|
@ -4,8 +4,29 @@ class Leaderboard < ApplicationRecord
|
|||
dependent: :destroy
|
||||
|
||||
validates :start_date, presence: true
|
||||
|
||||
enum :period_type, {
|
||||
daily: 0,
|
||||
weekly: 1
|
||||
}
|
||||
|
||||
def finished_generating?
|
||||
finished_generating_at.present?
|
||||
end
|
||||
end
|
||||
|
||||
def period_end_date
|
||||
if weekly?
|
||||
start_date + 6.days
|
||||
else
|
||||
start_date
|
||||
end
|
||||
end
|
||||
|
||||
def date_range_text
|
||||
if weekly?
|
||||
"#{start_date.strftime('%b %d')} - #{period_end_date.strftime('%b %d, %Y')}"
|
||||
else
|
||||
start_date.strftime("%B %d, %Y")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class AddPeriodTypeToLeaderboards < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_column :leaderboards, :period_type, :integer, default: 0, null: false
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue