Skip to content

Commit

Permalink
Implement Weekly Schedules & Tracklists (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
BGMP committed May 5, 2024
1 parent 68c1929 commit a76f750
Show file tree
Hide file tree
Showing 28 changed files with 672 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@import "teams";
@import "tournaments";
@import "tracks";
@import "weekly_schedules";

@import "twemoji/flags";

Expand Down
30 changes: 30 additions & 0 deletions app/assets/stylesheets/weekly_schedules.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#weekly-schedules {
#weekly-schedules-table {
tr {
color: #beb8bc;
}
}
}

#weekly-schedule {
#track-list-table {
th {
font-family: NissanOpti, serif;
font-size: 20px;
background-color: #003366;
}

tr {
color: #fff;
font-weight: bold;
}

.red {
background-color: #800000;
}

.black {
background-color: #000001;
}
}
}
1 change: 1 addition & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def build_navigation

@admin_nav = [
{ :name => t('nav.user.admin.upload-session'), :path => new_session_path, :organizer => true },
{ :name => t('nav.user.admin.generate-tracklist'), :path => weekly_schedules_path, :organizer => true },
{ :name => t('nav.user.admin.create-season'), :path => new_season_path },
{ :name => t('nav.user.admin.import-tracks'), :path => new_track_path },
{ :name => t('nav.user.admin.import-cars'), :path => new_car_path },
Expand Down
87 changes: 87 additions & 0 deletions app/controllers/weekly_schedules_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
class WeeklySchedulesController < ApplicationController
before_action :authenticate_user!, :except => [:index, :show]
before_action :authenticate_organizer, :except => [:index, :show]
before_action :set_weekly_schedule, :only => [:show, :edit, :update, :destroy]

respond_to :html, :json

# GET /weekly_schedules or /weekly_schedules.json
def index
@weekly_schedules = WeeklySchedule.all
@count = 1

respond_with @weekly_schedules do |format|
format.json { render :layout => false }
end
end

# GET /weekly_schedules/1 or /weekly_schedules/1.json
def show
@count = 0
@table_count = 0

respond_with @weekly_schedule do |format|
format.json { render :layout => false }
end
end

# GET /weekly_schedules/new
def new
@weekly_schedule = WeeklySchedule.new
end

# GET /weekly_schedules/1/edit
def edit
end

# POST /weekly_schedules or /weekly_schedules.json
def create
require 'rva_generate_weekly_schedule_service'

@weekly_schedule = RvaGenerateWeeklyScheduleService.new(weekly_schedule_params).generate

respond_to do |format|
if @weekly_schedule.save
format.html { redirect_to weekly_schedule_url(@weekly_schedule), :notice => "Weekly schedule was successfully created." }
format.json { render :show, :status => :created, :location => @weekly_schedule }
else
format.html { render :new, :status => :unprocessable_entity }
format.json { render :json => @weekly_schedule.errors, :status => :unprocessable_entity }
end
end
end

# PATCH/PUT /weekly_schedules/1 or /weekly_schedules/1.json
def update
respond_to do |format|
if @weekly_schedule.update(weekly_schedule_params)
format.html { redirect_to weekly_schedule_url(@weekly_schedule), :notice => "Weekly schedule was successfully updated." }
format.json { render :show, :status => :ok, :location => @weekly_schedule }
else
format.html { render :edit, :status => :unprocessable_entity }
format.json { render :json => @weekly_schedule.errors, :status => :unprocessable_entity }
end
end
end

# DELETE /weekly_schedules/1 or /weekly_schedules/1.json
def destroy
@weekly_schedule.destroy!

respond_to do |format|
format.html { redirect_to weekly_schedules_url, :notice => "Weekly schedule was successfully destroyed." }
format.json { head :no_content }
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_weekly_schedule
@weekly_schedule = WeeklySchedule.find(params[:id])
end

# Only allow a list of trusted parameters through.
def weekly_schedule_params
params.require(:weekly_schedule).permit(:season, :start_date)
end
end
46 changes: 46 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,52 @@ def category_name(category)
SYS::RVA_CATEGORY_NAMES[category].capitalize.gsub(/-[a-z]/, &:upcase)
end

# @param category [Integer]
# @return [String] Localized name of the category
def localized_category_name(category)
case category
when SYS::CATEGORY::ROOKIE
t('classes.rookie')
when SYS::CATEGORY::AMATEUR
t('classes.amateur')
when SYS::CATEGORY::ADVANCED
t('classes.advanced')
when SYS::CATEGORY::SEMI_PRO
t('classes.semi-pro')
when SYS::CATEGORY::PRO
t('classes.pro')
when SYS::CATEGORY::SUPER_PRO
t('classes.super-pro')
when SYS::CATEGORY::CLOCKWORK
t('classes.clockwork')
else
t('misc.unknown')
end
end

# @param weekday_number [Integer]
# @return [String] Localized name of the week day
def localized_weekday(weekday_number)
case weekday_number
when 1
t('misc.weekdays.monday')
when 2
t('misc.weekdays.tuesday')
when 3
t('misc.weekdays.wednesday')
when 4
t('misc.weekdays.thursday')
when 5
t('misc.weekdays.friday')
when 6
t('misc.weekdays.saturday')
when 0
t('misc.weekdays.sunday')
else
t('misc.unknown')
end
end

# @param input [Number] The number
# @param value [Integer] Amount of precision
# @return [String] The number with the desired precision as a string
Expand Down
2 changes: 2 additions & 0 deletions app/helpers/weekly_schedules_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module WeeklySchedulesHelper
end
1 change: 1 addition & 0 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ import "./channels"
import './cars'
import "./play"
import "./nav"
import "./weekly_schedule"

Turbo.session.drive = false
18 changes: 18 additions & 0 deletions app/javascript/weekly_schedule/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import html2canvas from "html2canvas";

$(document).on('turbo:load', function () {
for (let i = 0; i < 7; i++) {
document.getElementById(`dl-png-${i}`).onclick = function () {
const screenshotTarget = document.getElementById(`tracklist-${i}`);

html2canvas(screenshotTarget).then((canvas) => {
const base64image = canvas.toDataURL("image/png");
var anchor = document.createElement('a');
anchor.setAttribute("href", base64image);
anchor.setAttribute("download", `tracklist-${i + 1}.png`);
anchor.click();
anchor.remove();
})
}
}
})
10 changes: 10 additions & 0 deletions app/models/track.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ class Track
validates_presence_of :stock
validates_presence_of :average_lap_time

def lap_count(category)
normalized_avg_time = average_lap_time * SYS::CATEGORY::LAP_COUNT_CONSTANT[category]
return 3 if normalized_avg_time.zero?

lap_count = 135 / normalized_avg_time
return 2 if lap_count < 2

lap_count
end

def name_variations
[name, "#{name} R", "#{name} M", "#{name} RM"]
end
Expand Down
13 changes: 13 additions & 0 deletions app/models/track_list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class TrackList
include Mongoid::Document

embedded_in :weekly_schedule

embeds_many :track_list_entries

field :category, :type => Integer
field :track_count, :type => Integer

validates_presence_of :category
validates_presence_of :track_count
end
13 changes: 13 additions & 0 deletions app/models/track_list_entry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class TrackListEntry
include Mongoid::Document

embedded_in :track_list

field :track_name, :type => String
field :stock, :type => Boolean
field :lap_count, :type => Integer

validates_presence_of :track_name
validates_presence_of :stock
validates_presence_of :lap_count
end
15 changes: 15 additions & 0 deletions app/models/weekly_schedule.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class WeeklySchedule
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::MultiParameterAttributes

store_in :database => 'rv_weekly_schedules'

embeds_many :track_lists

accepts_nested_attributes_for :track_lists

belongs_to :season

field :start_date, :type => Date
end
85 changes: 85 additions & 0 deletions app/services/rva_generate_weekly_schedule_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
class RvaGenerateWeeklyScheduleService
include ApplicationHelper
include SeasonsHelper

def initialize(weekly_schedule_params)
@season = Season.find(weekly_schedule_params[:season])
@start_date = weekly_schedule_params[:start_date]
end

def generate
category_numbers = [
SYS::CATEGORY::ROOKIE,
SYS::CATEGORY::AMATEUR,
SYS::CATEGORY::ADVANCED,
SYS::CATEGORY::SEMI_PRO,
SYS::CATEGORY::PRO,
SYS::CATEGORY::SUPER_PRO,
SYS::CATEGORY::RANDOM
].shuffle

season_tracks = @season.tracks.clone.shuffle
reverse_tracks = []
reverse = false

track_lists = {}
num_track_lists = 0
category_numbers.each do |n|
season_tracks = @season.tracks.clone if season_tracks.length < 20

# pick 20 random tracks every 2 TrackLists
track_list_entries = {}
num_track_list_entries = 0

if reverse
reverse_tracks.each do |t|
track_entry_hash = {
:track_name => "#{t.name} R",
:stock => t.stock,
:lap_count => t.lap_count(n)
}

track_list_entries = track_list_entries.merge(num_track_list_entries.to_s => track_entry_hash)

num_track_list_entries += 1
end

reverse_tracks = []
else
20.times do
track = season_tracks.pop.clone
reverse_tracks << track

track_entry_hash = {
:track_name => track.name,
:stock => track.stock,
:lap_count => track.lap_count(n)
}

track_list_entries = track_list_entries.merge(num_track_list_entries.to_s => track_entry_hash)

num_track_list_entries += 1
end
end

track_list_hash = {
:category => n,
:track_count => 20,
:track_list_entries => track_list_entries
}

track_lists = track_lists.merge(num_track_lists.to_s => track_list_hash)

num_track_lists += 1
reverse = !reverse
end

weekly_schedule_hash = {
:season => @season,
:start_date => @start_date,
:track_lists => track_lists
}

WeeklySchedule.new(weekly_schedule_hash)
end
end
11 changes: 11 additions & 0 deletions app/views/weekly_schedules/_form.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
= form_with(model: weekly_schedule) do |form|
- if weekly_schedule.errors.any?
%div{style: "color: red"}
%h2
= pluralize(weekly_schedule.errors.count, "error")
prohibited this weekly_schedule from being saved:
%ul
- weekly_schedule.errors.each do |error|
%li= error.full_message
%div
= form.submit
1 change: 1 addition & 0 deletions app/views/weekly_schedules/_weekly_schedule.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
%div{id: "#{dom_id weekly_schedule}"}
2 changes: 2 additions & 0 deletions app/views/weekly_schedules/_weekly_schedule.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
json.extract! weekly_schedule, :id, :start_date, :track_lists, :created_at, :updated_at
json.url weekly_schedule_url(weekly_schedule, format: :json)

0 comments on commit a76f750

Please sign in to comment.