diff --git a/app/assets/stylesheets/pages/admin/_mission_submissions.scss b/app/assets/stylesheets/pages/admin/_mission_submissions.scss index 798ce131d..76a5cdc84 100644 --- a/app/assets/stylesheets/pages/admin/_mission_submissions.scss +++ b/app/assets/stylesheets/pages/admin/_mission_submissions.scss @@ -830,6 +830,26 @@ resize: vertical; } + &__detach { + display: flex; + flex-direction: column; + gap: var(--space-xxs); + } + + &__detach-option { + display: flex; + align-items: center; + gap: var(--space-xs); + cursor: pointer; + font-size: 0.95rem; + } + + &__detach-hint { + font-size: 0.85rem; + color: var(--muted); + margin: 0; + } + &__payout-note { font-size: 0.9rem; color: var(--color-brand-yellow); diff --git a/app/controllers/admin/missions/submissions_controller.rb b/app/controllers/admin/missions/submissions_controller.rb index 8c49ba06f..0ea137958 100644 --- a/app/controllers/admin/missions/submissions_controller.rb +++ b/app/controllers/admin/missions/submissions_controller.rb @@ -93,6 +93,10 @@ def update alert: "This submission can't be #{new_status} right now." and return end + detach_requested = new_status == "rejected" && + ActiveModel::Type::Boolean.new.cast(params.dig(:mission_submission, :detach_project)) + detached = false + Mission::Submission.transaction do if new_status == "approved" @submission.update!(reviewed_by: current_user, reviewed_at: Time.current, rejection_message: nil) @@ -102,14 +106,16 @@ def update else @submission.update!(reviewed_by: current_user, reviewed_at: Time.current, rejection_message: feedback) @submission.reject! + detached = detach_submission_project! if detach_requested end end notify_builder(new_status) reviewed = Mission::Submission.reviewed_today(current_user, mission: @mission) + verdict = detached ? "Rejected and detached the project" : new_status.titleize redirect_to next_admin_mission_submissions_path(mission_slug), - notice: "#{new_status.titleize}. That's #{reviewed} reviewed today." + notice: "#{verdict}. That's #{reviewed} reviewed today." end def next @@ -281,6 +287,20 @@ def reverse_fixed_stardust_if_granted ) end + # Detaches the submission's project from the mission it was rejected on, + # but only while that mission is still the project's current one — so we + # never yank a mission the builder has since swapped to. Returns whether + # a detach actually happened. The MissionAttachment change is versioned + # by PaperTrail (whodunnit set in the admin controller chain). + def detach_submission_project! + project = @submission.ship_event&.post&.project + return false unless project + return false unless project.current_mission == @submission.mission + + project.detach_mission! + true + end + def notify_builder(status) builder = @submission.ship_event&.post&.user return unless builder diff --git a/app/views/admin/missions/submissions/_form.html.erb b/app/views/admin/missions/submissions/_form.html.erb index 210c3bc95..6c037a1d6 100644 --- a/app/views/admin/missions/submissions/_form.html.erb +++ b/app/views/admin/missions/submissions/_form.html.erb @@ -21,6 +21,17 @@ placeholder: "Required for rejections. Optional for approvals." %> +
+ Only applies when rejecting. Frees the project from <%= mission.name %> so + the builder can pick a different mission. +
+