diff --git a/app/controllers/contests_controller.rb b/app/controllers/contests_controller.rb
index 48c52ea..411d56f 100644
--- a/app/controllers/contests_controller.rb
+++ b/app/controllers/contests_controller.rb
@@ -3,7 +3,7 @@ class ContestsController < ApplicationController
include ContestantsConcern
before_action :set_contest, only: %i[ destroy show ]
- before_action :set_settings_contest, only: %i[ settings_general_edit settings_general_update settings_offline_edit settings_offline_update settings_categories_edit ]
+ before_action :set_settings_contest, only: %i[ settings_general_edit settings_general_update settings_public_edit settings_public_update settings_onsite_edit settings_onsite_update settings_online_edit settings_online_update settings_categories_edit ]
before_action :offline_setup, only: %i[ offline_new offline_create offline_edit offline_update offline_completed ]
skip_before_action :require_authentication, only: %i[ scoreboard offline_new offline_create offline_edit offline_update offline_completed ]
@@ -24,7 +24,15 @@ class ContestsController < ApplicationController
authorize @contest
end
- def settings_offline_edit
+ def settings_public_edit
+ authorize @contest
+ end
+
+ def settings_onsite_edit
+ authorize @contest
+ end
+
+ def settings_online_edit
authorize @contest
end
@@ -42,13 +50,33 @@ class ContestsController < ApplicationController
end
end
- def settings_offline_update
+ def settings_public_update
authorize @contest
- if @contest.update(settings_offline_params)
- redirect_to "/contests/#{@contest.id}/settings/offline", notice: t("contests.edit.notice")
+ if @contest.update(settings_public_params)
+ redirect_to "/contests/#{@contest.id}/settings/public", notice: t("contests.edit.notice")
else
- render :settings_offline_edit, status: :unprocessable_entity
+ render :settings_public_edit, status: :unprocessable_entity
+ end
+ end
+
+ def settings_onsite_update
+ authorize @contest
+
+ if @contest.update(settings_onsite_params)
+ redirect_to "/contests/#{@contest.id}/settings/onsite", notice: t("contests.edit.notice")
+ else
+ render :settings_onsite_edit, status: :unprocessable_entity
+ end
+ end
+
+ def settings_online_update
+ authorize @contest
+
+ if @contest.update(settings_online_params)
+ redirect_to "/contests/#{@contest.id}/settings/online", notice: t("contests.edit.notice")
+ else
+ render :settings_online_edit, status: :unprocessable_entity
end
end
@@ -210,10 +238,18 @@ class ContestsController < ApplicationController
end
def settings_general_params
- params.expect(contest: [ :lang, :name, :duration, :public, :ranking_mode, :team, :allow_registration, :code ])
+ params.expect(contest: [ :lang, :name, :duration, :team, :allow_registration ])
end
- def settings_offline_params
+ def settings_public_params
+ params.expect(contest: [ :public, :ranking_mode ])
+ end
+
+ def settings_onsite_params
+ params.expect(contest: [ :code ])
+ end
+
+ def settings_online_params
params.expect(contest: [ :offline_form ])
end
diff --git a/app/policies/contest_policy.rb b/app/policies/contest_policy.rb
index dfe842c..d26a6cb 100644
--- a/app/policies/contest_policy.rb
+++ b/app/policies/contest_policy.rb
@@ -47,11 +47,27 @@ class ContestPolicy < ApplicationPolicy
edit?
end
- def settings_offline_edit?
+ def settings_public_edit?
edit?
end
- def settings_offline_update?
+ def settings_public_update?
+ edit?
+ end
+
+ def settings_onsite_edit?
+ edit?
+ end
+
+ def settings_onsite_update?
+ edit?
+ end
+
+ def settings_online_edit?
+ edit?
+ end
+
+ def settings_online_update?
edit?
end
diff --git a/app/views/application/_contest_nav.html.slim b/app/views/application/_contest_nav.html.slim
index bd2002d..b442ced 100644
--- a/app/views/application/_contest_nav.html.slim
+++ b/app/views/application/_contest_nav.html.slim
@@ -1,35 +1,3 @@
-javascript:
- async function copyExtensionUrlToClipboard() {
- await navigator.clipboard.writeText("#{message_url}?token=#{@contest.generate_token_for(:token)}");
- alert("#{t("contests.show.url_copied")}");
- }
-
-.row.mb-4
- .col
- - if @contest.public
- a.btn.btn-success href="/public/#{@contest.slug}"
- = t("contests.show.open_public_scoreboard")
- - else
- a.btn.btn-success.disabled
- = t("contests.show.public_scoreboard_disabled")
- - if @contest.offline_form && @contest.puzzles.length < 2
- a.ms-3.btn.btn-success href="/public/#{@contest.slug}/offline"
- = t("contests.show.open_offline_form")
- - else
- a.ms-3.btn.btn-success.disabled
- = t("contests.show.offline_form_disabled")
- button.btn.btn-success.ms-3 onclick="copyExtensionUrlToClipboard()"
- css:
- button > svg {
- margin-right: 2px;
- margin-top: -3px;
- }
-
- =< t("contests.show.copy_extension_url")
-
.row
.col
ul.nav.nav-tabs.mb-4
@@ -43,11 +11,5 @@ javascript:
a.nav-link class=active_page(contest_messages_path(@contest)) href=contest_messages_path(@contest)
= t("messages.plural").capitalize
li.nav-item
- a.nav-link class=active_page("/contests/#{@contest.id}/settings/general") href="/contests/#{@contest.id}/settings/general"
- = t("contests.form.general")
- li.nav-item
- a.nav-link class=active_page("/contests/#{@contest.id}/settings/offline") href="/contests/#{@contest.id}/settings/offline"
- = t("contests.form.offline")
- li.nav-item
- a.nav-link class=active_page("/contests/#{@contest.id}/settings/categories") href="/contests/#{@contest.id}/settings/categories"
- = t("contests.form.categories")
\ No newline at end of file
+ a.nav-link class=active_page("/contests/#{@contest.id}/settings") href="/contests/#{@contest.id}/settings/general"
+ = t("contests.nav.settings")
\ No newline at end of file
diff --git a/app/views/application/_params_nav.html.slim b/app/views/application/_params_nav.html.slim
new file mode 100644
index 0000000..cd95ea7
--- /dev/null
+++ b/app/views/application/_params_nav.html.slim
@@ -0,0 +1,18 @@
+.row
+ .col
+ ul.nav.nav-tabs.mb-4
+ li.nav-item
+ a.nav-link class=active_page("/contests/#{@contest.id}/settings/general") href="/contests/#{@contest.id}/settings/general"
+ = t("contests.nav.general")
+ li.nav-item
+ a.nav-link class=active_page("/contests/#{@contest.id}/settings/public") href="/contests/#{@contest.id}/settings/public"
+ = t("contests.nav.public")
+ li.nav-item
+ a.nav-link class=active_page("/contests/#{@contest.id}/settings/onsite") href="/contests/#{@contest.id}/settings/onsite"
+ = t("contests.nav.onsite")
+ li.nav-item
+ a.nav-link class=active_page("/contests/#{@contest.id}/settings/online") href="/contests/#{@contest.id}/settings/online"
+ = t("contests.nav.online")
+ li.nav-item
+ a.nav-link class=active_page("/contests/#{@contest.id}/settings/categories") href="/contests/#{@contest.id}/settings/categories"
+ = t("contests.nav.categories")
\ No newline at end of file
diff --git a/app/views/contests/settings_categories_edit.html.slim b/app/views/contests/settings_categories_edit.html.slim
index c6953d2..ae2350e 100644
--- a/app/views/contests/settings_categories_edit.html.slim
+++ b/app/views/contests/settings_categories_edit.html.slim
@@ -1,3 +1,10 @@
+= render "params_nav"
+
+.row
+ .col
+ .alert.alert-primary role="alert"
+ = t("contests.nav.categories_description")
+
= form_with model: Category, url: "/contests/#{@contest.id}/categories" do |form|
- if @contest.categories.size > 0
.row
@@ -24,6 +31,6 @@
= form.text_field :name, autocomplete: "off", value: nil, class: "form-control"
= form.label :name, class: "required"
= t("activerecord.attributes.category.new")
- .row.mt-3
+ .row.mt-4
.col
= form.submit t("helpers.buttons.add"), class: "btn btn-primary"
\ No newline at end of file
diff --git a/app/views/contests/settings_general_edit.html.slim b/app/views/contests/settings_general_edit.html.slim
index 210eac8..c7f58fa 100644
--- a/app/views/contests/settings_general_edit.html.slim
+++ b/app/views/contests/settings_general_edit.html.slim
@@ -1,3 +1,5 @@
+= render "params_nav"
+
= form_with model: @contest, url: "/contests/#{@contest.id}/settings/general" do |form|
.row.mt-2.mb-3
.col
@@ -15,22 +17,12 @@
.form-floating
= form.select :lang, Languages::AVAILABLE_LANGUAGES.map { |lang| [ lang[:name], lang[:id] ] }, {}, class: "form-select"
= form.label :lang
- .row.mb-3
- .col
- .form-floating
- = form.select :ranking_mode, Ranking::AVAILABLE_RANKING_MODES.map { |mode| [ mode[:name], mode[:id] ] }, {}, class: "form-select"
- = form.label :ranking_mode
.row.mt-2.mb-3
.col
.form-floating
= form.text_field :code, autocomplete: "off", class: "form-control"
= form.label :code, class: "required"
.form-text = t("activerecord.attributes.contest.code_description")
- .row.mt-4.mb-3
- .col
- .form-check.form-switch
- = form.check_box :public, class: "form-check-input"
- = form.label :public
.row.mb-3 style="display: none"
.col
.form-check.form-switch
diff --git a/app/views/contests/settings_offline_edit.html.slim b/app/views/contests/settings_offline_edit.html.slim
deleted file mode 100644
index 5ce258f..0000000
--- a/app/views/contests/settings_offline_edit.html.slim
+++ /dev/null
@@ -1,25 +0,0 @@
-- if @contest.puzzles.length > 1
- .row
- .col
- .alert.alert-warning
- = t("contests.form.offline_single_puzzle_warning")
-
-- if @contest.puzzles.length <= 1
- = form_with model: @contest, url: "/contests/#{@contest.id}/settings/offline" do |form|
- .row.mt-2.mb-3
- .col
- - if @contest.puzzles.length <= 1
- .form-check.form-switch
- = form.check_box :offline_form, class: "form-check-input"
- = form.label :offline_form
- .form-text = t("activerecord.attributes.contest.offline_form_warning")
- .form-text = t("activerecord.attributes.contest.offline_form_description")
- - else
- .form-check.form-switch
- = form.check_box :offline_form_fake, class: "form-check-input", disabled: true
- = form.label :offline_form
- .form-text = t("activerecord.attributes.contest.offline_form_warning")
- .form-text = t("activerecord.attributes.contest.offline_form_description")
- .row.mt-4
- .col
- = form.submit t("helpers.buttons.update"), class: "btn btn-primary"
\ No newline at end of file
diff --git a/app/views/contests/settings_online_edit.html.slim b/app/views/contests/settings_online_edit.html.slim
new file mode 100644
index 0000000..bc00b5f
--- /dev/null
+++ b/app/views/contests/settings_online_edit.html.slim
@@ -0,0 +1,46 @@
+= render "params_nav"
+
+javascript:
+ async function copyExtensionUrlToClipboard() {
+ await navigator.clipboard.writeText("#{message_url}?token=#{@contest.generate_token_for(:token)}");
+ alert("#{t("contests.show.url_copied")}");
+ }
+
+.row.mb-4.mt-2
+ .col
+ - if @contest.offline_form && @contest.puzzles.length < 2
+ a.btn.btn-success href="/public/#{@contest.slug}/offline"
+ = t("contests.show.open_offline_form")
+ - else
+ a.btn.btn-success.disabled
+ = t("contests.show.offline_form_disabled")
+ button.btn.btn-success.ms-3 onclick="copyExtensionUrlToClipboard()"
+ css:
+ button > svg {
+ margin-right: 2px;
+ margin-top: -3px;
+ }
+
+ =< t("contests.show.copy_extension_url")
+
+= form_with model: @contest, url: "/contests/#{@contest.id}/settings/online" do |form|
+ .row.mt-2.mb-3
+ .col
+ - if @contest.puzzles.length <= 1
+ .form-check.form-switch
+ = form.check_box :offline_form, class: "form-check-input"
+ = form.label :offline_form
+ .form-text = t("activerecord.attributes.contest.offline_form_warning")
+ .form-text = t("activerecord.attributes.contest.offline_form_description")
+ - else
+ .form-check.form-switch
+ = form.check_box :offline_form_fake, class: "form-check-input", disabled: true
+ = form.label :offline_form
+ .form-text = t("activerecord.attributes.contest.offline_form_warning")
+ .form-text = t("activerecord.attributes.contest.offline_form_description")
+ .row.mt-4
+ .col
+ = form.submit t("helpers.buttons.update"), class: "btn btn-primary"
\ No newline at end of file
diff --git a/app/views/contests/settings_onsite_edit.html.slim b/app/views/contests/settings_onsite_edit.html.slim
new file mode 100644
index 0000000..c458ae1
--- /dev/null
+++ b/app/views/contests/settings_onsite_edit.html.slim
@@ -0,0 +1,12 @@
+= render "params_nav"
+
+= form_with model: @contest, url: "/contests/#{@contest.id}/settings/general" do |form|
+ .row.mt-2.mb-3
+ .col
+ .form-floating
+ = form.text_field :code, autocomplete: "off", class: "form-control"
+ = form.label :code, class: "required"
+ .form-text = t("activerecord.attributes.contest.code_description")
+ .row.mt-4
+ .col
+ = form.submit t("helpers.buttons.update"), class: "btn btn-primary"
\ No newline at end of file
diff --git a/app/views/contests/settings_public_edit.html.slim b/app/views/contests/settings_public_edit.html.slim
new file mode 100644
index 0000000..fa89bb9
--- /dev/null
+++ b/app/views/contests/settings_public_edit.html.slim
@@ -0,0 +1,17 @@
+= render "params_nav"
+
+= form_with model: @contest, url: "/contests/#{@contest.id}/settings/public" do |form|
+ .row.mt-2
+ .col
+ .form-check.form-switch
+ = form.check_box :public, class: "form-check-input"
+ = form.label :public
+ .row.mt-3
+ .col
+ .form-floating
+ = form.select :ranking_mode, Ranking::AVAILABLE_RANKING_MODES.map { |mode| [ mode[:name], mode[:id] ] }, {}, class: "form-select"
+ = form.label :ranking_mode
+
+ .row.mt-4
+ .col
+ = form.submit t("helpers.buttons.update"), class: "btn btn-primary"
\ No newline at end of file
diff --git a/app/views/layouts/authenticated.html.slim b/app/views/layouts/authenticated.html.slim
index 3c3d51d..fbfe452 100644
--- a/app/views/layouts/authenticated.html.slim
+++ b/app/views/layouts/authenticated.html.slim
@@ -5,7 +5,7 @@ html
body
.container.mt-5
- if @current_user
- .float-end style="margin-top: -8px;"
+ .float-end style="margin-top: -5px;"
nav.navbar.bg-body-primary
- if @current_user.admin
a.navbar-brand href=users_path class="btn btn-light" style="margin-right: 0"
@@ -43,12 +43,19 @@ html
.toast-body
= msg
- h1.mb-4
+ h1.mb-5
- if @contest && @contest.id.present?
= @contest.name
- if active_page("/public") == "active" && @action_path
a.ms-4.btn.btn-primary href=@action_path style="margin-top: -6px"
= t("helpers.buttons.refresh")
+ - if active_page("/contests") == "active"
+ - if @contest.public
+ a.ms-4.btn.btn-success href="/public/#{@contest.slug}" style="margin-top: -6px;"
+ = t("contests.show.open_public_scoreboard")
+ - else
+ a.ms-4.btn.btn-success.disabled style="margin-top: -6px;"
+ = t("contests.show.public_scoreboard_disabled")
- else
= @title
diff --git a/app/views/messages/index.html.slim b/app/views/messages/index.html.slim
index cd561f7..06ce732 100644
--- a/app/views/messages/index.html.slim
+++ b/app/views/messages/index.html.slim
@@ -3,6 +3,8 @@
.row.mb-4
.col
+ .alert.alert-primary
+ = t("messages.index.info")
- if @messages.length == 0
.alert.alert-warning
= t("messages.index.no_messages")
diff --git a/app/views/puzzles/index.html.slim b/app/views/puzzles/index.html.slim
index a175fa5..00b53c6 100644
--- a/app/views/puzzles/index.html.slim
+++ b/app/views/puzzles/index.html.slim
@@ -5,36 +5,38 @@
.col
a.btn.btn-primary href=new_contest_puzzle_path(@contest) style="margin-top: -3px"
| + #{t("helpers.buttons.add")}
- table.table.table-striped.table-hover
- thead
- tr
- th
- = t("activerecord.attributes.puzzle.image")
- th
- = t("activerecord.attributes.puzzle.name")
- th
- = t("activerecord.attributes.puzzle.brand")
- th
- = t("activerecord.attributes.puzzle.pieces")
- th
- = t("activerecord.attributes.puzzle.hidden")
- tbody
- - @puzzles.each do |puzzle|
- tr.align-middle scope="row"
- td
- = image_tag(puzzle.image, class: "img-fluid", style: "max-height: 128px;") if puzzle.image.attached?
- td
- = puzzle.name
- td
- = puzzle.brand
- td
- = puzzle.pieces
- td
- - if puzzle.hidden?
-
- td
- a.btn.btn-sm.btn-secondary href=edit_contest_puzzle_path(@contest, puzzle)
- = t("helpers.buttons.edit")
\ No newline at end of file
+
+ .d-flex.flex-column style="overflow-y: auto"
+ table.table.table-striped.table-hover
+ thead
+ tr
+ th
+ = t("activerecord.attributes.puzzle.image")
+ th
+ = t("activerecord.attributes.puzzle.name")
+ th
+ = t("activerecord.attributes.puzzle.brand")
+ th
+ = t("activerecord.attributes.puzzle.pieces")
+ th
+ = t("activerecord.attributes.puzzle.hidden")
+ tbody
+ - @puzzles.each do |puzzle|
+ tr.align-middle scope="row"
+ td
+ = image_tag(puzzle.image, class: "img-fluid", style: "max-height: 128px;") if puzzle.image.attached?
+ td
+ = puzzle.name
+ td
+ = puzzle.brand
+ td
+ = puzzle.pieces
+ td
+ - if puzzle.hidden?
+
+ td
+ a.btn.btn-sm.btn-secondary href=edit_contest_puzzle_path(@contest, puzzle)
+ = t("helpers.buttons.edit")
\ No newline at end of file
diff --git a/config/locales/en.yml b/config/locales/en.yml
index a36b145..a7c64ed 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -193,14 +193,19 @@ en:
notice: Contest updated
title: Edit contest settings
form:
- categories: Participant categories
- general: General parameters
- offline: Offline participation
offline_single_puzzle_warning: This is not available for contests with more than one puzzle
index:
title: Welcome %{username}!
manage_contests: Manage my contests
new_contest: Create a new contest
+ nav:
+ categories: Participant categories
+ categories_description: Once you add categories, you will be able to assign them to participants on their profiles, and a filter for categories will be available on the public scoreboard
+ general: General
+ online: Online contests
+ onsite: Onsite contests
+ public: Public scoreboard
+ settings: Settings
new:
notice: Contest added
title: New jigsaw puzzle contest
@@ -287,10 +292,11 @@ en:
rank: Rank
lib:
ranking:
- actual: First by number of pieces assembled, then by time
+ actual: First by number of pieces assembled, then by time (recommended if unsure)
theorical: By time only (projected time calculated with the ppm count)
messages:
index:
+ info: This section is only used for contests that rely on the connection with Google Meet
no_messages: No messages received yet
convert:
title: New completion
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 548083b..84e1d0c 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -164,14 +164,19 @@ fr:
notice: Concours modifié
title: Paramètres du concours
form:
- categories: Catégories de participant.e.s
- general: Paramètres généraux
- offline: Participation hors-ligne
offline_single_puzzle_warning: Ce n'est pas activable pour les concours avec plusieurs puzzles
index:
title: Bienvenue %{username} !
manage_contests: Mes concours de puzzle
new_contest: Créer un nouveau concours
+ nav:
+ categories: Catégories de participant.e.s
+ categories_description: Après avoir ajouté des catégories, elles pourront être attributées aux participant.e.s sur leurs profils, et un filtre sera disponible sur le classement public
+ general: Général
+ online: Concours en ligne
+ onsite: Concours en présentiel
+ public: Classement public
+ settings: Paramètres
new:
notice: Concours ajouté
title: Nouveau concours
@@ -258,10 +263,11 @@ fr:
rank: Rang
lib:
ranking:
- actual: Par nombre de pièces assemblées, puis par temps
+ actual: Par nombre de pièces assemblées, puis par temps (recommandé)
theorical: Par temps uniquement (temps projeté calculé à partir de la vitesse d'assemblage)
messages:
index:
+ info: Cette section n'est pertinente que pour les concours en ligne qui utilisent la connexion depuis Google Meet
no_messages: Pas de messages reçus pour le moment
convert:
title: Ajout d'une complétion
diff --git a/config/routes.rb b/config/routes.rb
index fe112da..dc23263 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -11,8 +11,12 @@ Rails.application.routes.draw do
resources :contests do
get "settings/general", to: "contests#settings_general_edit"
patch "settings/general", to: "contests#settings_general_update"
- get "settings/offline", to: "contests#settings_offline_edit"
- patch "settings/offline", to: "contests#settings_offline_update"
+ get "settings/public", to: "contests#settings_public_edit"
+ patch "settings/public", to: "contests#settings_public_update"
+ get "settings/onsite", to: "contests#settings_onsite_edit"
+ patch "settings/onsite", to: "contests#settings_onsite_update"
+ get "settings/online", to: "contests#settings_online_edit"
+ patch "settings/online", to: "contests#settings_online_update"
get "settings/categories", to: "contests#settings_categories_edit"
resources :categories, only: [ :create, :destroy ]
resources :completions