Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/controllers/events_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def index
end

def show
@event = @event.decorate
end

def new # all logged in users can create events
Expand All @@ -16,7 +17,6 @@ def new # all logged in users can create events
end

def edit
@event = @event.decorate
set_form_variables
unless @event.created_by == current_user || current_user.super_user?
redirect_to events_path, alert: "You are not authorized to edit this event."
Expand Down Expand Up @@ -64,6 +64,7 @@ def destroy
private

def set_form_variables
@event = @event.decorate
@event.build_main_image if @event.main_image.blank?
@event.gallery_images.build
end
Expand Down
164 changes: 107 additions & 57 deletions app/views/events/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,76 +1,126 @@
<div class="detail py-6 min-h-screen">
<div class="max-w-5xl mx-auto px-4">

<div class="flex justify-end mb-6">
<%= link_to("Index", events_path, class: "btn btn-secondary-outline") %>
<% if current_user.super_user? %>
<%= link_to("Edit", edit_event_path(@event), class: "btn btn-primary-outline") %>
<% end %>
</div>
<div class="max-w-3xl mx-auto bg-white border border-gray-200 rounded-xl shadow p-6">
<div class="header-row flex justify-between items-center">
<div class="text-left">
<div class="pt-4 mb-4">Event Details</div>
</div>
<div class="min-h-screen py-8">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">

<!-- Outer Soft Container (Events = blue theme) -->
<div class="bg-blue-50 border border-gray-200 rounded-xl shadow-md hover:shadow-lg transition-shadow duration-200 p-6">

<!-- Top Right Actions -->
<div class="text-right mb-4 space-x-2">
<%= link_to "Index", events_path, class: "btn btn-secondary-outline" %>

<div>
<% if current_user.super_user? %>
<%= link_to "Edit", edit_event_path(@event),
class: "btn btn-secondary-outline admin-only bg-blue-100" %>
<% end %>

<span class="inline-block">
<%= render "bookmarks/editable_bookmark_button", resource: @event %>
</div>
</span>
</div>

<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-3">
<div>
<%= title_with_badges(@event) %>
</div>
</div>
<!-- Inner White Card -->
<div class="bg-white rounded-lg shadow p-8">

<div class="images">
<!-- Hero Image -->
<% if @event.main_image&.file&.attached? %>
<div class="mb-8">
<%= image_tag @event.main_image.file,
class: "w-full rounded-lg shadow-sm border border-gray-200",
alt: @event.title %>
</div>
<% end %>
<div class="grid grid-cols-1 md:grid-cols-5 gap-10">

<!-- Left Column -->
<div class="md:col-span-3">

<!-- Title + Badges -->
<div class="my-3">
<%= title_with_badges(@event, font_size: "text-3xl") %>
</div>

<!-- Dates Section -->
<div class="space-y-6">

<div class="">
<%= @event.times(display_day: true, display_date: true) %>
</div>

<!-- Gallery Images -->
<% if @event.gallery_images.any? { |img| img.persisted? && img.file.attached? } %>
<div class="event-gallery single-event-detail text-center mb-4">
<div class="flex flex-wrap justify-center gap-4 mx-auto max-w-3xl">
<% @event.gallery_images.each_with_index do |gallery_image, idx| %>
<% if gallery_image.file&.attached? %>
<%= image_tag url_for(gallery_image.file),
alt: "Gallery Image #{idx + 1}",
data: { file_preview_target: "preview" },
class: "w-32 h-32 object-cover border border-gray-300 shadow-sm" %>
<div class="registration-section flex flex-col gap-4 mb-6">
<!-- ⭐ BUTTONS -->
<div class="flex flex-wrap items-center gap-3">
<% registered = @event.event_registrations.exists?(registrant_id: current_user.id) %>

<% if registered %>
<%= button_to "De-register",
event_registrant_registration_path(event_id: @event),
method: :delete,
data: { turbo_confirm: "Are you sure?" },
class: "btn btn-secondary-outline" %>

<% elsif @event.registerable? %>
<%= button_to "Register",
event_registrant_registration_path(event_id: @event),
class: "btn btn-primary-outline" %>
<% else %>
<span class="text-sm text-gray-500 italic">Registration closed</span>
<% end %>

<% if registered %>
<span class="text-xs bg-green-100 text-green-700 px-2 py-0.5 rounded-full">
You are registered!
</span>
<% end %>
</div>

