Skip to content
Snippets Groups Projects
Unverified Commit 857fdb78 authored by Felix Eckhofer's avatar Felix Eckhofer :man_dancing:
Browse files

Fix problems with state in broadcast session

The state is now fully client-side and handled in session_controller.
This allows us to continue to broadcast the session frame to everyone.
parent 8b75d7d3
No related branches found
No related tags found
No related merge requests found
...@@ -35,24 +35,36 @@ class CandidatesController < ApplicationController ...@@ -35,24 +35,36 @@ class CandidatesController < ApplicationController
def destroy def destroy
@candidate = Candidate.find(params[:id]) @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") Rails.logger.debug("destroyed candidate entry")
Turbo::StreamsChannel.broadcast_replace_later_to( Turbo::StreamsChannel.broadcast_replace_later_to(
@session.conference, session.conference,
target: helpers.dom_id(@session), target: helpers.dom_id(session),
partial: "sessions/session", partial: "sessions/session",
locals: { session: @session } locals: { session: session }
) )
respond_to do |format| respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(@session), partial: "sessions/session", locals: { session: @session }) } 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.html { redirect_to conference_session_path(session.conference, session), notice: 'Candidate removed successfully.' }
end end
else else
respond_to do |format| 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.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.html { redirect_to conference_session_path(session.conference, session), alert: 'Failed to remove candidate.' }
end end
end end
end end
......
...@@ -2,4 +2,10 @@ module ApplicationHelper ...@@ -2,4 +2,10 @@ module ApplicationHelper
def logged_in? def logged_in?
!session[:user_id].nil? !session[:user_id].nil?
end end
def body_data_attributes
attributes = {}
attributes[:loggedin_uid] = session[:user_id] if logged_in?
{ data: attributes }
end
end end
import { Controller } from "@hotwired/stimulus" import { Controller } from "@hotwired/stimulus"
export default class extends Controller { export default class extends Controller {
static targets = ["form", "link"]; 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) { submitWithPrompt(event) {
event.preventDefault(); event.preventDefault();
const reason = prompt("Why are you especially qualified? (Please keep it short, thanks)"); const reason = prompt(event.target.dataset.prompt);
if (reason !== null && reason.trim() !== "") { if (reason !== null && reason.trim() !== "") {
const input = document.createElement("input"); const input = document.createElement("input");
input.type = "hidden"; input.type = "hidden";
input.name = "note"; input.name = "note";
input.value = reason; input.value = reason;
this.formTarget.appendChild(input); const form = event.target.closest("form");
this.formTarget.requestSubmit(); form.appendChild(input);
form.requestSubmit();
} }
} }
} }
...@@ -3,7 +3,7 @@ ...@@ -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 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> <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"> <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> <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 %>"> <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" /> <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" />
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<%= javascript_importmap_tags %> <%= javascript_importmap_tags %>
</head> </head>
<body> <body <%= tag.attributes(body_data_attributes) %>>
<nav class="main-nav bg-slate-100 border-b border-slate-200 shadow"> <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="container mx-auto p-5 flex flex-row justify-between">
<div class="main-nav-left flex flex-row gap-4 items-center"> <div class="main-nav-left flex flex-row gap-4 items-center">
......
<% unassigned_users = User.all - session.assignments.collect(&:user) %> <% 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" : "") %>"> <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> <h4>
<small class="text-2xs uppercase font-light bg-black/10 rounded-sm p-1 mr-1 lang-<%= session.language %>"><%= session.language %></small> <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 @@ ...@@ -20,24 +20,19 @@
</svg> </svg>
<%= session.stage.name %> <%= session.stage.name %>
</span> </span>
<% if logged_in? %> <span class="absolute top-0 right-0 text-3xl only-loggedin">
<span class="absolute top-0 right-0 text-3xl"> <%= 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 %>
<% 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 %>
🙅 <%= 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 %> 🙋
<% else %> <% end %>
<%= 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 %> <%= 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 %> 🙌
<%= 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 %>
<% end %> <% end %>
<% end %> <% end %>
</span> </span>
<% end %>
</div> </div>
<div> <div>
<ul class="flex flex-wrap text-xs gap-1"> <ul class="flex flex-wrap text-xs gap-1">
...@@ -76,7 +71,7 @@ ...@@ -76,7 +71,7 @@
</div> </div>
<% end %> <% end %>
<small>candidates (<%= session.candidates.length %>)</small> <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| %> <% session.candidates.sort_by { |cand| cand.note.nil? ? 1:0 }.each do |candidate| %>
<li class="inline-flex items-end"> <li class="inline-flex items-end">
<span class="assigned-user"><%= render partial: 'candidates/user_avatar', locals: { candidate: } %></span> <span class="assigned-user"><%= render partial: 'candidates/user_avatar', locals: { candidate: } %></span>
......
...@@ -26,6 +26,7 @@ Rails.application.routes.draw do ...@@ -26,6 +26,7 @@ Rails.application.routes.draw do
resources :sessions, param: :ref_id do resources :sessions, param: :ref_id do
resources :assignments, only: [:create, :destroy] resources :assignments, only: [:create, :destroy]
resources :candidates, only: [:create, :destroy] resources :candidates, only: [:create, :destroy]
delete 'candidates', to: 'candidates#destroy_self'
end end
resources :speakers, param: :ref_id resources :speakers, param: :ref_id
end end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment