Revamp contest settings into tabs
This commit is contained in:
@@ -8,9 +8,9 @@ class CategoriesController < ApplicationController
|
||||
@category = Category.new(category_params)
|
||||
@category.contest_id = @contest.id
|
||||
if @category.save
|
||||
redirect_to edit_contest_path(@contest), notice: t("categories.new.notice")
|
||||
redirect_to "/contests/#{@contest.id}/settings/categories", notice: t("categories.new.notice")
|
||||
else
|
||||
redirect_to edit_contest_path(@contest), notice: t("categories.new.error")
|
||||
redirect_to "/contests/#{@contest.id}/settings/categories", notice: t("categories.new.error")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -18,7 +18,7 @@ class CategoriesController < ApplicationController
|
||||
authorize @contest
|
||||
|
||||
@category.destroy
|
||||
redirect_to edit_contest_path(@contest), notice: t("categories.destroy.notice")
|
||||
redirect_to "/contests/#{@contest.id}/settings/categories", notice: t("categories.destroy.notice")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -2,6 +2,7 @@ class ContestsController < ApplicationController
|
||||
include CompletionsConcern
|
||||
|
||||
before_action :set_contest, only: %i[ destroy edit show update ]
|
||||
before_action :set_settings_contest, only: %i[ settings_general_edit settings_general_update settings_offline_edit settings_offline_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 ]
|
||||
|
||||
@@ -16,8 +17,8 @@ class ContestsController < ApplicationController
|
||||
authorize @contest
|
||||
|
||||
@title = I18n.t("contests.show.title", name: @contest.name)
|
||||
@action_name = t("helpers.buttons.edit")
|
||||
@action_path = edit_contest_path(@contest)
|
||||
@action_name = t("helpers.buttons.settings")
|
||||
@action_path = "/contests/#{@contest.id}/settings/general"
|
||||
@contestants = @contest.contestants.sort_by { |contestant| [
|
||||
-contestant.completions.where(remaining_pieces: nil).size,
|
||||
(contestant.completions.where(remaining_pieces: nil).size == @contest.puzzles.length ? 1 : 0) * contestant.time_seconds,
|
||||
@@ -37,6 +38,56 @@ class ContestsController < ApplicationController
|
||||
@action_path = contest_path(@contest)
|
||||
end
|
||||
|
||||
def settings_general_edit
|
||||
authorize @contest
|
||||
|
||||
@action_name = t("helpers.buttons.back")
|
||||
@action_path = contest_path(@contest)
|
||||
@title = t("contests.edit.title")
|
||||
end
|
||||
|
||||
def settings_offline_edit
|
||||
authorize @contest
|
||||
|
||||
@action_name = t("helpers.buttons.back")
|
||||
@action_path = contest_path(@contest)
|
||||
@title = t("contests.edit.title")
|
||||
end
|
||||
|
||||
def settings_categories_edit
|
||||
authorize @contest
|
||||
|
||||
@action_name = t("helpers.buttons.back")
|
||||
@action_path = contest_path(@contest)
|
||||
@title = t("contests.edit.title")
|
||||
end
|
||||
|
||||
def settings_general_update
|
||||
authorize @contest
|
||||
|
||||
if @contest.update(settings_general_params)
|
||||
redirect_to "/contests/#{@contest.id}/settings/general", notice: t("contests.edit.notice")
|
||||
else
|
||||
@action_name = t("helpers.buttons.back")
|
||||
@action_path = contest_path(@contest)
|
||||
@title = t("contests.edit.title")
|
||||
render :settings_general_edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def settings_offline_update
|
||||
authorize @contest
|
||||
|
||||
if @contest.update(settings_offline_params)
|
||||
redirect_to "/contests/#{@contest.id}/settings/offline", notice: t("contests.edit.notice")
|
||||
else
|
||||
@action_name = t("helpers.buttons.back")
|
||||
@action_path = contest_path(@contest)
|
||||
@title = t("contests.edit.title")
|
||||
render :settings_offline_edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
authorize :contest
|
||||
|
||||
@@ -49,7 +100,7 @@ class ContestsController < ApplicationController
|
||||
@contest = Contest.new(contest_params)
|
||||
@contest.user_id = current_user.id
|
||||
if @contest.save
|
||||
redirect_to @contest, notice: t("contests.new.notice")
|
||||
redirect_to "/contests/#{@contest.id}/settings/general", notice: t("contests.new.notice")
|
||||
else
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
@@ -199,10 +250,22 @@ class ContestsController < ApplicationController
|
||||
@contest = Contest.find(params[:id])
|
||||
end
|
||||
|
||||
def set_settings_contest
|
||||
@contest = Contest.find(params[:contest_id])
|
||||
end
|
||||
|
||||
def contest_params
|
||||
params.expect(contest: [ :lang, :name, :offline_form, :public, :team, :allow_registration ])
|
||||
end
|
||||
|
||||
def settings_general_params
|
||||
params.expect(contest: [ :lang, :name, :public, :team, :allow_registration ])
|
||||
end
|
||||
|
||||
def settings_offline_params
|
||||
params.expect(contest: [ :offline_form ])
|
||||
end
|
||||
|
||||
def filter_contestants_per_category
|
||||
if params.key?(:category) && params[:category] != "-1"
|
||||
if params[:category] == "-2"
|
||||
|
||||
5
app/helpers/style_helper.rb
Normal file
5
app/helpers/style_helper.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
module StyleHelper
|
||||
def active_page(path)
|
||||
request.path.starts_with?(path) ? "active" : ""
|
||||
end
|
||||
end
|
||||
@@ -27,6 +27,26 @@ class ContestPolicy < ApplicationPolicy
|
||||
record.user.id == user.id || user.admin?
|
||||
end
|
||||
|
||||
def settings_general_edit?
|
||||
edit?
|
||||
end
|
||||
|
||||
def settings_general_update?
|
||||
edit?
|
||||
end
|
||||
|
||||
def settings_offline_edit?
|
||||
edit?
|
||||
end
|
||||
|
||||
def settings_offline_update?
|
||||
edit?
|
||||
end
|
||||
|
||||
def settings_categories_edit?
|
||||
edit?
|
||||
end
|
||||
|
||||
def finalize_import?
|
||||
record.user.id == user.id || user.admin?
|
||||
end
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
h4.mt-5 = t("contests.form.general")
|
||||
= form_with model: contest do |form|
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :name, autocomplete: "off", class: "form-control"
|
||||
= form.label :name, class: "required"
|
||||
.row.mb-3
|
||||
.col
|
||||
.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-check.form-switch
|
||||
= form.check_box :public, class: "form-check-input"
|
||||
= form.label :public
|
||||
.row.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.mb-3
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :team, class: "form-check-input"
|
||||
= form.label :team
|
||||
.form-text = t("activerecord.attributes.contest.team_description")
|
||||
.row.mb-3 style="display: none"
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :allow_registration, class: "form-check-input"
|
||||
= form.label :allow_registration
|
||||
.form-text = t("activerecord.attributes.contest.allow_registration_description")
|
||||
.row
|
||||
.col
|
||||
= form.submit submit_text, class: "btn btn-primary"
|
||||
|
||||
|
||||
h4.mt-5 = t("contests.form.categories")
|
||||
|
||||
= form_with model: Category, url: "/contests/#{@contest.id}/categories" do |form|
|
||||
- if @contest.categories.size > 0
|
||||
.row
|
||||
.col-6
|
||||
table.table.table-striped.table-hover
|
||||
thead
|
||||
tr
|
||||
th
|
||||
= t("activerecord.attributes.category.name")
|
||||
th
|
||||
= t("activerecord.attributes.category.contestant_count")
|
||||
tbody
|
||||
- @contest.categories.each do |category|
|
||||
tr.align-middle scope="row"
|
||||
td
|
||||
= category.name
|
||||
td
|
||||
= category.contestants.size
|
||||
td
|
||||
= link_to t("helpers.buttons.delete"), contest_category_path(@contest, category), data: { turbo_method: :delete }, class: "btn btn-sm btn-danger ms-2"
|
||||
.row.mt-3
|
||||
.col-4
|
||||
.form-floating
|
||||
= form.text_field :name, autocomplete: "off", value: nil, class: "form-control"
|
||||
= form.label :name, class: "required"
|
||||
= t("activerecord.attributes.category.new")
|
||||
.row.mt-3
|
||||
.col
|
||||
= form.submit t("helpers.buttons.add"), class: "btn btn-primary"
|
||||
12
app/views/contests/_settings_nav.html.slim
Normal file
12
app/views/contests/_settings_nav.html.slim
Normal file
@@ -0,0 +1,12 @@
|
||||
.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.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")
|
||||
@@ -1 +0,0 @@
|
||||
= render "form", contest: @contest, submit_text: t("helpers.buttons.save")
|
||||
@@ -1 +1,9 @@
|
||||
= render "form", contest: @contest, submit_text: t("helpers.buttons.create")
|
||||
= form_with model: @contest do |form|
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :name, autocomplete: "off", class: "form-control"
|
||||
= form.label :name, class: "required"
|
||||
.row.mt-4
|
||||
.col
|
||||
= form.submit t("helpers.buttons.create"), class: "btn btn-primary"
|
||||
31
app/views/contests/settings_categories_edit.html.slim
Normal file
31
app/views/contests/settings_categories_edit.html.slim
Normal file
@@ -0,0 +1,31 @@
|
||||
= render "settings_nav"
|
||||
|
||||
= form_with model: Category, url: "/contests/#{@contest.id}/categories" do |form|
|
||||
- if @contest.categories.size > 0
|
||||
.row
|
||||
.col-6
|
||||
table.table.table-striped.table-hover
|
||||
thead
|
||||
tr
|
||||
th
|
||||
= t("activerecord.attributes.category.name")
|
||||
th
|
||||
= t("activerecord.attributes.category.contestant_count")
|
||||
tbody
|
||||
- @contest.categories.each do |category|
|
||||
tr.align-middle scope="row"
|
||||
td
|
||||
= category.name
|
||||
td
|
||||
= category.contestants.size
|
||||
td
|
||||
= link_to t("helpers.buttons.delete"), contest_category_path(@contest, category), data: { turbo_method: :delete }, class: "btn btn-sm btn-danger ms-2"
|
||||
.row.mt-3
|
||||
.col-4
|
||||
.form-floating
|
||||
= form.text_field :name, autocomplete: "off", value: nil, class: "form-control"
|
||||
= form.label :name, class: "required"
|
||||
= t("activerecord.attributes.category.new")
|
||||
.row.mt-3
|
||||
.col
|
||||
= form.submit t("helpers.buttons.add"), class: "btn btn-primary"
|
||||
33
app/views/contests/settings_general_edit.html.slim
Normal file
33
app/views/contests/settings_general_edit.html.slim
Normal file
@@ -0,0 +1,33 @@
|
||||
= render "settings_nav"
|
||||
|
||||
= form_with model: @contest, url: "/contests/#{@contest.id}/settings/general" do |form|
|
||||
.row.mt-2.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :name, autocomplete: "off", class: "form-control"
|
||||
= form.label :name, class: "required"
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.select :lang, Languages::AVAILABLE_LANGUAGES.map { |lang| [ lang[:name], lang[:id] ] }, {}, class: "form-select"
|
||||
= form.label :lang
|
||||
.row.mt-4.mb-3
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :public, class: "form-check-input"
|
||||
= form.label :public
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :team, class: "form-check-input"
|
||||
= form.label :team
|
||||
.form-text = t("activerecord.attributes.contest.team_description")
|
||||
.row.mb-3 style="display: none"
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :allow_registration, class: "form-check-input"
|
||||
= form.label :allow_registration
|
||||
.form-text = t("activerecord.attributes.contest.allow_registration_description")
|
||||
.row.mt-4
|
||||
.col
|
||||
= form.submit t("helpers.buttons.update"), class: "btn btn-primary"
|
||||
20
app/views/contests/settings_offline_edit.html.slim
Normal file
20
app/views/contests/settings_offline_edit.html.slim
Normal file
@@ -0,0 +1,20 @@
|
||||
= render "settings_nav"
|
||||
|
||||
= 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"
|
||||
@@ -176,6 +176,7 @@ en:
|
||||
form:
|
||||
categories: Participant categories
|
||||
general: General parameters
|
||||
offline: Offline participation
|
||||
index:
|
||||
title: Welcome %{username}!
|
||||
manage_contests: Manage my contests
|
||||
@@ -249,9 +250,11 @@ en:
|
||||
import: CSV Import
|
||||
open: Open
|
||||
refresh: Refresh
|
||||
settings: Settings
|
||||
sign_in: Sign in
|
||||
save: Save
|
||||
start: Click here to start your participation
|
||||
update: Save modifications
|
||||
field: Field
|
||||
none: No field selected
|
||||
rank: Rank
|
||||
@@ -266,7 +269,7 @@ en:
|
||||
nav:
|
||||
users: Users
|
||||
home: My contests
|
||||
settings: Settings
|
||||
settings: My account
|
||||
log_out: Log out
|
||||
offlines:
|
||||
form:
|
||||
|
||||
@@ -147,6 +147,7 @@ fr:
|
||||
form:
|
||||
categories: Catégories de participant.e.s
|
||||
general: Paramètres généraux
|
||||
offline: Participation hors-ligne
|
||||
index:
|
||||
title: Bienvenue %{username} !
|
||||
manage_contests: Mes concours de puzzle
|
||||
@@ -220,9 +221,11 @@ fr:
|
||||
import: Importer un CSV
|
||||
open: Détails
|
||||
refresh: Rafraîchir
|
||||
settings: Paramètres
|
||||
sign_in: Se connecter
|
||||
save: Modifier
|
||||
start: Clique ici pour démarrer ta participation
|
||||
update: Enregistrer les modifications
|
||||
field: Champ
|
||||
none: Aucun champ sélectionné
|
||||
rank: Rang
|
||||
@@ -237,7 +240,7 @@ fr:
|
||||
nav:
|
||||
users: Utilisateur.ices
|
||||
home: Mes concours
|
||||
settings: Paramètres
|
||||
settings: Mon compte
|
||||
log_out: Déconnexion
|
||||
offlines:
|
||||
form:
|
||||
|
||||
@@ -9,6 +9,11 @@ Rails.application.routes.draw do
|
||||
root "contests#index"
|
||||
|
||||
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/categories", to: "contests#settings_categories_edit"
|
||||
resources :categories, only: [ :create, :destroy ]
|
||||
resources :completions
|
||||
resources :contestants
|
||||
|
||||
Reference in New Issue
Block a user