Add Schedule & My Plan pages, auth-aware navbar, and dashboard grid#5
Merged
Add Schedule & My Plan pages, auth-aware navbar, and dashboard grid#5
Conversation
Port the ashevillagers auth flow: users enter their email, we check our DB first, fall back to Tito API, auto-create a user from their ticket, then email a 30-day magic link. No passwords. Single User model with three roles (attendee, volunteer, admin); admins are seeded in db/seeds.rb and never overwritten by Tito sync. Admin UI at /admin for user CRUD, bulk Tito sync, and DB-backed Configuration management for Tito credentials and email_from. Ruby bumped to 3.4.4 for Rails 8.1.3 compatibility.
Pull the template branch's navbar/footer/ridge-bg layout, logo, colfax font, and the blueridgeruby.com class-name system. Restyle all session views (new, callback, not_registered) and the dashboard to use the brand palette (navy text, red gradient CTAs, ridge background). Give the admin area a matching navy top bar and brand-consistent forms, tables, and role badges. Extend application.css with form/card/button/ alert/table/badge utilities on top of the template's base. Also add test/system/ scaffolding so bin/rails test:system runs cleanly and a brakeman.ignore entry for the admin-only role mass-assignment (guarded by require_admin! on every action).
…link-auth # Conflicts: # .ruby-version # app/assets/stylesheets/application.css # config/routes.rb # db/schema.rb
The Dockerfile has `# check=error=true`, which promotes BuildKit lint
warnings to hard errors. The shell-form CMD from the Railway setup
tripped JSONArgsRecommended and blocked the build.
Use JSON-form CMD with `sh -c` so `${PORT}` still expands at runtime,
and `exec` so SIGTERM is forwarded directly to the Rails process
instead of being swallowed by the shell. Defaults PORT to 3000 for
local `docker run`.
Railway deploys booted into a PG::UndefinedTable error: the app eager- loaded ApplicationMailer, which reads email_from from the configurations table at class-load time, but the table didn't exist yet because migrations had never run. The root cause was the CMD shape. bin/docker-entrypoint only runs db:prepare when the last two args are exactly `./bin/rails server`, and the previous `sh -c "..."` form hid those args behind the shell. Switch to the Rails 8 default `CMD ["./bin/thrust", "./bin/rails", "server"]`, which: - is JSON form, so the Dockerfile linter passes - matches the entrypoint pattern, so db:prepare runs before Rails boots - lets Thruster read Railway's $PORT natively (no shell expansion needed) - keeps signal forwarding correct (Thruster is PID 1)
Thruster 0.1.20 binds to $HTTP_PORT (default 80), but Railway routes traffic to whatever it set $PORT to. The deploy was healthy (migrations ran, Puma was up on 3000 as Thruster's upstream) but Railway's router got 502s because no one was listening on $PORT. Propagate PORT → HTTP_PORT in the server-startup branch of the entrypoint. Respects an explicit HTTP_PORT if the caller set one, and falls back to 80 (Thruster's default) otherwise — so local `docker run` still works without either var set.
Static front-end design (no JS yet) for the companion app's two new pages. Schedule lists all 4 days with add-to-plan toggles; Plan shows a populated personalized itinerary with travel times, notes, custom blocks, and an empty-day state. Navbar gains a Login link pointing to /plan and the Schedule link now points to the internal route.
…into Kitkatnik/schedule-planner # Conflicts: # app/assets/stylesheets/application.css
Logged in: Schedule, My Plan, Admin (if admin), Sign Out. Logged out: mirrors blueridgeruby.com nav with an added Log In link left of Register. Sign Out uses button_to with DELETE to /session; styled as a text link to match the other nav items.
Replace the user-info card on the dashboard with a 6-tile grid of things attendees can do: See the schedule, Host an Activity, Plan your trip, Explore Asheville, Get your Ashevillagers, and Book a Ruby Embassy Appointment. Active tiles link out; the rest show a 'Coming soon' badge with a dashed border to signal future work.
…anner # Conflicts: # app/assets/stylesheets/application.css # app/mailers/application_mailer.rb # app/models/user.rb # app/views/dashboard/show.html.erb # app/views/layouts/admin.html.erb # config/routes.rb # db/schema.rb
|
🚅 Deployed to the ruby-embassy-pr-5 environment in ruby-embassy
|
Kitkatnik
added a commit
that referenced
this pull request
Apr 26, 2026
…#14) * Replace Embassy mock data with real backend - Add Question, NotaryProfile, EmbassyBooking, EmbassyApplication, and EmbassyApplicationAnswer models, with embassy_mode/embassy_capacity columns on ScheduleItem. - Seed 80 questions and 18 notaries from db/seeds/embassy_questions.rb via idempotent EmbassyQuestionsSeed.import! (keyed by external_id). - Wire EmbassyBookings, EmbassyApplications, and the Admin::* controllers to real ActiveRecord queries in place of FakeEmbassy. - Generate real PDF downloads with Prawn (PassportApplicationPdf, formal tax-form aesthetic), replacing the browser-print HTML partial. - Draw Section 3 questions and notary by least-used-first (EmbassyApplicationDraw) for fair distribution across applicants. - Enforce booking capacity inside a row-locked transaction; support edit-while-draft on EmbassyApplication. - Add Stimulus controller to toggle the embassy capacity/mode fields on the admin schedule-item form when kind = embassy. - Delete fake_embassy.rb, _pdf.html.erb, _expired.html.erb. * Show "Submit Application" label on application submit button Switch from f.submit (which renders <input type="submit"> where the value attribute IS the displayed label) to <button type="submit"> elements with separate inner text and submitted value. The button now shows "Submit Application" instead of the literal "1" that was being submitted as the form value. Renames the discriminator parameter from `submit` to `intent` for clarity. * Make "Save & Return Later" actually save the draft Previously "Save & Return Later" was a link that navigated away without saving any answers — confusing alongside a separate "Save draft" button that did save. Removes the redundant Save draft button and converts "Save & Return Later" into a submit button (intent=draft) that saves the in-progress answers and redirects to /plan. Extracts the shared "submit vs. draft" branch into finalize_or_redirect so both create and update go through one path. * Fix PDF layout: 2-column short fields, max_length, page numbers PDF layout overhaul addressing five visual issues: - Application now spans 2 pages instead of 8+. Short fields (Given Name + GitHub handle, Pronouns + Age in Coding Years, etc.) render side-by-side in two columns. Long answers get more vertical room sized from question.max_length. - Add max_length column on Question, surfaced on the admin form and as HTML maxlength on the user-facing form. Defaults: 60 chars (short), 240 chars (long). Caps text so it always fits the printed PDF box. - Page footer now uses pdf.repeat(:all, dynamic: true) inside pdf.canvas so it renders in the bottom margin (not the content area) and shows the actual page number on every page (was always "Page 2 of 2"). - Applicant signature + date side-by-side in fixed-position bounding boxes — they now align horizontally (was vertically stacked due to fragile move_up arithmetic). - Notary printed name + date aligned the same way; signature + notary ID below them no longer overlap. Root-cause fix for the runaway pagination: boxed_text's inner bounding_box had height < line height for short fields, which silently triggered Prawn auto-pagination. Switched to draw_text/text_box for single-line fields and made the inner-box height calculations safe. * Compact PDF checkboxes, fill page 2 with ordinances, fix copy PDF refinements: - Render checkbox_group options inline with formatted_text fragments so short option lists ("Learning / Networking / Vibes / Free coffee") fit on one line; longer lists wrap naturally to 2 lines. - Add INSTRUCTIONS TO THE APPLICANT (4 paragraphs) and EMBASSY ORDINANCES (7 §-numbered clauses) after the signature block to fill the otherwise mostly-blank page 2 with parodic legalese. - Rename header subtitle from "United Embassy of Ruby" to "Blue Ridge Ruby Embassy" on both application + notary pages. Confirmation page: - Reword photography etiquette to ask about consent for photographing other attendees instead of the (fictional) Stamping Apparatus. * Restore 2-column grid for Section 4 checkbox group on PDF The inline checkbox rendering works well for short option lists like Section 1.7 (Learning / Networking / Vibes / Free coffee) but turns Section 4's longer affirmations into a hard-to-scan run-on. Branch on a heuristic: 6+ options OR any option > 30 characters falls back to the 2-column grid. Section 4 (7 options, ~50 chars each) now uses the grid; Sections 1.7-1.9 keep the inline layout. * Drop 'will be printed on official PDF' from max-length hint * Force Section 5 onto its own page in the PDF * PDF copy fixes: signature, §2, §5, instruction #2 - APPLICANT SIGNATURE box left blank for physical ink signing; caption reads "Signature of Applicant" (drops "(typed)" — the typed name is already captured above as 5.4). - §2 Discretion: replaces "tabs over spaces" jab with "documented hatred of the Ruby programming language" — fits the Embassy theme. - §5 Right of Appeal: replaces /dev/null gag with noreply@blueridgeruby.com so the appeal channel is at least nominally plausible. - Instruction #2: rewritten generically ("Answer all questions as printed...") to keep Section 3's randomization a surprise — attendees comparing applications will see different questions and not realize why. Removes the now-unused PassportApplicationPdf#answer_text helper. * Align checkbox options in fixed-column grid The inline formatted_text path packed options as natural-width fragments, so spacing varied between every option. Replaces it with a universal grid layout that adapts column count from option width: - Short options (max ~12 chars): 4 columns - Medium phrases (max ~25 chars): 3 columns - Long affirmations (Section 4): 2 columns Each option gets a fixed-width slot, so they line up vertically within a question — even across multiple rows. Drops the two_column_options? branch since one grid path now handles all sizes. * Add ridiculous legalese, increase section spacing on PDF Section spacing: - Bump pre-section padding from 5pt to 8pt and pre-questions padding from 2pt to 3pt for more breathing room without forcing extra pages. Legal text expansion (page 2 onward, ~2 pages of dense parody legalese): - Add INSTRUCTION #5 about pens. - Expand EMBASSY ORDINANCES from 7 § to 20 §, adding clauses on Decorum, Documentation, Reciprocal Recognition, Jurisdiction, Force Majeure, Amendments, Counterparts, No Third-Party Beneficiaries, Indemnification, Survival, Entire Agreement, Conflict of Laws, Notices. - Add SCHEDULE A — DEFINITIONS (Applicant, Attaché, Business Gem, Embassy, Notary, Passport, Stamping, Vibe). - Add SCHEDULE B — PROHIBITED ACTIVITIES (forgery, photography of the Stamping Apparatus mid-impact, narrating proceedings, etc.). - Add SCHEDULE C — RULES OF CONSTRUCTION (singular/plural, business gem carve-outs, Schrödinger-cat gender clause). - Add SCHEDULE D — REPRESENTATIONS AND WARRANTIES. - Expand ACKNOWLEDGMENT to four paragraphs ending in "IN WITNESS WHEREOF, the Applicant has caused this Application to be executed by clicking a button on a website..." Drop the cursor-based break guards in render_instructions so the legal text now flows across page boundaries instead of being silently truncated when a paragraph would orphan. * Fix nil-kind crash on Plan page and harden destroy cascade A handful of dev DB records had ScheduleItem#kind values (4, 5, 6) that no longer exist in the model's enum, leftover from an earlier schema that included additional kinds like meal/break/mystery. Reading the enum returned nil, which then crashed item.kind.humanize on the Plan and Admin Schedule Items pages. - View guard: render the kind badge only when item.kind is present; Admin shows "unknown (N)" so stale rows are visible. - Add has_one :embassy_booking, dependent: :destroy on PlanItem so destroying a plan item properly cascades to its booking + application + answers. Without this inverse the cascade chain went via ScheduleItem and tried to delete plan_items before their referencing bookings, raising PG::ForeignKeyViolation. * Pack legal jargon into 3-column page-2 layout, polish copy Layout: - Use Prawn column_box(columns: 3) for INSTRUCTIONS / EMBASSY ORDINANCES / SCHEDULES A-D in 5.5pt small print, leaving the page-bottom for ACKNOWLEDGMENT full-width at 6pt. PDF is back to 3 pages: application (p1), Section 5 + signature + all legal text (p2), notary (p3). Copy edits: - Reciprocal Recognition (§9): swap CoffeeScript/Crystal/Elixir name-drops for generic "sister Ruby Embassies hosted at other regional and international Ruby gatherings." - Business Gem definition: now refers to three (3) ceremonial gemstones used for symbolic Embassy purposes; "business gem" usage elsewhere rephrased as "(3) event days." - Drop Schedule B (b) (Stamping Apparatus photography prohibition) and (d) (no narration / livestreaming) — attendees are free to photograph and livestream. - Drop Schedule C #8 (Schrödinger-cat gender clause) — keep wording inclusive and avoid commentary on protected categories. - Drop "and the open bar" from Schedule D (e). * Fold ACKNOWLEDGMENT into 3-column flow, fix Business Gems pun The ACKNOWLEDGMENT was rendering full-width below the column box and overlapping the page footer divider. Putting it inside the column box as just another section lets Prawn handle layout uniformly — no cursor math, no overlap. Also rewrites the "Business Gems" definition to actually be about RubyGems (the package manager) instead of literal gemstones, since the joke is meant to be coding-flavored not jewelry-flavored. * Justify and even out spacing in PDF legalese columns - Set align: :justify on all column-flow paragraphs so text reads flush to both column edges (matches the formal-document register). - Bump section-break gap from 4pt to 5pt for clearer separation between sections. - Bump post-divider gap from 1pt to 3pt so the first paragraph of each section has visible breathing room below its header. - Bump inter-paragraph gap from 1pt to 2pt for uniform rhythm throughout each section. * Force SCHEDULE C to start at the top of the third column Prawn's column_box has no built-in column_break primitive, so simulate one by overflowing the cursor past the bottom of the current column — Prawn snaps to the top of the next one. Tagging which sections want this in a small constant so it's data- driven and easy to add other forced breaks if the layout shifts. * Pass CI: rubocop autocorrect + clear unused fixtures - Auto-corrected Layout/SpaceInsideArrayLiteralBrackets across migrations, seed file, controllers, and PDF service to match the project's rubocop-rails-omakase preference for [ ... ] over [...]. - Empty out the auto-generated test/fixtures/*.yml stubs for the new Question, NotaryProfile, EmbassyBooking, EmbassyApplication, and EmbassyApplicationAnswer models. The placeholder rows produced by rails g model violated NOT NULL constraints (jsonb columns expect [], not nil) and broke fixture loading in every test. No tests use these fixtures yet; they can be filled in when real model tests are written.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/schedule) lists all four conference days with an Add-to-Plan toggle, anchor nav, type badges, and a flexible/TBD treatment for Saturday Ruby Embassy blocks; My Plan (/plan) shows a personalized itinerary with travel times, notes, custom blocks, and an empty-day state. Data is YAML-backed (config/schedule.yml) and fully static for now — JS/persistence comes in a follow-up PR.application.cssgains a schedule/plan component system (day-nav, schedule-item, plan-item, item-badge, add-btn, travel-section, empty-day, custom-block-btn) plus the.action-grid/.action-cardstyles for the dashboard, all extending the template's utility-class system with the BRR palette.Test plan
bin/rails server, open/schedule— verify 4 days render, anchor nav jumps correctly, type badges show the right colors, and the pre-marked "Added" items show the solid-red button state while the rest show the outlined "+ Add"/plan— verify travel times, mocked notes, the custom Thursday dinner block with its red accent, the Saturday empty-state, and "+ Add custom block" affordance/dashboard— active tiles navigate, coming-soon tiles render muted with the badge