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
12 changes: 11 additions & 1 deletion app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,14 @@ ul.dropdown-menu li {

.berkeley-color {
background-color: #003262;
}
}

.field-error {
border: 2px solid red;
}

.field-error-message {
color: red;
margin-top: 5px;
font-size: 13px;
}
4 changes: 2 additions & 2 deletions app/controllers/admin/events_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def create
redirect_to admin_events_path, flash: { success: "Event created successfully." }
else
flash.now[:alert] = "Missing values. Failed to create event."
render :new
render :new, status: :unprocessable_entity
end
end

Expand All @@ -39,7 +39,7 @@ def update
redirect_to admin_events_path, flash: { success: "Event updated successfully." }
else
flash.now[:alert] = "Failed to update event."
render :edit
render :edit, status: :unprocessable_entity
end
end

Expand Down
9 changes: 6 additions & 3 deletions app/models/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

class Event < ApplicationRecord
has_one_attached :flyer
validates :title, :date, :start_time, :location, :description, presence: true
validates :title, :date, :start_time, :location, :description, presence: { message: "%{attribute} cannot be empty" }
validate :acceptable_flyer
validate :end_time_after_start_time, if: -> { start_time.present? && end_time.present? }

Expand All @@ -24,8 +24,11 @@ def formatted_date
def self.to_csv
require "csv"
CSV.generate(headers: true) do |csv|
csv << column_names
all.each { |event| csv << event.attributes.values_at(*column_names) }
columns = %w[title date start_time end_time location description]
csv << columns
all.order(date: :desc).each do |event|
csv << event.attributes.values_at(*columns)
end
end
end

Expand Down
55 changes: 45 additions & 10 deletions app/views/admin/events/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,40 @@
<div class="container mt-3">
<%= form_with model: @event, url: admin_events_path, method: :post, local: true, html: { multipart: true, id: "event-form" } do |form| %>
<div class="mb-3">
<%= form.label :title, class: 'form-label' %>
<%= form.text_field :title, class: 'form-control' %>
<%= form.label :title, class: 'form-label' do %>
Title <span style="color: red;">*</span>
<% end %>
<%= form.text_field :title, class: "form-control #{'field-error' if @event.errors[:title].any?}" %>
<% if @event.errors[:title].any? %>
<div class="field-error-message" role="alert">
⚠️ <%= @event.errors[:title].first if @event.errors[:title].any? %>
</div>
<% end %>
</div>

<div class="mb-3 form-group">
<%= form.label :date %>
<%= form.date_field :date, class: 'form-control' %>
<%= form.label :date do %>
Date <span style="color: red;">*</span>
<% end %>
<%= form.date_field :date, class: "form-control #{'field-error' if @event.errors[:date].any?}" %>
<% if @event.errors[:date].any? %>
<div class="field-error-message" role="alert">
⚠️ <%= @event.errors[:date].first if @event.errors[:date].any? %>
</div>
<% end %>
</div>

<div class="mb-3 form-group row">
<div class="col-md-6">
<%= form.label :start_time %>
<%= form.time_field :start_time, class: 'form-control', id: 'start-time' %>
<%= form.label :start_time do %>
Start time <span style="color: red;">*</span>
<% end %>
<%= form.time_field :start_time, id: "start-time", class: "form-control #{'field-error' if @event.errors[:start_time].any?}" %>
<% if @event.errors[:start_time].any? %>
<div class="field-error-message" role="alert">
⚠️ <%= @event.errors[:start_time].first if @event.errors[:start_time].any? %>
</div>
<% end %>
</div>
<div class="col-md-6">
<%= form.label :end_time %>
Expand All @@ -37,13 +58,27 @@
</div>

<div class="mb-3">
<%= form.label :location %>
<%= form.text_field :location, class: 'form-control' %>
<%= form.label :location do %>
Location <span style="color: red;">*</span>
<% end %>
<%= form.text_field :location, class: "form-control #{'field-error' if @event.errors[:location].any?}" %>
<% if @event.errors[:location].any? %>
<div class="field-error-message" role="alert">
⚠️ <%= @event.errors[:location].first if @event.errors[:location].any? %>
</div>
<% end %>
</div>

<div class="mb-3">
<%= form.label :description, class: 'form-label' %>
<%= form.text_area :description, class: 'form-control', rows: 3 %>
<%= form.label :description, class: 'form-label' do %>
Description <span style="color: red;">*</span>
<% end %>
<%= form.text_area :description, class: "form-control #{'field-error' if @event.errors[:description].any?}", rows: 3 %>
<% if @event.errors[:description].any? %>
<div class="field-error-message" role="alert">
⚠️ <%= @event.errors[:description].first if @event.errors[:description].any? %>
</div>
<% end %>
</div>

<div class="mb-3">
Expand Down
101 changes: 99 additions & 2 deletions features/admin_event_management.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,102 @@ Feature: Admin Event Management

Background:
Given I logged in as a "Admin"
And I am on the admins page

And I am on the admin dashboard
And I click "Manage Events"
Then I should land on the admin events page

Scenario: Admin can view the admin events page
Then I should see "Manage Events"
And I should see "Title"
And I should see "Description"
And I should see "Date"
And I should see "Time"
And I should see "Location"
And I should see "Flyer"
And I should see "Actions"
And I should see "Add New Event"
And I should see "Back to Admin Dashboard"
And I should see "Export"

