From e762bb6e9b9abf2a0c4ae9b7acbc4f9e88ce9605 Mon Sep 17 00:00:00 2001 From: Fiona Date: Tue, 7 Oct 2025 11:54:58 -0400 Subject: [PATCH 1/2] Add ability to update puzzles from the admin table --- app/assets/stylesheets/application.css | 50 +++++++++++++++++-- app/controllers/puzzles_controller.rb | 27 ++++++++++ .../controllers/modal_controller.js | 11 ++++ app/views/layouts/application.html.erb | 1 + app/views/puzzles/_form.html.erb | 30 +++++++++++ app/views/puzzles/_puzzles_table.html.erb | 6 ++- app/views/puzzles/edit.html.erb | 15 ++++++ app/views/puzzles/update.turbo_stream.erb | 25 ++++++++++ config/routes.rb | 2 +- 9 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 app/javascript/controllers/modal_controller.js create mode 100644 app/views/puzzles/_form.html.erb create mode 100644 app/views/puzzles/edit.html.erb create mode 100644 app/views/puzzles/update.turbo_stream.erb diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 2b9e313..25a39b1 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -72,11 +72,11 @@ th { background-color: #4CAF50; } -.reject-btn { +.reject-btn, .close-btn { background-color: #f44336; } -.pending-btn { +.pending-btn, .edit-btn { background-color: yellow; color: black; } @@ -109,4 +109,48 @@ th { .banner-message.alert { background-color: #fff3cd; color: #856404; -} \ No newline at end of file +} + +/* full screen overlay */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.5); /* semi-transparent black */ + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; +} + +/* modal content box */ +.modal-content { + background-color: white; + padding: 1.5rem; + border-radius: 0.5rem; + min-width: 300px; + max-width: 600px; + box-shadow: 0 4px 12px rgba(0,0,0,0.3); +} + +.modal-area { + display: flex; + flex-direction: column; + margin-bottom: 1rem; +} + +/* Horizontal radio buttons for puzzle answer */ +.answer-radio-group { + display: flex; + gap: 1.5em; + align-items: center; +} +.answer-radio-group label { + display: flex; + align-items: center; + gap: 0.3em; +} + + diff --git a/app/controllers/puzzles_controller.rb b/app/controllers/puzzles_controller.rb index d23ef29..72380c5 100644 --- a/app/controllers/puzzles_controller.rb +++ b/app/controllers/puzzles_controller.rb @@ -9,4 +9,31 @@ def index @rejected_puzzles = Puzzle.rejected @archived_puzzles = Puzzle.archived end + + def edit + @puzzle = Puzzle.find(params[:id]) + end + + def update + @puzzle = Puzzle.find(params[:id]) + if @puzzle.update(puzzle_params) + respond_to do |format| + format.turbo_stream + format.html { redirect_to puzzles_path, notice: "Puzzle updated." } + format.json { render json: { success: true, puzzle: @puzzle } } + end + else + respond_to do |format| + format.turbo_stream { render turbo_stream: turbo_stream.replace(@puzzle, partial: "puzzles/form", locals: { puzzle: @puzzle }) } + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: { success: false, errors: @puzzle.errors.full_messages }, status: :unprocessable_entity } + end + end + end + + private + + def puzzle_params + params.require(:puzzle).permit(:question, :answer, :explanation, :link) + end end diff --git a/app/javascript/controllers/modal_controller.js b/app/javascript/controllers/modal_controller.js new file mode 100644 index 0000000..831d917 --- /dev/null +++ b/app/javascript/controllers/modal_controller.js @@ -0,0 +1,11 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ["content"] + + close(event) { + if (event.target.dataset.action === "modal#close") { + this.element.remove() + } + } +} diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index e91ec44..3af3fed 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -33,5 +33,6 @@ <% end %> <%= yield %> + diff --git a/app/views/puzzles/_form.html.erb b/app/views/puzzles/_form.html.erb new file mode 100644 index 0000000..a342f8c --- /dev/null +++ b/app/views/puzzles/_form.html.erb @@ -0,0 +1,30 @@ +<%=form_with model: @puzzle do |f| %> + + + + + + + + + <%= f.submit "Save", class: "btn approve-btn" %> +<% end %> diff --git a/app/views/puzzles/_puzzles_table.html.erb b/app/views/puzzles/_puzzles_table.html.erb index a691e41..d83cacd 100644 --- a/app/views/puzzles/_puzzles_table.html.erb +++ b/app/views/puzzles/_puzzles_table.html.erb @@ -10,7 +10,7 @@ <% puzzles.each do |puzzle| %> - + <%= puzzle.question %> <%= puzzle.answer %> <%= puzzle.explanation %> @@ -24,6 +24,10 @@ <% if actions == :pending %> <%= button_to 'Approve', puzzle_state_path(puzzle, state: :approved), method: :patch, form_class: 'inline-form', class: 'btn approve-btn' %> <%= button_to 'Reject', puzzle_state_path(puzzle, state: :rejected), method: :patch, form_class: 'inline-form', class: 'btn reject-btn' %> + <%= link_to "Edit", + edit_puzzle_path(puzzle), + data: { turbo_frame: "modal" }, + class: "btn edit-btn" %> <% elsif actions == :approved %> <%= button_to 'Reject', puzzle_state_path(puzzle, state: :rejected), method: :patch, form_class: 'inline-form', class: 'btn reject-btn' %> <%= button_to 'Pending', puzzle_state_path(puzzle, state: :pending), method: :patch, form_class: 'inline-form', class: 'btn pending-btn' %> diff --git a/app/views/puzzles/edit.html.erb b/app/views/puzzles/edit.html.erb new file mode 100644 index 0000000..957e420 --- /dev/null +++ b/app/views/puzzles/edit.html.erb @@ -0,0 +1,15 @@ + + + + diff --git a/app/views/puzzles/update.turbo_stream.erb b/app/views/puzzles/update.turbo_stream.erb new file mode 100644 index 0000000..c771aad --- /dev/null +++ b/app/views/puzzles/update.turbo_stream.erb @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 6b20b1b..96801d9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - resources :puzzles, only: [ :index ] do + resources :puzzles, only: [ :index, :edit, :update ] do resource :state, only: [ :update ], module: :puzzles end resources :sessions, only: [ :create, :destroy ] From 69b57de75f72bfba5b0aafa12eb467b42b62e426 Mon Sep 17 00:00:00 2001 From: Francois Buys Date: Thu, 9 Oct 2025 00:16:08 +0200 Subject: [PATCH 2/2] Close edit modal when overlay is clicked Remove unnecessary dataset action check in modal close method. Update modal overlay to use click event for closing, ensuring consistent modal dismissal behavior. --- app/javascript/controllers/modal_controller.js | 4 +--- app/views/puzzles/edit.html.erb | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/javascript/controllers/modal_controller.js b/app/javascript/controllers/modal_controller.js index 831d917..af8346e 100644 --- a/app/javascript/controllers/modal_controller.js +++ b/app/javascript/controllers/modal_controller.js @@ -4,8 +4,6 @@ export default class extends Controller { static targets = ["content"] close(event) { - if (event.target.dataset.action === "modal#close") { - this.element.remove() - } + this.element.remove() } } diff --git a/app/views/puzzles/edit.html.erb b/app/views/puzzles/edit.html.erb index 957e420..1e3fedc 100644 --- a/app/views/puzzles/edit.html.erb +++ b/app/views/puzzles/edit.html.erb @@ -1,6 +1,5 @@ - -