diff --git a/app/controllers/candidates_controller.rb b/app/controllers/candidates_controller.rb index 61f1c3c9a6280949cfe56e0892f796902fbf0689..4b5afa66eda13004faca5fbc7f12e46eb3fdbe5b 100644 --- a/app/controllers/candidates_controller.rb +++ b/app/controllers/candidates_controller.rb @@ -35,24 +35,36 @@ class CandidatesController < ApplicationController def destroy @candidate = Candidate.find(params[:id]) - @session = @candidate.session + @session = Session.find_by(ref_id: params[:session_ref_id]) + destroy_candidate(@session, @candidate) + end + + def destroy_self + @session = Session.find_by(ref_id: params[:session_ref_id]) + user = User.find(session[:user_id]) + @candidate = Candidate.find_by(user:, session: @session) + destroy_candidate(@session, @candidate) + end + + private - if @candidate&.destroy + def destroy_candidate(session, candidate) + if candidate&.destroy Rails.logger.debug("destroyed candidate entry") Turbo::StreamsChannel.broadcast_replace_later_to( - @session.conference, - target: helpers.dom_id(@session), + session.conference, + target: helpers.dom_id(session), partial: "sessions/session", - locals: { session: @session } + locals: { session: session } ) respond_to do |format| - format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(@session), partial: "sessions/session", locals: { session: @session }) } - format.html { redirect_to conference_session_path(@session.conference, @session), notice: 'Candidate removed successfully.' } + format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(session), partial: "sessions/session", locals: { session: session }) } + format.html { redirect_to conference_session_path(session.conference, session), notice: 'Candidate removed successfully.' } end else respond_to do |format| - format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(@session), partial: "sessions/session", locals: { session: @session }), status: :unprocessable_entity } - format.html { redirect_to conference_session_path(@session.conference, @session), alert: 'Failed to remove candidate.' } + format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(session), partial: "sessions/session", locals: { session: session }), status: :unprocessable_entity } + format.html { redirect_to conference_session_path(session.conference, session), alert: 'Failed to remove candidate.' } end end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6d16c9aeafa09c87a3e7af019880496cae491e27..db5791d8dccaf0db38968adb3ffcbb488c91a5f0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,4 +2,10 @@ module ApplicationHelper def logged_in? !session[:user_id].nil? end + + def body_data_attributes + attributes = {} + attributes[:loggedin_uid] = session[:user_id] if logged_in? + { data: attributes } + end end diff --git a/app/javascript/controllers/bothhands_controller.js b/app/javascript/controllers/bothhands_controller.js deleted file mode 100644 index e818f5719abb856472b4b1a568d5f9edd7caacaf..0000000000000000000000000000000000000000 --- a/app/javascript/controllers/bothhands_controller.js +++ /dev/null @@ -1,19 +0,0 @@ -import { Controller } from "@hotwired/stimulus" - -export default class extends Controller { - static targets = ["form", "link"]; - - submitWithPrompt(event) { - event.preventDefault(); - - const reason = prompt("Why are you especially qualified? (Please keep it short, thanks)"); - if (reason !== null && reason.trim() !== "") { - const input = document.createElement("input"); - input.type = "hidden"; - input.name = "note"; - input.value = reason; - this.formTarget.appendChild(input); - this.formTarget.requestSubmit(); - } - } -} diff --git a/app/javascript/controllers/session_controller.js b/app/javascript/controllers/session_controller.js new file mode 100644 index 0000000000000000000000000000000000000000..8cef9dc28456120069c176694ca54d9296f07ad1 --- /dev/null +++ b/app/javascript/controllers/session_controller.js @@ -0,0 +1,40 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ["candidates"]; + + connect() { + const uid = document.body.dataset.loggedinUid; + const isCandidate = this.candidatesTarget.querySelector(`a.candidate[data-candidate-uid="${uid}"]`); + + this.element.querySelectorAll('.only-loggedin').forEach(el => { + el.hidden = !uid; + }); + this.element.querySelectorAll('.only-loggedout').forEach(el => { + el.hidden = uid; + }); + this.element.querySelectorAll('.only-candidate').forEach(el => { + el.hidden = !isCandidate; + }); + this.element.querySelectorAll('.only-no-candidate').forEach(el => { + el.hidden = isCandidate; + }); + + + } + + submitWithPrompt(event) { + event.preventDefault(); + + const reason = prompt(event.target.dataset.prompt); + if (reason !== null && reason.trim() !== "") { + const input = document.createElement("input"); + input.type = "hidden"; + input.name = "note"; + input.value = reason; + const form = event.target.closest("form"); + form.appendChild(input); + form.requestSubmit(); + } + } +} diff --git a/app/views/candidates/_user_avatar.html.erb b/app/views/candidates/_user_avatar.html.erb index 04f1a3b84a30641888bca5a58c117b40c7c96968..8d2c0c89b2ff318b7ce80cbfc22667ba80075513 100644 --- a/app/views/candidates/_user_avatar.html.erb +++ b/app/views/candidates/_user_avatar.html.erb @@ -3,7 +3,7 @@ <span class="gap-x-0.5 rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" style="background-color: <%= user.avatar_color %>" title="<%= user.name %>"> <span style="color: <%= user.text_color %>"><%= user.name %></span> <button type="button" class="group relative -mr-1 size-3.5 rounded-sm hover:bg-gray-500/20"> - <%= link_to conference_session_assignments_path(session.conference, session, user_id: user.id), data: { turbo_method: :post, turbo_frame: dom_id(session) } do %> + <%= link_to conference_session_assignments_path(session.conference, session, user_id: user.id), class: "candidate", data: { turbo_method: :post, turbo_frame: dom_id(session), candidate_uid: user.id } do %> <span class="sr-only">Add</span> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16" stroke-width="1" class="size-3.5 stroke-gray-600/50 group-hover:stroke-gray-600/75 fill-gray-600/50" style="stroke: <%= user.text_color %>; fill: <%= user.text_color %>"> <path d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z" /> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 4b08dc167c06cfd63730900da97845981f658872..45f37abdebbeb4d6ddc72321c486e18f5f02bc82 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -11,7 +11,7 @@ <%= javascript_importmap_tags %> </head> - <body> + <body <%= tag.attributes(body_data_attributes) %>> <nav class="main-nav bg-slate-100 border-b border-slate-200 shadow"> <div class="container mx-auto p-5 flex flex-row justify-between"> <div class="main-nav-left flex flex-row gap-4 items-center"> diff --git a/app/views/sessions/_session.html.erb b/app/views/sessions/_session.html.erb index e34e709a7e39a3f4e567f6dbb92b586dcfad729f..9a2b4fc969ba0f1438d17dc9da221d7867fc833b 100644 --- a/app/views/sessions/_session.html.erb +++ b/app/views/sessions/_session.html.erb @@ -1,5 +1,5 @@ <% unassigned_users = User.all - session.assignments.collect(&:user) %> -<%= turbo_frame_tag dom_id(session), method: "morph", class: "w-full" do %> +<%= turbo_frame_tag dom_id(session), method: "morph", class: "w-full", data: { controller: "session" } do %> <div class="session shadow hover:shadow-lg overflow-scroll text-sm w-full !h-full min-h-full hover:!min-h-max <%= session.translators_needed? ? "translators-needed" : "no-translators-needed" %> <%= session.backup_needed? ? "backup-needed" : "no-backup-needed" %> <%= session.assignees? ? "has-assignees" : "no-assignees" %> <%= (session.ends_at < Time.now ? "past" : "") %>"> <h4> <small class="text-2xs uppercase font-light bg-black/10 rounded-sm p-1 mr-1 lang-<%= session.language %>"><%= session.language %></small> @@ -20,24 +20,19 @@ </svg> <%= session.stage.name %> </span> - <% if logged_in? %> - <span class="absolute top-0 right-0 text-3xl"> - <% if candidate = session.candidates.find_by(user_id: current_user.id) %> - <%= link_to conference_session_candidate_path(session.conference, session, candidate), class: "pr-1", title: "Withdraw", aria_label: "Withdraw", data: { turbo_method: :delete, turbo_frame: dom_id(session) }, method: :delete do %> - 🙅 - <% end %> - <% else %> - <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1", title: "Volunteer Myself", aria_label: "Volunteer Myself", data: { turbo_method: :post, turbo_frame: dom_id(session) } do %> - 🙋 - <% end %> - <%= form_with url: conference_session_candidates_path(session.conference, session), method: :post, class: "inline", data: { turbo_frame: dom_id(session), controller: "bothhands", bothhands_target: "form" } do |form| %> - <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1", title: "Volunteer (with special skills)", aria_label: "Volunteer (with special skills)", data: { action: "bothhands#submitWithPrompt", turbo_prefetch:"false" } do %> - 🙌 - <% end %> + <span class="absolute top-0 right-0 text-3xl only-loggedin"> + <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1 only-candidate", title: "Withdraw", aria_label: "Withdraw", data: { turbo_method: :delete, turbo_frame: dom_id(session) }, method: :delete do %> + 🙅 + <% end %> + <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1 only-no-candidate", title: "Volunteer Myself", aria_label: "Volunteer Myself", data: { turbo_method: :post, turbo_frame: dom_id(session) } do %> + 🙋 + <% end %> + <%= form_with url: conference_session_candidates_path(session.conference, session), method: :post, class: "inline", data: { turbo_frame: dom_id(session) } do |form| %> + <%= link_to conference_session_candidates_path(session.conference, session), class: "pr-1 only-no-candidate", title: "Volunteer (with special skills)", aria_label: "Volunteer (with special skills)", data: { action: "session#submitWithPrompt", prompt: "Why are you especially qualified? (Please keep it short, thanks)", turbo_prefetch:"false" } do %> + 🙌 <% end %> <% end %> - </span> - <% end %> + </span> </div> <div> <ul class="flex flex-wrap text-xs gap-1"> @@ -76,7 +71,7 @@ </div> <% end %> <small>candidates (<%= session.candidates.length %>)</small> - <ul class="inline-flex flex-wrap gap-1 my-1"> + <ul class="inline-flex flex-wrap gap-1 my-1" data-session-target="candidates"> <% session.candidates.sort_by { |cand| cand.note.nil? ? 1:0 }.each do |candidate| %> <li class="inline-flex items-end"> <span class="assigned-user"><%= render partial: 'candidates/user_avatar', locals: { candidate: } %></span> diff --git a/config/routes.rb b/config/routes.rb index 0483a6e75f73813647670ac1453ad5caa500bf1b..9f10884a9afee88b726c47286df61229a9a79744 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -26,6 +26,7 @@ Rails.application.routes.draw do resources :sessions, param: :ref_id do resources :assignments, only: [:create, :destroy] resources :candidates, only: [:create, :destroy] + delete 'candidates', to: 'candidates#destroy_self' end resources :speakers, param: :ref_id end