diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 91e3528..632ef2c 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -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 diff --git a/app/controllers/contests_controller.rb b/app/controllers/contests_controller.rb index 418b8bb..8608d51 100644 --- a/app/controllers/contests_controller.rb +++ b/app/controllers/contests_controller.rb @@ -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" diff --git a/app/helpers/style_helper.rb b/app/helpers/style_helper.rb new file mode 100644 index 0000000..a6ea0bf --- /dev/null +++ b/app/helpers/style_helper.rb @@ -0,0 +1,5 @@ +module StyleHelper + def active_page(path) + request.path.starts_with?(path) ? "active" : "" + end +end diff --git a/app/policies/contest_policy.rb b/app/policies/contest_policy.rb index d973f49..332185d 100644 --- a/app/policies/contest_policy.rb +++ b/app/policies/contest_policy.rb @@ -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 diff --git a/app/views/contests/_form.html.slim b/app/views/contests/_form.html.slim deleted file mode 100644 index b10a5b3..0000000 --- a/app/views/contests/_form.html.slim +++ /dev/null @@ -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" \ No newline at end of file diff --git a/app/views/contests/_settings_nav.html.slim b/app/views/contests/_settings_nav.html.slim new file mode 100644 index 0000000..e9f4952 --- /dev/null +++ b/app/views/contests/_settings_nav.html.slim @@ -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") \ No newline at end of file diff --git a/app/views/contests/edit.html.slim b/app/views/contests/edit.html.slim deleted file mode 100644 index 3f099f5..0000000 --- a/app/views/contests/edit.html.slim +++ /dev/null @@ -1 +0,0 @@ -= render "form", contest: @contest, submit_text: t("helpers.buttons.save") \ No newline at end of file diff --git a/app/views/contests/new.html.slim b/app/views/contests/new.html.slim index fdbdabc..fe4fea8 100644 --- a/app/views/contests/new.html.slim +++ b/app/views/contests/new.html.slim @@ -1 +1,9 @@ -= render "form", contest: @contest, submit_text: t("helpers.buttons.create") \ No newline at end of file += 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" \ 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 new file mode 100644 index 0000000..142dbf3 --- /dev/null +++ b/app/views/contests/settings_categories_edit.html.slim @@ -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" \ 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 new file mode 100644 index 0000000..8511ea5 --- /dev/null +++ b/app/views/contests/settings_general_edit.html.slim @@ -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" \ No newline at end of file diff --git a/app/views/contests/settings_offline_edit.html.slim b/app/views/contests/settings_offline_edit.html.slim new file mode 100644 index 0000000..be8a866 --- /dev/null +++ b/app/views/contests/settings_offline_edit.html.slim @@ -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" \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 11ab007..2e6779b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 27357c8..85b72ad 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -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: diff --git a/config/routes.rb b/config/routes.rb index e05898b..908ffa3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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