Events: remaining fixes
Some checks failed
CI / scan_ruby (push) Has been cancelled
CI / scan_js (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
sto
2026-08-06 11:26:51 +02:00
parent 77b4e06151
commit 817857ffd8
7 changed files with 58 additions and 47 deletions

View File

@@ -169,6 +169,7 @@ class ContestsController < ApplicationController
end end
def scoreboard def scoreboard
@is_scoreboard = true
if active_page("/public/event/") == "active" if active_page("/public/event/") == "active"
@event = Event.find_by(slug: params[:id]) @event = Event.find_by(slug: params[:id])
unless @event && @event.shared_scoreboard && !@event.contests.where(public: true).empty? unless @event && @event.shared_scoreboard && !@event.contests.where(public: true).empty?
@@ -187,6 +188,10 @@ class ContestsController < ApplicationController
else else
@contest = @event.contests.where(public: true).first @contest = @event.contests.where(public: true).first
end end
if @contest.completions.empty? && @contest.start_time == nil
authorize @contest
render :scoreboard_not_started and return
end
else else
@contest = Contest.find_by(slug: params[:id]) @contest = Contest.find_by(slug: params[:id])
unless @contest && @contest.public unless @contest && @contest.public
@@ -195,6 +200,7 @@ class ContestsController < ApplicationController
end end
end end
authorize @contest authorize @contest
@is_scoreboard_started = true
I18n.locale = @contest.lang I18n.locale = @contest.lang

View File

@@ -35,14 +35,14 @@ class EventsController < ApplicationController
def show def show
authorize @event authorize @event
@contests = @event.contests.includes([ :contestants, :puzzles ]) @contests = @event.contests.includes([ :contestants, puzzles: [ :image_attachment ] ])
@title = @event.name @title = @event.name
end end
def edit def edit
authorize @event authorize @event
@title = I18n.t("events.edit.title") @title = @event.name
@nonav = true @nonav = true
end end
@@ -52,7 +52,7 @@ class EventsController < ApplicationController
if @event.update(event_params) if @event.update(event_params)
redirect_to event_path(@event), notice: t("events.edit.notice") redirect_to event_path(@event), notice: t("events.edit.notice")
else else
@title = I18n.t("events.edit.title") @title = @event.name
@nonav = true @nonav = true
render :edit, status: :unprocessable_entity render :edit, status: :unprocessable_entity
end end

View File

@@ -1,4 +1,4 @@
.mt-2.row style="font-size: 16px;" .mt-3.row style="font-size: 16px;"
.col .col
ul.nav.nav-tabs.mb-4 ul.nav.nav-tabs.mb-4
- @contest.event.contests.where(public: true).each do |contest| - @contest.event.contests.where(public: true).each do |contest|

View File

@@ -0,0 +1,2 @@
.mt-3
= t("contests.scoreboard.not_started_message")

View File

@@ -45,54 +45,55 @@ html
h1.mb-4 h1.mb-4
- if @contest && @contest.id.present? - if @contest && @contest.id.present?
- if active_page("/public") == "active" && @action_path - if active_page("/public") == "active" && @is_scoreboard
- if active_page("/public/event/") == "active" - if active_page("/public/event/") == "active"
= @contest.event.name = @contest.event.name
= render "event_nav" = render "event_nav"
- else - else
= @contest.name = @contest.name
.float-end style="margin-top: #{active_page("/public/event/") == "active" ? "-18px" : "-5px"};" id="scoreboard-switches" - if @is_scoreboard_started
.d-inline-flex.align-items-center .float-end style="margin-top: #{active_page("/public/event/") == "active" ? "-18px" : "-5px"};" id="scoreboard-switches"
.ms-4.form-check.form-switch style="font-size: 16px; font-weight: 300;" .d-inline-flex.align-items-center
input.form-check-input type="checkbox" id="refresh-checkbox" .ms-4.form-check.form-switch style="font-size: 16px; font-weight: 300;"
label.ms-1 style="font-size: 16px; font-weight: 300;" input.form-check-input type="checkbox" id="refresh-checkbox"
= t("contests.scoreboard.auto_refresh") label.ms-1 style="font-size: 16px; font-weight: 300;"
.js data-turbo="false" = t("contests.scoreboard.auto_refresh")
javascript: .js data-turbo="false"
function refresh() { javascript:
if (document.getElementById('refresh-checkbox').checked) { function refresh() {
addParam('autorefresh', 1); if (document.getElementById('refresh-checkbox').checked) {
setTimeout(refresh, 30000); addParam('autorefresh', 1);
setTimeout(refresh, 30000);
}
} }
} function addParam(key, value) {
function addParam(key, value) { const urlParams = new URLSearchParams(window.location.search);
const urlParams = new URLSearchParams(window.location.search); urlParams.delete(key);
urlParams.delete(key); urlParams.append(key, value);
urlParams.append(key, value); const refreshBtn = document.getElementById('refresh-button')
const refreshBtn = document.getElementById('refresh-button') refreshBtn.href = `/public/#{@contest.friendly_id}?${urlParams.toString()}`;
refreshBtn.href = `/public/#{@contest.friendly_id}?${urlParams.toString()}`; refreshBtn.click();
refreshBtn.click(); }
} function removeParam(key) {
function removeParam(key) { const urlParams = new URLSearchParams(window.location.search);
const urlParams = new URLSearchParams(window.location.search); urlParams.delete(key);
urlParams.delete(key); const refreshBtn = document.getElementById('refresh-button')
const refreshBtn = document.getElementById('refresh-button') refreshBtn.href = `/public/#{@contest.friendly_id}?${urlParams.toString()}`;
refreshBtn.href = `/public/#{@contest.friendly_id}?${urlParams.toString()}`; refreshBtn.click();
refreshBtn.click(); }
} function autoRefresh() {
function autoRefresh() { if (document.getElementById('refresh-checkbox').checked) setTimeout(refresh, 30000);
if (document.getElementById('refresh-checkbox').checked) setTimeout(refresh, 30000); document.getElementById('refresh-checkbox').addEventListener('change', (e) => {
document.getElementById('refresh-checkbox').addEventListener('change', (e) => { if (e.target.checked) refresh();
if (e.target.checked) refresh(); else removeParam('autorefresh');
else removeParam('autorefresh'); });
}); }
} async function startAutoRefresh(count) {
async function startAutoRefresh(count) { if (count == 0) return;
if (count == 0) return; if (document.getElementById('refresh-button') && document.getElementById('refresh-checkbox')) autoRefresh();
if (document.getElementById('refresh-button') && document.getElementById('refresh-checkbox')) autoRefresh(); else setTimeout(() => startAutoRefresh(count - 1), 10);
else setTimeout(() => startAutoRefresh(count - 1), 10); }
} startAutoRefresh(200);
startAutoRefresh(200);
- elsif active_page("/contests") == "active" - elsif active_page("/contests") == "active"
= @contest.name = @contest.name
- if @contest.event && @contest.event.shared_scoreboard - if @contest.event && @contest.event.shared_scoreboard

View File

@@ -236,6 +236,7 @@ en:
all_categories: All categories all_categories: All categories
auto_refresh: Auto refresh (30s) auto_refresh: Auto refresh (30s)
hide_offline: Hide offline participants hide_offline: Hide offline participants
not_started_message: This contest isn't started yet.
refresh: Activate auto-refresh (every 5s) refresh: Activate auto-refresh (every 5s)
title: "%{name}" title: "%{name}"
show: show:

View File

@@ -207,6 +207,7 @@ fr:
all_categories: Toutes les catégories all_categories: Toutes les catégories
auto_refresh: Auto-rafraichissement (30s) auto_refresh: Auto-rafraichissement (30s)
hide_offline: Cacher les participant.e.s hors-ligne hide_offline: Cacher les participant.e.s hors-ligne
not_started_message: Cette épreuve n'a pas encore commencé.
refresh: Activer le rafraichissement automatique de la page (toutes les 5s) refresh: Activer le rafraichissement automatique de la page (toutes les 5s)
title: "%{name}" title: "%{name}"
show: show:
@@ -270,7 +271,7 @@ fr:
index: index:
contest: épreuve contest: épreuve
contests: épreuves contests: épreuves
message: Nouvelle fonctionalité ! Les événements permettent de regrouper plusieurs concours/épreuves en un seul espace de gestion. Cela permet aussi, si souhaité, d'avoir un lien de classement commun à toutes les épreuces d'un même événement. message: Nouvelle fonctionalité ! Les événements permettent de regrouper plusieurs concours/épreuves en un seul espace de gestion. Cela permet aussi, si souhaité, d'avoir un lien de classement commun à toutes les épreuves d'un même événement.
my_contests_outside_events: Mes concours non associés à un événement my_contests_outside_events: Mes concours non associés à un événement
new: Créer un nouvel événement new: Créer un nouvel événement
other_contest: concours other_contest: concours