Skip to content

Commit

Permalink
Extract a Games::Listings View Model from Games::Index
Browse files Browse the repository at this point in the history
I'm now of the opinion that if we have a partial drawing data from a
View Model then it should be one named after that partial. e.g.

```
 # bad
 render("listings", view: @view)

 # good
 render("listings", listings: @view.listings)
```

Also, simplify the Games::Index view model code a bit. I'm not sure
why so many things were class methods. I guess because they don't depend
on state, but, still, it was causing some confusion when looking at it.
  • Loading branch information
Paul DobbinSchmaltz committed Nov 11, 2024
1 parent 023c3d2 commit 64ef154
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 98 deletions.
6 changes: 3 additions & 3 deletions app/views/games/_listings.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<%# locals: (view:) %>
<%# locals: (listings:) %>

<div class="space-y-6">
<% if view.any_listings? %>
<% view.listings_grouped_by_date.each do |listings_date, listings| %>
<% if listings.any? %>
<% listings.listings_grouped_by_date.each do |listings_date, listings| %>
<div class="space-y-3">
<h3><%= listings_date %></h3>
<h4 class="h5 text-dim-sm">
Expand Down
2 changes: 1 addition & 1 deletion app/views/games/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@
engagement_tally: @view.engagement_tally) %>
</h2>

<%= render("listings", view: @view) %>
<%= render("listings", listings: @view.listings) %>
</div>
101 changes: 7 additions & 94 deletions app/views/games/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
class Games::Index
def self.turbo_stream_name = :sweep_ops_archive

def self.current_time_zone_description
Time.zone.to_s
end

def initialize(base_arel:, type_filter:)
@base_arel = base_arel
@type_filter = type_filter
Expand All @@ -19,7 +15,7 @@ def time_zone_form(user:)
Users::TimeZone::Form.new(user:)
end

def current_time_zone_description = self.class.current_time_zone_description
def current_time_zone_description = Time.zone.to_s

def types
Type.wrap(Game::ALL_TYPES, type_filter:)
Expand All @@ -29,39 +25,20 @@ def engagement_tally
EngagementTally.new(base_arel:)
end

def any_listings?
arel.any?
end

def listings_grouped_by_date
games_grouped_by_ended_at.
transform_keys! { |date| ListingsDate.new(date, base_arel: arel) }.
transform_values! { |games| Listing.wrap(games) }
def listings
Games::Listings.new(base_arel:, type_filter:)
end

private

attr_reader :base_arel,
:type_filter

def arel
arel = base_arel
arel = arel.for_type(type_filter) if type_filter
arel
end

def games_grouped_by_ended_at
arel.group_by { |game| game.ended_at.to_date }
end

# Games::Index::Type wraps {Game::TYPES}, for display of the "Initials = Name"
# map/legend.
# map/legend + filter links.
class Type
include WrapMethodBehaviors

def self.total_games_count = @total_games_count ||= base_arel.count
def self.base_arel = Game.for_game_over_statuses

def initialize(preset, type_filter:)
@preset = preset
@type_filter = type_filter
Expand Down Expand Up @@ -93,8 +70,7 @@ def games_percentage
attr_reader :preset,
:type_filter

def base_arel = self.class.base_arel
def total_games_count = self.class.total_games_count
def base_arel = Game.for_game_over_statuses

def filter_active?
type_filter&.include?(name)
Expand All @@ -104,6 +80,8 @@ def games_percent
result = (games_count / total_games_count.to_f) * 100.0
result.nan? ? 0.0 : result
end

def total_games_count = @total_games_count ||= base_arel.count
end

# Games::Index::EngagementTally
Expand All @@ -120,69 +98,4 @@ def initialize(base_arel:)

def start_at = App.created_at
end

# Games::Index::ListingsDate
class ListingsDate
include Games::Past::EngagementTallyBehaviors

attr_reader :date

def initialize(date, base_arel:)
@date = date
@base_arel = base_arel
end

def to_s
I18n.l(date, format: :weekday_comma_date)
end

private

attr_reader :base_arel

def start_at
date.in_time_zone.at_beginning_of_day
end

def end_at
date.in_time_zone.at_end_of_day
end
end

# Games::Index::Listing
class Listing
include WrapMethodBehaviors

def initialize(game)
@game = game
end

def game_url
Router.game_path(game)
end

def game_number = game.display_id
def type = game.type
def type_indicator = type[0]

def show_game_score? = !!_game_score
def game_score = View.round(_game_score, precision: 0)

def game_status_mojis
if game_ended_in_defeat?
Emoji.mine
elsif game_ended_in_victory?
"#{Emoji.ship}#{Emoji.victory}"
end
end

private

attr_reader :game

def _game_score = game.score

def game_ended_in_victory? = game.ended_in_victory?
def game_ended_in_defeat? = game.ended_in_defeat?
end
end
99 changes: 99 additions & 0 deletions app/views/games/listings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# frozen_string_literal: true

# Games::Listings represents {Game} listings on the Games Index page.
class Games::Listings
def initialize(base_arel:, type_filter:)
@base_arel = base_arel
@type_filter = type_filter
end

def any?
arel.any?
end

def listings_grouped_by_date
games_grouped_by_ended_at.
transform_keys! { |date| ListingsDate.new(date, base_arel: arel) }.
transform_values! { |games| Listing.wrap(games) }
end

private

attr_reader :base_arel,
:type_filter

def games_grouped_by_ended_at
arel.group_by { |game| game.ended_at.to_date }
end

def arel
arel = base_arel
arel = arel.for_type(type_filter) if type_filter
arel
end

# Games::Listings::ListingsDate
class ListingsDate
include Games::Past::EngagementTallyBehaviors

attr_reader :date

def initialize(date, base_arel:)
@date = date
@base_arel = base_arel
end

def to_s
I18n.l(date, format: :weekday_comma_date)
end

private

attr_reader :base_arel

def start_at
date.in_time_zone.at_beginning_of_day
end

def end_at
date.in_time_zone.at_end_of_day
end
end

# Games::Listings::Listing
class Listing
include WrapMethodBehaviors

def initialize(game)
@game = game
end

def game_url
Router.game_path(game)
end

def game_number = game.display_id
def type = game.type
def type_indicator = type[0]

def show_game_score? = !!_game_score
def game_score = View.round(_game_score, precision: 0)

def game_status_mojis
if game_ended_in_defeat?
Emoji.mine
elsif game_ended_in_victory?
"#{Emoji.ship}#{Emoji.victory}"
end
end

private

attr_reader :game

def _game_score = game.score

def game_ended_in_victory? = game.ended_in_victory?
def game_ended_in_defeat? = game.ended_in_defeat?
end
end

0 comments on commit 64ef154

Please sign in to comment.