diff --git a/app/helpers/better_together/events_helper.rb b/app/helpers/better_together/events_helper.rb index 88070da7e..19bee5223 100644 --- a/app/helpers/better_together/events_helper.rb +++ b/app/helpers/better_together/events_helper.rb @@ -3,6 +3,37 @@ module BetterTogether # View helpers for events module EventsHelper + # Returns a formatted time range for an event + # If only a start time is present, it is formatted by itself. + # If the event ends on the same day, the end time is shown without the date. + # Otherwise, both start and end are fully formatted. + def event_time_range(event, format: :event) + return unless event&.starts_at + + start_time = l(event.starts_at, format: format) + return start_time unless event.ends_at + + end_time = if event.starts_at.to_date == event.ends_at.to_date + l(event.ends_at, format: '%-I:%M %p') + else + l(event.ends_at, format: format) + end + + "#{start_time} - #{end_time}" + end + + # Builds a location string from the event's location and its associated address + def event_location(event) + location = event&.location + return unless location + + parts = [] + parts << location.name if location.respond_to?(:name) && location.name.present? + parts << location.location.to_s if location.respond_to?(:location) && location.location.present? + + parts.compact.join(', ').presence + end + # Return hosts for an event that the current user is authorized to view. # Keeps view markup small and centralizes the policy logic for testing. def visible_event_hosts(event) diff --git a/app/views/better_together/events/_event.html.erb b/app/views/better_together/events/_event.html.erb index 2b78b4e9e..6a4cbb1f4 100644 --- a/app/views/better_together/events/_event.html.erb +++ b/app/views/better_together/events/_event.html.erb @@ -4,16 +4,16 @@ <%= cache event.cache_key_with_version do %> <% if policy(event).show? %> <%= render 'better_together/shared/card', entity: event do %> - <% if event.location&.name&.present? %> -
- <%= event.location %> -
- <% end %> - <% if event.starts_at.present? %> -
- <%= l(event.starts_at, format: :short) %> -
- <% end %> + <% if (location = event_location(event)) %> +
+ <%= location %> +
+ <% end %> + <% if (time_range = event_time_range(event, format: :short)) %> +
+ <%= time_range %> +
+ <% end %>
<%= categories_badge(event) %>
@@ -25,4 +25,3 @@ <% end %> <% end %> <% end %> - diff --git a/app/views/better_together/events/show.html.erb b/app/views/better_together/events/show.html.erb index 2122d927d..e04f6637c 100644 --- a/app/views/better_together/events/show.html.erb +++ b/app/views/better_together/events/show.html.erb @@ -17,14 +17,14 @@

<%= @resource.name %>

- <% if @event.location&.name&.present? %> + <% if (location = event_location(@event)) %>
- <%= @event.location %> + <%= location %>
<% end %> - <% if @event.starts_at.present? %> + <% if (time_range = event_time_range(@event)) %>
- <%= l(@event.starts_at, format: :event) %> + <%= time_range %>
<% end %>
@@ -92,16 +92,16 @@
<%= @event.privacy.humanize %>
- <% if @event.location&.name&.present? %> + <% if (location = event_location(@event)) %>
- <%= @event.location %> + <%= location %>
<% end %> - <% if @event.starts_at.present? %> + <% if (time_range = event_time_range(@event)) %>
- <%= l(@event.starts_at, format: :event) %> + <%= time_range %>
- <% end %> + <% end % <% if @event.registration_url.present? %>
<%= link_to t('better_together.events.register'), @event.registration_url, target: '_blank', class: 'text-decoration-none' %> diff --git a/spec/helpers/better_together/events_helper_spec.rb b/spec/helpers/better_together/events_helper_spec.rb new file mode 100644 index 000000000..fec0da5ef --- /dev/null +++ b/spec/helpers/better_together/events_helper_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'rails_helper' + +module BetterTogether + RSpec.describe EventsHelper, type: :helper do + describe '#event_time_range' do + let(:start_time) { Time.zone.parse('2024-03-10 15:00') } + let(:event) { instance_double(Event, starts_at: start_time, ends_at: end_time) } + + context 'when end time is on same day' do + let(:end_time) { Time.zone.parse('2024-03-10 17:00') } + + it 'formats with end time only' do + expected = "#{I18n.l(start_time, format: :event)} - #{I18n.l(end_time, format: '%-I:%M %p')}" + expect(helper.event_time_range(event)).to eq(expected) + end + end + + context 'when end time is on a different day' do + let(:end_time) { Time.zone.parse('2024-03-11 17:00') } + + it 'formats both start and end times fully' do + expected = "#{I18n.l(start_time, format: :event)} - #{I18n.l(end_time, format: :event)}" + expect(helper.event_time_range(event)).to eq(expected) + end + end + + context 'without an end time' do + let(:end_time) { nil } + + it 'returns only the start time' do + expect(helper.event_time_range(event)).to eq(I18n.l(start_time, format: :event)) + end + end + end + + describe '#event_location' do + it 'combines name and location' do + locatable = instance_double( + Geography::LocatableLocation, + name: 'Town Hall', + location: 'Springfield' + ) + event = instance_double(Event, location: locatable) + + expect(helper.event_location(event)).to eq('Town Hall, Springfield') + end + + it 'returns nil when no location is present' do + expect(helper.event_location(instance_double(Event, location: nil))).to be_nil + end + end + end +end diff --git a/spec/views/better_together/events/_event.html.erb_spec.rb b/spec/views/better_together/events/_event.html.erb_spec.rb new file mode 100644 index 000000000..e92b914c4 --- /dev/null +++ b/spec/views/better_together/events/_event.html.erb_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'better_together/events/_event', type: :view do + it 'renders formatted location and time range' do + start_time = Time.zone.parse('2024-03-10 15:00') + end_time = Time.zone.parse('2024-03-10 17:00') + locatable = instance_double( + BetterTogether::Geography::LocatableLocation, + name: 'Town Hall', + location: 'Springfield' + ) + event = instance_double( + BetterTogether::Event, + cache_key_with_version: 'events/1-20240310', + starts_at: start_time, + ends_at: end_time, + location: locatable + ) + + view.define_singleton_method(:categories_badge) { |*_args| '' } + allow(view).to receive(:render).with('better_together/shared/card', entity: event).and_yield + allow(view).to receive(:event_time_range).and_call_original + allow(view).to receive(:event_location).and_call_original + + render partial: 'better_together/events/event', locals: { event: event } + + expect(view).to have_received(:event_time_range).with(event, format: :short) + expect(view).to have_received(:event_location).with(event) + + expect(rendered).to include('Town Hall, Springfield') + expected_time = "#{I18n.l(start_time, format: :event)} - #{I18n.l(end_time, format: '%-I:%M %p')}" + expect(rendered).to include(expected_time) + end +end