diff --git a/app/assets/stylesheets/_items.sass b/app/assets/stylesheets/_items.sass index 31cb72ee..71aeadde 100644 --- a/app/assets/stylesheets/_items.sass +++ b/app/assets/stylesheets/_items.sass @@ -1,6 +1,6 @@ @import "partials/campaign-progress" -body.items +body.items, body.item_trades +campaign-progress text-align: center diff --git a/app/controllers/item_trades_controller.rb b/app/controllers/item_trades_controller.rb new file mode 100644 index 00000000..34c28451 --- /dev/null +++ b/app/controllers/item_trades_controller.rb @@ -0,0 +1,25 @@ +class ItemTradesController < ApplicationController + def index + @item = Item.find params[:item_id] + + @type = type_from_params + + @item_trades = @item.closet_hangers.trading.includes(:user, :list). + user_is_active.order('users.last_trade_activity_at DESC').to_trades + + @trades = @item_trades[@type] + + render layout: 'items' + end + + def type_from_params + case params[:type] + when 'offering' + :offering + when 'seeking' + :seeking + else + raise ArgumentError, "unexpected trades type: #{params[:type].inspect}" + end + end +end diff --git a/app/helpers/item_trades_helper.rb b/app/helpers/item_trades_helper.rb new file mode 100644 index 00000000..45bfbdf4 --- /dev/null +++ b/app/helpers/item_trades_helper.rb @@ -0,0 +1,2 @@ +module ItemTradesHelper +end diff --git a/app/models/closet_hanger.rb b/app/models/closet_hanger.rb index dde61fc4..7a67f1b3 100644 --- a/app/models/closet_hanger.rb +++ b/app/models/closet_hanger.rb @@ -161,12 +161,6 @@ class ClosetHanger < ApplicationRecord # # We don't preload anything here - if you want user names or list names, you # should `includes` them in the hanger scope first, to avoid extra queries! - Trade = Struct.new('Trade', :user_id, :hangers) do - def user - # Take advantage of `includes(:user)` on the hangers, if applied. - hangers.first.user - end - end def self.to_trades # Let's ensure that the `trading` filter is applied, to avoid data leaks. # (I still recommend doing it at the call site too for clarity, though!) @@ -185,6 +179,17 @@ class ClosetHanger < ApplicationRecord {offering: offering, seeking: seeking} end + Trade = Struct.new('Trade', :user_id, :hangers) do + def user + # Take advantage of `includes(:user)` on the hangers, if applied. + hangers.first.user + end + + def lists + hangers.map(&:list).filter(&:present?) + end + end + protected def list_belongs_to_user diff --git a/app/views/item_trades/index.html.haml b/app/views/item_trades/index.html.haml new file mode 100644 index 00000000..afbab69c --- /dev/null +++ b/app/views/item_trades/index.html.haml @@ -0,0 +1,30 @@ +- title t(".title.#{@type}") +- hide_title_header + +%h2.item-page-subtitle= t(".title.#{@type}") + +- if @trades.present? + %table + %thead + %tr + %th= t(".table.headings.last_active") + %th= t(".table.headings.user.#{@type}") + %th= t(".table.headings.lists") + %tbody + - @trades.each do |trade| + %tr + %td + -# TODO: Replace this with the coarse-grained version from 2020, + -# and translate it! + = time_ago_in_words trade.user.last_trade_activity_at + ago + %td= trade.user.name + %td + - if trade.lists.present? + %ul + - trade.lists.each do |list| + %li= list.name + - else + %span.not-in-a-list= t(".table.not_in_a_list") +- else + %p= t(".no_trades_yet") diff --git a/config/locales/en.yml b/config/locales/en.yml index 62591b51..fba59820 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -369,6 +369,23 @@ en: user_wants: wants fits_pet_type: fits + item_trades: + index: + title: + offering: "Trades: Offering" + seeking: "Trades: Seeking" + table: + headings: + last_active: Last active + user: + offering: Owner + seeking: Seeker + lists: Lists + not_in_a_list: Not in a list + no_trades_yet: + No trades yet! To add your name to this page, add this item to one of + your lists, and mark the list as "Trading". + neopets_page_import_tasks: create: success: Page %{index} saved! diff --git a/config/routes.rb b/config/routes.rb index a730c457..927f178e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,7 +18,11 @@ OpenneoImpressItems::Application.routes.draw do # Our customization data! Both the item pages, and JSON API endpoints. resources :items, :only => [:index, :show] do + resources :trades, path: 'trades/:type', controller: 'item_trades', + only: [:index], constraints: {type: ['offering', 'seeking']} + resources :appearances, controller: 'item_appearances', only: [:index] + collection do get :needed end