Scenario: Admin can create a new event successfully
When I click "Add New Event"
Then I should land on the new event page
When I fill in "Title" with "Test Event"
And I fill in "Date" with "2025-05-10"
And I fill in "start-time" with "13:20"
And I fill in "Location" with "Test location"
And I fill in "Description" with "Test event description."
And I click "Create Event"
Then I should land on the admin events page
And I should see "Event created successfully."
And I should see "Test Event"

Scenario: Admin cannot create an event with missing required fields
When I click "Add New Event"
Then I should land on the new event page
When I fill in "Title" with "Test Event"
And I leave "Date" empty
And I leave "start-time" empty
And I fill in "Location" with "Test location"
And I fill in "Description" with "Test event description."
And I click "Create Event"
And I should see "Missing values. Failed to create event."
And I should see "Date cannot be empty"
And I should see "Start time cannot be empty"

Scenario: Edit event form shows times without seconds
Given the following event exists:
| title | start_time | end_time | date | location | description |
| Sample Talk | 2025-05-01 14:30:45 | 2025-05-01 16:15:20 | 2025-05-01 | Room 101 | A test event session |
When I visit the edit page for "Sample Talk"
Then the start time field should show "14:30"
And the end time field should show "16:15"

Scenario: Admin tries to view an event show page
Given the following event exists:
| title | start_time | end_time | date | location | description |
| Sample Talk | 2025-05-01 14:00:00 | 2025-05-01 15:00:00 | 2025-05-01 | Hall A | Description. |
When I visit the show page for "Sample Talk"
Then I should be redirected to the admin events page

Scenario: Admin successfully updates an event
Given the following event exists:
| title | start_time | end_time | date | location | description |
| Test Event | 2025-05-01 14:00:00 | 2025-05-01 15:00:00 | 2025-05-01 | Hall A | Description. |
And I visit the admin events page
When I click "Edit" for "Test Event"
And I fill in "Title" with "Updated Event"
And I click "Update Event"
Then I should land on the admin events page
And I should see "Event updated successfully."
And I should see "Updated Event"

Scenario: Admin fails to update an event due to a missing field
Given the following event exists:
| title | start_time | end_time | date | location | description |
| Test Event | 2025-05-01 14:00:00 | 2025-05-01 15:00:00 | 2025-05-01 | Hall A | Description. |
And I visit the admin events page
When I click "Edit" for "Test Event"
And I fill in "Title" with ""
And I click "Update Event"
Then I should stay on the edit event page
And I should see "Failed to update event."

Scenario: Admin deletes an existing event
Given the following event exists:
| title | start_time | end_time | date | location | description |
| Test Event | 2025-05-01 14:00:00 | 2025-05-01 15:00:00 | 2025-05-01 | Hall A | Description. |
And I visit the admin events page
When I click "Delete" for "Test Event"
Then I should be redirected to the admin events page
And I should see "Event deleted successfully."
And I should not see "Test Event"

Scenario: Admin can export all events as CSV
Given the following event exists:
| title | start_time | end_time | date | location | description |
| Test Event | 2025-05-01 14:00:00 | 2025-05-01 15:00:00 | 2025-05-01 | Hall A | Description. |
And I visit the admin events page
When I click link "Export"
Then I should receive a CSV file named with "events"
Then I should see "Test Event"
53 changes: 53 additions & 0 deletions features/step_definitions/admin_event_steps.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# frozen_string_literal: true

Then("I should land on the admin events page") do
expect(current_path).to eq admin_events_path
end

Then("I should land on the new event page") do
expect(current_path).to eq new_admin_event_path
end

Then("I should land on the edit event page") do
expect(current_path).to eq edit_admin_event_path
end

Then("I should stay on the edit event page") do
expect(page).to have_current_path(current_path, ignore_query: true)
expect(current_path).to match(%r{/admin/events/\d+})
end

Given("the following event exists:") do |table|
table.hashes.each do |event_attrs|
Event.create!(event_attrs)
end
end

When("I visit the edit page for {string}") do |event_title|
event = Event.find_by!(title: event_title)
visit edit_admin_event_path(event)
end

When("I visit the admin events page") do
visit admin_events_path
end

Then("the start time field should show {string}") do |expected_time|
start_time_value = find_field("start-time").value
expect(start_time_value).to include(expected_time)
end

Then("the end time field should show {string}") do |expected_time|
end_time_value = find_field("end-time").value
expect(end_time_value).to include(expected_time)
end

When("I visit the show page for {string}") do |event_name|
event = Event.find_by!(title: event_name)
visit admin_event_path(event)
end

Then("I should be redirected to the admin events page") do
expect(page).to have_current_path(admin_events_path)
expect(page).to have_content("Manage Events")
end
10 changes: 10 additions & 0 deletions features/step_definitions/general_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@
Then(/^(?:|I )should not got "([^"]*)"$/) do |text|
expect(page).not_to have_selector(:link_or_button, text)
end

Then(/^I leave "(.*?)" empty$/) do |field|
fill_in field, with: ""
end

Then("I should receive a CSV file named with {string}") do |prefix|
disposition = page.response_headers["Content-Disposition"]
expect(disposition).to include("attachment;")
expect(disposition).to match(/filename="#{prefix}-\d{4}-\d{2}-\d{2}\.csv"/)
end
Loading