Skip to content

Lightning Talks: speak signups, public lineup, admin management#33

Merged
Kitkatnik merged 10 commits into
mainfrom
Kitkatnik/lightning-speak
Apr 27, 2026
Merged

Lightning Talks: speak signups, public lineup, admin management#33
Kitkatnik merged 10 commits into
mainfrom
Kitkatnik/lightning-speak

Conversation

@Kitkatnik

Copy link
Copy Markdown
Collaborator

Summary

Adds a new Speak flow on lightning blocks (distinct from "Add to Plan") so attendees can claim one of 10 speaking slots in a 60-minute block; slot times are computed (60 ÷ N minutes per speaker, capped at 10 → 6 min floor) and re-derived as people sign up. Speakers can fill in optional talk details (title, description, slides URL); volunteering auto-adds the block to My Plan with a Presenting badge.

Admins get a top-level /admin/lightning_talks page that renders the lineup directly with add/remove/drag-to-reorder (Stimulus + HTML5 drag-and-drop wired through Turbo Streams so slot times re-render in place after a reorder) and a printable PDF lineup export via Prawn.

Also includes a small navbar cleanup: removes the redundant "Admin Dashboard" link from the admin nav (the brand link already points there).

Test plan

  • Sign in as an attendee → /schedule → click Speak on Friday's Lightning Talks → confirm row updates in place, lineup expands, and Presenting badge appears on /plan
  • Click Edit my lightning talk from /plan and from /schedule → fill in title/description/slides → confirm save scrolls back to the lightning row
  • Sign in as an admin → /admin/lightning_talks → add/remove a speaker, drag to reorder → confirm displayed slot times update after reorder
  • Click Export PDF on the admin page → confirm a printable lineup downloads

Adds a separate "Speak" affordance on lightning blocks (distinct from
"Add to Plan") so attendees can claim a presenter slot. Slots are
race-safely claimed via with_lock, capped at 10 speakers, and start
times are computed by dividing the 60-minute block by the current
signup count. Volunteering auto-adds the block to the user's Plan with
a "Presenting" badge.

Admins get a Speakers panel on the schedule item edit page with
drag-to-reorder, manual add/remove, talk-detail editing, and CSV
export at /admin/schedule_items/:id/lightning_talk_signups.csv.
…peak

# Conflicts:
#	app/assets/stylesheets/application.css
#	app/controllers/plan_controller.rb
#	app/models/schedule_item.rb
#	app/models/user.rb
#	app/views/plan/_plan_item.html.erb
#	config/routes.rb
#	db/schema.rb
- Reorder slot row so name + title + Slides + Edit my lightning talk
  share row 1; description wraps to row 2 (was 3 rows previously).
- Replace the gray "click to see lineup" hint with a red chevron +
  "View lineup"/"Hide lineup" affordance that rotates on open.
- Restyle the Edit my lightning talk form to match other user-facing
  forms (card + label/input classes + standard btn classes).
- After saving talk details, redirect to /schedule with a fragment
  anchor so the browser scrolls back to the lightning row instead of
  landing at the top of the schedule.
The "Ruby Embassy Admin" brand link in the navbar already points at
admin_root_path, so the separate "Admin Dashboard" link was a
duplicate destination. Removed from both the desktop nav and the
mobile drawer.
A directory view at /admin/lightning_talks listing every lightning
block with its speaker count (e.g., 7/10) and a "Manage lineup" link
that opens the existing per-block speakers page (add/remove/reorder
+ CSV export). Wired up via:

- New navbar entry between "Schedule" and "Embassy Applications"
  (desktop + mobile drawer).
- New Lightning Talks tile on the admin dashboard.

The page is read-only — all mutations still happen on the per-block
page that the row links into.
- Admin Lightning Talks page now renders the lineup directly (the
  speakers panel for the single lightning block) instead of a
  table-of-one directory. Empty state covers the "no block scheduled"
  case.
- "Edit my lightning talk" link on My Plan now uses
  data-turbo-frame="_top" so it escapes the plan_item frame instead
  of throwing a "Content Missing" error.
- Save on the edit form now uses data-turbo="false" so the redirect
  to /schedule#schedule_item_<id> reloads the page natively and the
  browser scrolls to the lightning row. (Cancel already worked because
  it was a GET navigation.)
The admin Speakers panel now exports a printable PDF lineup (numbered
table of position, slot time, speaker, talk title) instead of a CSV.
Built with Prawn + prawn-table, mirroring the PassportApplicationPdf
service pattern.

The old per-block HTML index page (admin/schedule_items/:id/
lightning_talk_signups) had its own "Export CSV" button on top of the
panel's button, so anyone landing on that URL saw two duplicate
buttons. Deleted the HTML view; the controller now redirects HTML
format to the canonical /admin/lightning_talks page. PDF format still
serves the file. Create/update/destroy redirects use redirect_back so
they land back wherever the admin came from.

Drops the csv gem (added in the earlier merge, no longer used by
anyone in the codebase).
The "Add a speaker" form uses flex+items-end to put the User column
next to the Add button. Rails f.submit renders <input type="submit">,
which browsers stretch unpredictably as a flex item — the result was
a button as tall as the label+select stacked together.

Switching to button_tag (which renders <button type="submit">) makes
the button a normal flex item that sizes to content and aligns to
the bottom of the cross-axis like intended.
The reorder endpoint returned head :no_content, so dragging a row
moved it visually but the per-row time labels stayed put — slot
times depend on position, and nothing re-rendered them.

Now the controller responds with a Turbo Stream that replaces the
speakers <ol> with the freshly-ordered partial. Extracted
_speakers_list.html.erb so both the initial panel render and the
reorder response use the same template. Stimulus controller sends
Accept: text/vnd.turbo-stream.html and applies the response via
Turbo.renderStreamMessage.

Kept the format.json head :no_content branch so the existing
controller test (and any future API client) still works.
The previous layout stacked the label+select inside a flex column and
sat the Add button beside it with items-end. Even with button_tag,
the button still rendered taller than the select because the parent
flex's cross-axis behavior was inconsistent.

Restructured: the label is now on its own row; the select and button
share a single flex row underneath. Both are direct siblings at the
same baseline, so they naturally render at the same height with no
align-items wrangling.
@railway-app

railway-app Bot commented Apr 27, 2026

Copy link
Copy Markdown

🚅 Deployed to the ruby-embassy-pr-33 environment in ruby-embassy

Service Status Web Updated (UTC)
ruby-embassy ✅ Success (View Logs) Web Apr 27, 2026 at 5:27 am

@railway-app railway-app Bot temporarily deployed to ruby-embassy / ruby-embassy-pr-33 April 27, 2026 05:26 Destroyed
@Kitkatnik Kitkatnik merged commit b9291b2 into main Apr 27, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant