Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/controllers/contest_descriptions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ def handle_save(success, action)
format.turbo_stream {
render turbo_stream: turbo_stream.replace('contest_description_form', partial: 'contest_descriptions/form', locals: { contest_description: @contest_description }), status: :unprocessable_entity
}
format.html { render action_name.to_sym, status: :unprocessable_entity }
format.html {
template = action_name == 'create' ? :new : :edit
render template, status: :unprocessable_entity
}
end
end
end
Expand Down
26 changes: 17 additions & 9 deletions app/controllers/entry_rankings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,18 @@ def select_for_next_round
authorize @entry_ranking, :select_for_next_round?

selected = params[:selected_for_next_round] == '1'
Rails.logger.debug { "Selected value before update: #{selected}" }

if @entry_ranking.update_column(:selected_for_next_round, selected)
Rails.logger.debug { "Value after update: #{@entry_ranking.reload.selected_for_next_round}" }
# Update ALL rankings for this entry in this round, not just one
entry = @entry_ranking.entry
judging_round = @entry_ranking.judging_round

# Update all rankings for this entry
updated = EntryRanking.where(entry: entry, judging_round: judging_round)
.update_all(selected_for_next_round: selected)

if updated > 0
Rails.logger.info { "Updated #{updated} rankings for entry #{entry.id} - selected_for_next_round: #{selected}" }

respond_to do |format|
format.html {
redirect_back(fallback_location: container_contest_description_contest_instance_judging_round_path(
Expand All @@ -57,11 +65,11 @@ def select_for_next_round
flash.now[:notice] = 'Entry selection updated successfully'
render turbo_stream: [
turbo_stream.replace(
"selected_for_next_round_#{@entry_ranking.entry.id}",
"selected_for_next_round_#{entry.id}",
partial: 'judging_rounds/entry_checkbox',
locals: {
entry: @entry_ranking.entry,
judging_round: @judging_round,
entry: entry,
judging_round: judging_round,
container: @container,
contest_description: @contest_description,
contest_instance: @contest_instance
Expand All @@ -80,11 +88,11 @@ def select_for_next_round
}
format.turbo_stream {
render turbo_stream: turbo_stream.replace(
"selected_for_next_round_#{@entry_ranking.entry.id}",
"selected_for_next_round_#{entry.id}",
partial: 'judging_rounds/entry_checkbox',
locals: {
entry: @entry_ranking.entry,
judging_round: @judging_round,
entry: entry,
judging_round: judging_round,
container: @container,
contest_description: @contest_description,
contest_instance: @contest_instance
Expand Down
40 changes: 25 additions & 15 deletions app/controllers/judge_dashboard_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,35 @@ class JudgeDashboardController < ApplicationController
def index
authorize :judge_dashboard

# Find contest instances where the judge has at least one active assignment to an incomplete round
contest_instances_with_incomplete_assigned_rounds = JudgingRound
.joins(:round_judge_assignments)
.where(completed: false)
.where(round_judge_assignments: { user_id: current_user.id, active: true })
.select(:contest_instance_id)
.distinct

@judging_assignments = current_user.judging_assignments
.includes(contest_instance: [
contest_description: [ :container ],
judging_rounds: [ :round_judge_assignments ],
entries: [ :entry_rankings ]
])
.where(active: true)
.order('judging_rounds.round_number ASC')
.joins(:contest_instance)
.includes(contest_instance: [
contest_description: [ :container ],
judging_rounds: [ :round_judge_assignments ],
entries: [ :entry_rankings ]
])
.where(judging_assignments: { active: true })
.where(contest_instances: { active: true, id: contest_instances_with_incomplete_assigned_rounds })
.order('judging_rounds.round_number ASC')

# Filter to only include rounds that are active and the judge is actively assigned to
@assigned_rounds = JudgingRound.joins(:round_judge_assignments)
.where(
active: true,
round_judge_assignments: {
user_id: current_user.id,
active: true
}
)
.where(contest_instance_id: @judging_assignments.pluck(:contest_instance_id))
.where(
active: true,
round_judge_assignments: {
user_id: current_user.id,
active: true
}
)
.where(contest_instance_id: @judging_assignments.pluck(:contest_instance_id))

@entry_rankings = EntryRanking.includes(:judging_round)
.where(user: current_user)
Expand Down
69 changes: 69 additions & 0 deletions app/javascript/controllers/contest_activation_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static targets = ["activeCheckbox", "submitButton"]
static values = {
isNewRecord: Boolean,
confirmMessage: String
}

connect() {
console.log("contest-activation controller connected")
console.log("isNewRecord:", this.isNewRecordValue)
console.log("hasSubmitButtonTarget:", this.hasSubmitButtonTarget)
if (this.isNewRecordValue && this.hasSubmitButtonTarget) {
this.submitButtonTarget.addEventListener('click', this.handleButtonClick.bind(this))
console.log("Event listener added to submit button")
}
}

handleButtonClick(event) {
console.log("=== handleButtonClick called ===")
console.log("isNewRecord:", this.isNewRecordValue)
console.log("checkbox checked:", this.activeCheckboxTarget.checked)

// Only prompt for new records (creation)
if (!this.isNewRecordValue) {
console.log("Not a new record, returning")
return
}

// If active checkbox is already checked, proceed normally
if (this.activeCheckboxTarget.checked) {
console.log("Checkbox already checked, proceeding normally")
return
}

// Prevent the default form submission temporarily
event.preventDefault()

// Show confirmation dialog synchronously
const message = this.confirmMessageValue ||
"This contest will be created as inactive. Would you like to make it active now? " +
"Active contests allow administrators to manage entries and judges to provide feedback during their assigned periods."

const userConfirmed = confirm(message)
console.log("User confirmed:", userConfirmed)

if (userConfirmed) {
// User wants to activate - check the checkbox
this.activeCheckboxTarget.checked = true
console.log("Checkbox set to checked")
} else {
console.log("User cancelled, checkbox remains unchecked")
}

// Now submit the form using requestSubmit to trigger proper form validation
console.log("Submitting form using requestSubmit")
if (this.submitButtonTarget.form.requestSubmit) {
this.submitButtonTarget.form.requestSubmit(this.submitButtonTarget)
} else {
// Fallback for older browsers
this.submitButtonTarget.form.submit()
}
}

checkActivation(event) {
// This method is no longer used
}
}
3 changes: 3 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ application.register("comments-counter", CommentsCounterController)
import ConfirmController from "./confirm_controller"
application.register("confirm", ConfirmController)

import ContestActivationController from "./contest_activation_controller"
application.register("contest-activation", ContestActivationController)

import DropdownController from "./dropdown_controller"
application.register("dropdown", DropdownController)

Expand Down
14 changes: 11 additions & 3 deletions app/views/contest_descriptions/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<div id="contest_description_form" class="mb-1">
<%= simple_form_for([@container, @contest_description],
html: {
id: 'new_contest_description_form'
id: 'new_contest_description_form',
data: {
controller: "contest-activation",
contest_activation_is_new_record_value: @contest_description.new_record?
}
}) do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
Expand All @@ -12,11 +16,15 @@
<%= f.input :eligibility_rules, as: :rich_text_area, hint: "These notes display on the applicant entry form and on the assigned judges' dashboard" %>
<%= f.input :notes, as: :rich_text_area, hint: "These notes are not visible on the applicant entry form" %>
<%= f.input :short_name %>
<%= f.input :active, hint: "Toggle this checkbox to make the contest active. When active, administrators will be able to manage the submitted entries. Judges, during their assigned judging period, will be able to view the entries and provide feedback. Note that the contest's instances availabilty for submissions will follow the visibility settings based on specific dates configured in each contest instance. If this checkbox is unchecked, the contest and its instances will remain inactive and hidden from evaluation workflows." %>
<%= f.input :active,
hint: "Toggle this checkbox to make the contest active. When active, administrators will be able to manage the submitted entries. Judges, during their assigned judging period, will be able to view the entries and provide feedback. Note that the contest's instances availabilty for submissions will follow the visibility settings based on specific dates configured in each contest instance. If this checkbox is unchecked, the contest and its instances will remain inactive and hidden from evaluation workflows.",
input_html: { data: { contest_activation_target: "activeCheckbox" } } %>
</div>

<div class="form-actions">
<%= f.button :submit, (f.object.new_record? ? "Create Contest" : "Update Contest"), class: "btn btn-primary" %>
<%= f.button :submit, (f.object.new_record? ? "Create Contest" : "Update Contest"),
class: "btn btn-primary",
data: { contest_activation_target: "submitButton" } %>
<%= link_to "Cancel", (f.object.new_record? ? container_path(@container) : container_contest_description_contest_instances_path(@container, @contest_description)), class: "text-danger link_to" %>
</div>
<% end %>
Expand Down
14 changes: 10 additions & 4 deletions app/views/contest_instances/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<%= simple_form_for([@container, @contest_description, @contest_instance],
html: {
data: {
controller: "form-validation",
controller: "form-validation contest-activation",
action: "submit->form-validation#submitForm",
form_validation_target: "form"
form_validation_target: "form",
contest_activation_is_new_record_value: @contest_instance.new_record?,
contest_activation_confirm_message_value: "This contest instance will be created as inactive. Would you like to make it active now? Active instances accept entries during the specified open and close dates."
}
}) do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>

<div class="form-inputs">
<%= f.input :active, hint: "Specify whether this contest is currently accepting entries during the contest open and close dates specified below." %>
<%= f.input :active,
hint: "Specify whether this contest is currently accepting entries during the contest open and close dates specified below.",
input_html: { data: { contest_activation_target: "activeCheckbox" } } %>
<%= f.association :contest_description, label_method: :name %>
<div class="row">
<div class="col-md-6">
Expand Down Expand Up @@ -120,7 +124,9 @@
</div>

<div class="form-actions py-2">
<%= f.button :submit, class: "btn btn-primary" %>
<%= f.button :submit,
class: "btn btn-primary",
data: { contest_activation_target: "submitButton" } %>
<%= link_to "Cancel", (f.object.new_record? ? container_contest_description_contest_instances_path(@container, @contest_description) : container_contest_description_contest_instance_path(@container, @contest_description, @contest_instance)), class: "text-danger link_to" %>
</div>
<% end %>
Loading
Loading