<!-- ⭐ CALENDAR LINKS -->
<% if registered %>
<div class="flex gap-2 items-center text-sm text-gray-700">
<%= @event.calendar_links %>
</div>
<% end %>

</div>

<% if @event.registration_close_date %>
<div>
<p class="font-semibold text-gray-700">Registration Close Date</p>
<p class="text-gray-900">
<%= @event.registration_close_date&.strftime("%B %d, %Y %l:%M %P") || "—" %>
</p>
</div>
<% end %>

</div>
</div>
<% end %>
</div>

<div class="mb-3">
<p class="font-bold text-gray-700">Description:</p>
<p class="text-gray-900"><%= @event.description.presence || "—" %></p>
</div>
<!-- Right Column -->
<div class="md:col-span-2 space-y-6">

<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-3">
<div>
<p class="font-bold text-gray-700">Start Date:</p>
<p class="text-gray-900"><%= @event.start_date&.strftime("%B %d, %Y %l:%M %p") || "—" %></p>
</div>
<!-- Main Image Hero Image -->
<% if @event.main_image&.file&.attached? %>
<div>
<%= image_tag @event.main_image.file,
class: "w-full rounded-lg shadow-sm border border-gray-200",
alt: @event.main_image.file.blob.filename.to_s %>
</div>
<% end %>

<div>
<p class="font-bold text-gray-700">End Date:</p>
<p class="text-gray-900"><%= @event.end_date&.strftime("%B %d, %Y %l:%M %p") || "—" %></p>
<!-- Gallery Image Thumbnails -->
<% if @event.gallery_images.any? { |img| img.persisted? && img.file.attached? } %>
<div class="flex flex-wrap justify-start gap-3">
<% @event.gallery_images.each_with_index do |gallery_image, idx| %>
<% if gallery_image.file&.attached? %>
<%= image_tag url_for(gallery_image.file),
alt: "Gallery Image #{idx + 1}: #{gallery_image.file.blob.filename.to_s}",
class: "w-24 h-24 object-cover rounded border shadow-sm" %>
<% end %>
<% end %>
</div>
<% end %>

</div>
</div>

<div class="md:col-span-2">
<p class="font-bold text-gray-700">Registration Close Date:</p>
<p class="text-gray-900"><%= @event.registration_close_date&.strftime("%B %d, %Y %l:%M %p") || "—" %></p>
<!-- FULL-WIDTH DESCRIPTION -->
<div class="mt-6 md:col-span-5">
<p class="text-gray-900 leading-relaxed">
<%= @event.description.presence || "—" %>
</p>
</div>

</div>
</div>
</div>
Expand Down
24 changes: 21 additions & 3 deletions spec/factories/events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,27 @@
factory :event do
title { "sample title" }
description { "sample description" }
start_date { 1.day.from_now }
end_date { 2.days.from_now }
registration_close_date { 3.days.ago }
start_date { 12.day.from_now }
end_date { 14.days.from_now }
registration_close_date { 13.days.from_now }
publicly_visible { true }

trait :registration_closed do
after(:build) do |event|
event.registration_close_date = 13.days.ago
end
end

trait :main_image_with_file do
after(:build) do |event|
event.main_image = build(:image, :with_file, owner: event)
end
end

trait :gallery_image_with_file do
after(:build) do |event|
event.gallery_images << build(:image, :with_file, owner: event)
end
end
end
end
30 changes: 22 additions & 8 deletions spec/factories/images.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,30 @@
factory :image do
association :owner, factory: :user

association :report
# Default to no type -- must use a trait

file_file_name { "test.jpg" }
file_content_type { "image/jpeg" }
file_file_size { 1024 }
file_updated_at { Time.zone.now }
# --- Traits for type-specific subclasses ---
factory :main_image, class: "Images::MainImage"
factory :gallery_image, class: "Images::GalleryImage"

trait :with_file do
after(:build) do |image|
image.file.attach(
io: File.open(Rails.root.join("app", "assets", "images", "missing.png")),
filename: "missing.png",
content_type: "image/png"
)
end
end

trait :invalid_format do
file_content_type { "image/webp" }
file_file_name { "invalid.webp" }
after(:build) do |image|
image.file.attach(
io: File.open(Rails.root.join("app", "assets", "images", "invalid.webp")),
filename: "invalid.webp",
content_type: "image/webp"
)
end
end
end
end
end
Loading