Compare commits

..

No commits in common. "42b1bf3e8cb898c82e880434106b314367f9bb52" and "68578aa929e6256e5cbdaba95dcd398b4c72e17d" have entirely different histories.

23 changed files with 376 additions and 502 deletions

View file

@ -1,22 +0,0 @@
const userListSections = document.querySelectorAll(
".item-header .user-lists-section");
for (const section of userListSections) {
try {
const dialog = section.querySelector("dialog");
const opener = section.querySelector(".dialog-opener");
const closer = section.querySelector(".dialog-closer");
if (dialog.showModal) { // check browser support
opener.addEventListener("click", (event) => {
dialog.show();
event.preventDefault();
});
document.body.addEventListener("click", (event) => {
if (dialog.open && !section.contains(event.target)) {
dialog.close();
}
});
}
} catch (error) {
console.error(`Error applying dialog behavior to item header:`, error);
}
}

View file

@ -1,6 +1,6 @@
@import "partials/campaign-progress"
body.items, body.item_trades
body.items
+campaign-progress
text-align: center

View file

@ -17,7 +17,6 @@
@import items
@import items/index
@import items/show
@import item_trades/index
@import outfits/index
@import outfits/new
@import pets/bulk

View file

@ -1,29 +0,0 @@
@import "../partials/item_header"
body.item_trades-index
.item-header
+item-header
.item-subpage-title
text-align: left
margin-bottom: .5em
.trades-table
text-align: left
width: 100%
table-layout: fixed
th, td
&:nth-child(1), &:nth-child(2)
width: 15ch
overflow: hidden
text-overflow: ellipsis
.trade-list-names
list-style: none
li
display: inline
&:not(:last-child)::after
content: ", "

View file

@ -1,10 +1,151 @@
@import "../partials/clean/constants"
@import "../partials/clean/mixins"
@import "../partials/item_header"
body.items-show
.item-header
+item-header
#item-header
border-bottom: 1px solid $module-border-color
margin-bottom: 1em
padding: 1em 0
display: grid
grid-template-areas: "img gap1" "img name" "img links" "img gap2"
align-items: center
justify-content: center
column-gap: 1em
row-gap: .5em
#item-thumbnail
grid-area: img
border: 1px solid $module-border-color
height: 80px
width: 80px
#item-name
grid-area: name
text-align: left
line-height: 100%
#item-links
grid-area: links
text-align: left
a
font-size: 75%
margin-left: 1em
#item-name
margin-bottom: 0
#item-info-section
display: grid
grid-template-areas: "info form"
grid-template-columns: 1fr auto
#item-info
grid-area: info
#item-zones
font:
family: $text-font
size: 85%
margin-bottom: 1em
p
display: inline
&:first-child
margin-right: 1em
#your-items-form
grid-area: form
border: 1px solid $module-border-color
font-size: 85%
margin-bottom: 3em
margin-left: 1em
padding: 1em
width: 30em
// compete with #trade-hangers
position: relative
z-index: 2
h3
font-size: 150%
font-weight: bold
margin-bottom: .25em
#closet-hangers-ownership-groups
+clearfix
margin-bottom: .5em
div
float: left
margin: 0 5%
text-align: left
width: 40%
li
list-style: none
word-wrap: break-word
label.unlisted
font-style: italic
form
padding: .5em 0
select
width: 9em
input[type=number]
margin-right: .5em
width: 3em
#trade-hangers
font-size: 85%
margin-bottom: 3em
text-align: left
p
position: relative
&:first-child
margin-bottom: .5em
&[data-overflows]
overflow: hidden
.toggle
display: block
&[data-showing-more]
.toggle
.less
display: block
.more
display: none
.toggle
background: white
bottom: 0
cursor: pointer
display: none
font-family: $main-font
padding: 0 1em
position: absolute
right: 0
button
+reset-awesome-button
&:hover
text-decoration: underline
.less
display: none
#item-contributors
+subtle-banner
@ -31,3 +172,13 @@ body.items-show
.nc-icon
height: 16px
width: 16px
&.js
#trade-hangers
p
max-height: 3em
overflow: hidden
&.showing-more
max-height: none

View file

@ -1,158 +0,0 @@
@import "../partials/clean/constants"
@import "../partials/clean/mixins"
=item-header
border-bottom: 1px solid $module-border-color
margin-top: 1em
margin-bottom: 1em
.item-header-main
display: grid
grid-template-areas: "img gap1" "img name" "img links" "img lists" "img gap2" "nav nav"
align-items: center
justify-content: center
column-gap: 1em
row-gap: .5em
.item-thumbnail
grid-area: img
border: 1px solid $module-border-color
height: 80px
width: 80px
.item-name
grid-area: name
text-align: left
line-height: 100%
margin-bottom: 0
.item-links
grid-area: links
font-size: 85%
text-align: left
display: flex
align-items: center
gap: 1em
.item-kind
padding: .25em .5em
border-radius: .25em
cursor: help
text-decoration: none
font-weight: bold
line-height: 1
// These colors are copied from DTI 2020, for initial consistency!
// They're based on the Chakra UI colors, which I think are in turn the
// Bootstrap colors? Or something?
&[data-type=nc]
background: #E9D8FD
color: #44337A
&[data-type=pb]
background: #FEEBC8
color: #7B341E
&[data-type=np]
background: #E2E8F0
color: #1A202C
.user-lists-section
grid-area: lists
font-size: 85%
text-align: left
.dialog-opener
&::after
content: " "
dialog
background: $background-color
border: 1px solid $module-border-color
border-radius: .5em
padding: 1em
width: 30em
text-align: center
z-index: 2
margin-top: .5em
box-shadow: 0px 1px 4px #666
h3
font-size: 150%
font-weight: bold
margin-bottom: .25em
.closet-hangers-ownership-groups
+clearfix
margin-bottom: .5em
div
float: left
margin: 0 5%
text-align: left
width: 40%
li
list-style: none
word-wrap: break-word
label.unlisted
font-style: italic
form
padding: .5em 0
select
width: 9em
input[type=number]
margin-right: .5em
width: 3em
.item-description
margin-top: .5em
margin-bottom: 1em
.item-subpages-nav
display: flex
align-items: flex-end
.preview-link
margin-right: auto
.trades-section
display: flex
gap: .5em
header
align-self: center
font-weight: bold
&::after
content: ":"
ul
align-self: flex-end
list-style: none
display: flex
gap: .5em
li
display: block
a
display: block
border: 1px solid $module-border-color
border-bottom: 0
border-radius: .5em .5em 0 0
padding: .5em 1em
text-decoration: none
&:hover, &:focus
text-decoration: underline
&[data-is-current=true]
background: $module-bg-color
font-weight: bold

View file

@ -1,29 +0,0 @@
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]
if user_signed_in?
@current_user_lists = current_user.closet_lists.alphabetical.
group_by_owned
@current_user_quantities = current_user.item_quantities_for(@item)
end
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

View file

@ -58,15 +58,49 @@ class ItemsController < ApplicationController
respond_to do |format|
format.html do
@trades = @item.closet_hangers.trading.user_is_active.to_trades
@occupied_zones = @item.occupied_zones(
scope: Zone.includes_translations.alphabetical
)
@restricted_zones = @item.restricted_zones(
scope: Zone.includes_translations.alphabetical
)
@contributors_with_counts = @item.contributors_with_counts
@supported_species_ids = @item.supported_species_ids
@basic_colored_pet_types_by_species_id = PetType.special_color_or_basic(@item.special_color).
includes_child_translations.group_by(&:species)
trading_closet_hangers = @item.closet_hangers.trading.includes(:user).
user_is_active.order('users.last_trade_activity_at DESC')
owned_trading_hangers = trading_closet_hangers.filter { |c| c.owned? }
wanted_trading_hangers = trading_closet_hangers.filter { |c| c.wanted? }
@trading_users_by_owned = {
true => owned_trading_hangers.map(&:user).uniq,
false => wanted_trading_hangers.map(&:user).uniq,
}
if user_signed_in?
@current_user_lists = current_user.closet_lists.alphabetical.
group_by_owned
@current_user_quantities = current_user.item_quantities_for(@item)
# Empty arrays are important so that we can loop over this and still
# show the generic no-list case
@current_user_lists = {true => [], false => []}
current_user.closet_lists.alphabetical.each do |list|
@current_user_lists[list.hangers_owned] << list
end
@current_user_quantities = Hash.new(0) # default is zero
hangers = current_user.closet_hangers.where(item_id: @item.id).
select([:owned, :list_id, :quantity])
hangers.each do |hanger|
key = hanger.list_id || hanger.owned
@current_user_quantities[key] = hanger.quantity
end
end
end
format.gif do

View file

@ -1,26 +0,0 @@
module ItemTradesHelper
def vague_trade_timestamp(last_trade_activity_at)
if last_trade_activity_at >= 1.week.ago
translate "item_trades.index.table.last_active.this_week"
else
last_trade_activity_at.strftime("%b %Y")
end
end
def sorted_vaguely_by_trade_activity(trades)
# First, sort the list in ascending order.
trades_ascending = trades.sort_by do |trade|
if trade.user.last_trade_activity_at >= 1.week.ago
# Sort recent trades in a random order, but still collectively as the
# most recent. (This discourages spamming updates to game the system!)
[1, rand]
else
# Sort older trades by last trade activity.
[0, trade.user.last_trade_activity_at]
end
end
# Then, reverse it!
trades_ascending.reverse!
end
end

View file

@ -50,6 +50,10 @@ module ItemsHelper
content_tag :div, content, :class => 'closeted-icons'
end
def list_zones(zones, method=:label)
zones.map(&method).join(', ')
end
def nc_icon
image_tag 'nc.png', :title => t('items.item.nc.description'),
:alt => t('items.item.nc.abbr'), :class => 'nc-icon'
@ -79,6 +83,17 @@ module ItemsHelper
"https://www.neopets.com/genie.phtml?type=process_genie&criteria=exact&auctiongenie=#{CGI::escape item.name}"
end
def trading_users_header(owned, count)
ownership_key = owned ? 'owned' : 'wanted'
translate ".trading_users.header.#{ownership_key}", :count => count
end
def render_trading_users(owned)
@trading_users_by_owned[owned].map do |user|
link_to user.name, user_closet_hangers_path(user)
end.to_sentence.html_safe
end
def format_contribution_count(count)
" (&times;#{count})".html_safe if count > 1
end

View file

@ -13,3 +13,29 @@ ReactDOM.render(
</AppProvider>,
rootNode,
);
try {
const tradeHangers = document.querySelector("#trade-hangers");
const tradeSections = document.querySelectorAll("#trade-hangers p");
for (const section of tradeSections) {
const oneLine = parseFloat(getComputedStyle(section)['line-height']);
const maxHeight = Math.ceil(oneLine * 2);
if (section.clientHeight > maxHeight) {
section.style.maxHeight = `${maxHeight}px`;
section.setAttribute("data-overflows", "");
}
section.querySelector(".more")?.addEventListener("click", (event) => {
section.setAttribute("data-showing-more", "");
section.style.maxHeight = "none";
});
section.querySelector(".less")?.addEventListener("click", (event) => {
section.removeAttribute("data-showing-more");
section.style.maxHeight = `${maxHeight}px`;
});
}
} catch (error) {
console.error("Error applying trade list more/less toggle", error);
}

View file

@ -153,43 +153,6 @@ class ClosetHanger < ApplicationRecord
# If quantity is zero and there's no hanger, good. Do nothing.
end
# Use this with a scoped relation to convert it into a list of trades, e.g.
# `item.hangers.trading.to_trades`.
#
# A trade includes the user who's trading, and the available closet hangers
# (which you can use to get e.g. the list name).
#
# 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!
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!)
all_trading_hangers = trading.to_a
owned_hangers = all_trading_hangers.filter(&:owned?)
wanted_hangers = all_trading_hangers.filter(&:wanted?)
# Group first into offering vs seeking, then by user.
offering, seeking = [owned_hangers, wanted_hangers].map do |hangers|
hangers.group_by(&:user_id).map do |user_id, user_hangers|
Trade.new(user_id, user_hangers)
end
end
{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

View file

@ -87,13 +87,6 @@ class ClosetList < ApplicationRecord
end
end
def self.group_by_owned
h = all.group_by(&:hangers_owned?)
h[true] ||= []
h[false] ||= []
h
end
include VisibilityMethods
class Null

View file

@ -278,6 +278,17 @@ class Item < ApplicationRecord
write_attribute('species_support_ids', replacement)
end
def supported_species_ids
return Species.select([:id]).map(&:id) if modeled_body_ids.include?(0)
pet_types = PetType.where(:body_id => modeled_body_ids).select('DISTINCT species_id')
species_ids = pet_types.map(&:species_id)
# If there are multiple known supported species, it probably supports them
# all. (I've never heard of only a handful of species being supported :P)
species_ids.size >= 2 ? Species.select([:id]).map(&:id) : species_ids
end
def support_species?(species)
species_support_ids.blank? || species_support_ids.include?(species.id)
end

View file

@ -175,18 +175,6 @@ class User < ApplicationRecord
contact_neopets_connection.try(:neopets_username)
end
def item_quantities_for(item_id)
quantities = Hash.new(0)
hangers = closet_hangers.where(item_id: item_id).
select([:owned, :list_id, :quantity])
hangers.each do |hanger|
quantities[hanger.list_id || hanger.owned?] = hanger.quantity
end
quantities
end
def log_trade_activity
touch(:last_trade_activity_at)
end

View file

@ -1,36 +0,0 @@
- title t(".title.#{@type}")
- hide_title_header
= render partial: "items/item_header",
locals: {item: @item, trades: @item_trades,
current_subpage: "trades_#{@type}",
current_user_lists: @current_user_lists,
current_user_quantities: @current_user_quantities}
%h2.item-subpage-title= t(".title.#{@type}")
- if @trades.present?
%table.trades-table
%thead
%tr
%th= t(".table.headings.last_active")
%th= t(".table.headings.user.#{@type}")
%th= t(".table.headings.lists")
%tbody
- sorted_vaguely_by_trade_activity(@trades).each do |trade|
%tr
%td
= vague_trade_timestamp trade.user.last_trade_activity_at
%td= trade.user.name
%td
- if trade.lists.present?
%ul.trade-list-names
- trade.lists.each do |list|
%li= link_to list.name, user_closet_hangers_path(trade.user,
anchor: "closet-list-#{list.id}")
- else
= link_to t(".table.not_in_a_list.#{@type}"), user_closet_hangers_path(trade.user,
anchor: "closet-hangers-group-#{@type == :offering}"),
class: "not-in-a-list"
- else
%p= t(".no_trades_yet")

View file

@ -1,90 +0,0 @@
- raise ArgumentError unless defined? item
- raise ArgumentError unless defined? trades
- raise ArgumentError unless defined? current_user_lists
- raise ArgumentError unless defined? current_user_quantities
- raise ArgumentError unless defined? current_subpage
%header.item-header
.item-header-main
= image_tag item.thumbnail_url, class: 'item-thumbnail'
%h2.item-name= item.name
%nav.item-links
- if item.nc?
%abbr.item-kind{'data-type' => 'nc', title: t('items.show.item_kinds.nc.description')}
= t('items.show.item_kinds.nc.label')
- elsif item.pb?
%abbr.item-kind{'data-type' => 'pb', title: t('items.show.item_kinds.pb.description')}
= t('items.show.item_kinds.pb.label')
- else
%abbr.item-kind{'data-type' => 'np', title: t('items.show.item_kinds.np.description')}
= t('items.show.item_kinds.np.label')
= link_to t('items.show.resources.jn_items'), jn_items_url_for(item)
- if item.nc_trade_value
= link_to t('items.show.resources.owls', value: item.nc_trade_value.value_text),
"https://www.neopets.com/~owls",
title: nc_trade_value_updated_at_text(item.nc_trade_value)
- unless item.nc?
= link_to t('items.show.resources.shop_wizard'), shop_wizard_url_for(item)
= link_to t('items.show.resources.super_shop_wizard'), super_shop_wizard_url_for(item)
= link_to t('items.show.resources.trading_post'), trading_post_url_for(item)
= link_to t('items.show.resources.auction_genie'), auction_genie_url_for(item)
- if user_signed_in?
.user-lists-section
= link_to t('items.show.closet_hangers.button'),
user_closet_hangers_path(current_user),
class: 'dialog-opener'
%dialog
%h3
= t 'items.show.closet_hangers.header_html',
user_items_link: link_to(t('your_items'),
user_closet_hangers_path(current_user))
= form_tag update_quantities_user_item_closet_hangers_path(:user_id => current_user, :item_id => item), :method => :put do
.closet-hangers-ownership-groups
- current_user_lists.each do |owned, lists|
%div
%h4= closet_lists_group_name(:you, owned)
%ul
- lists.each_with_index do |list, index|
%li
= number_field_tag "quantity[#{list.id}]",
current_user_quantities[list.id], min: 0,
autofocus: owned && index == 0
= label_tag "quantity[#{list.id}]", list.name
%li
= number_field_tag "quantity[#{owned}]",
current_user_quantities[owned], min: 0,
autofocus: owned && lists.empty?
- unless lists.empty?
= label_tag "quantity[#{owned}]",
t('closet_lists.unlisted_name'),
:class => 'unlisted'
- else
= label_tag "quantity[#{owned}]",
t('items.show.closet_hangers.quantity_label')
= submit_tag t('items.show.closet_hangers.submit')
%p.item-description= item.description
%nav.item-subpages-nav
= link_to t('items.show.subpages_nav.preview'), item,
class: ['preview-link'], 'data-is-current' => current_subpage == 'preview'
.trades-section
%header= t('items.show.subpages_nav.trades.header')
%ul
%li
= link_to t('items.show.subpages_nav.trades.offering',
count: trades[:offering].size),
item_trades_path(item, type: 'offering'),
'data-is-current' => current_subpage == 'trades_offering'
%li
= link_to t('items.show.subpages_nav.trades.seeking',
count: trades[:offering].size),
item_trades_path(item, type: 'seeking'),
'data-is-current' => current_subpage == 'trades_seeking'
- content_for :javascripts do
= javascript_include_tag 'items/item_header'

View file

@ -1,10 +1,84 @@
- title @item.name
- canonical_path @item
= render partial: "item_header",
locals: {item: @item, trades: @trades, current_subpage: "preview",
current_user_lists: @current_user_lists,
current_user_quantities: @current_user_quantities}
%header#item-header
= image_tag @item.thumbnail_url, :id => 'item-thumbnail'
%h2#item-name= @item.name
%nav#item-links
= nc_icon_for(@item)
- unless @item.rarity.blank?
== #{t '.rarity'}: #{@item.rarity_index} (#{@item.rarity})
= link_to t('.resources.jn_items'), jn_items_url_for(@item)
- if @item.nc_trade_value
= link_to t('.resources.owls', value: @item.nc_trade_value.value_text),
"https://www.neopets.com/~owls",
title: nc_trade_value_updated_at_text(@item.nc_trade_value)
- unless @item.nc?
= link_to t('.resources.shop_wizard'), shop_wizard_url_for(@item)
= link_to t('.resources.super_shop_wizard'), super_shop_wizard_url_for(@item)
= link_to t('.resources.trading_post'), trading_post_url_for(@item)
= link_to t('.resources.auction_genie'), auction_genie_url_for(@item)
%section#item-info-section
#item-info
%p= @item.description
#item-zones
%p
%strong #{t '.zones.occupied_header'}:
= list_zones @occupied_zones, :uncertain_label
%p
%strong #{t '.zones.restricted_header'}:
- if @restricted_zones.empty?
= t '.zones.none'
- else
= list_zones @restricted_zones
#trade-hangers
- if Time.now < Date.new(2024, 1, 26)
%p
✨⏳️
%i We now only show recently-updated lists here!
⏳️✨
- [true, false].each do |owned|
%p
%strong
= trading_users_header(owned, @trading_users_by_owned[owned].size)
= render_trading_users(owned)
%span.toggle
%button.more= t '.trading_users.show_more'
%button.less= t '.trading_users.show_less'
- if user_signed_in?
#your-items-form
%h3
= t '.closet_hangers.header_html',
:user_items_link => link_to(t('your_items'),
user_closet_hangers_path(current_user))
= form_tag update_quantities_user_item_closet_hangers_path(:user_id => current_user, :item_id => @item), :method => :put do
#closet-hangers-ownership-groups
- @current_user_lists.each do |owned, lists|
%div
%h4= closet_lists_group_name(:you, owned)
%ul
- lists.each do |list|
%li
= number_field_tag "quantity[#{list.id}]",
@current_user_quantities[list.id], :min => 0
= label_tag "quantity[#{list.id}]", list.name
%li
= number_field_tag "quantity[#{owned}]",
@current_user_quantities[owned], :min => 0
- unless lists.empty?
= label_tag "quantity[#{owned}]",
t('closet_lists.unlisted_name'),
:class => 'unlisted'
- else
= label_tag "quantity[#{owned}]",
t('.closet_hangers.quantity_label')
= submit_tag t('.closet_hangers.submit')
#outfit-preview-root{'data-item-id': @item.id}

View file

@ -270,6 +270,7 @@ en-MEEP:
description: You want this meepit
show:
rarity: Meepity
resources:
jn_items: JN Meepits
shop_wizard: Meep Wizard
@ -284,6 +285,18 @@ en-MEEP:
occupied_header: Occupeeps
restricted_header: Restreeps
none: Meepless
trading_users:
header:
owned:
zero: We don't know anymeep who has this item meep for trade.
one: "1 user has this item meep for trade:"
other: "%{count} users have this item meep for trade:"
wanted:
zero: "We don't know anymeep who meeps this item."
one: "1 user meeps this item:"
other: "%{count} users meep this item:"
show_more: meep more
show_less: meep less
preview:
header: Meepview
customize_more: Customize meep

View file

@ -298,16 +298,7 @@ en:
description: You want this item
show:
item_kinds:
nc:
label: NC
description: Purchaseable with Neocash
np:
label: NP
description: Purchaseable with Neopoints
pb:
label: PB
description: Only obtainable via paintbrush
rarity: Rarity
resources:
jn_items: JN Items
owls: "Owls: %{value}"
@ -316,7 +307,6 @@ en:
trading_post: Trades
auction_genie: Auctions
closet_hangers:
button: Add to your lists
header_html: Track this in %{user_items_link}
quantity_label: How many?
submit: Save to Your Items
@ -324,12 +314,18 @@ en:
occupied_header: Occupies
restricted_header: Restricts
none: None
subpages_nav:
preview: Preview
trades:
header: Trades
offering: Offering (%{count})
seeking: Seeking (%{count})
trading_users:
header:
owned:
zero: We don't know anyone who has this item up for trade.
one: "1 user has this item up for trade:"
other: "%{count} users have this item up for trade:"
wanted:
zero: "We don't know anyone who wants this item."
one: "1 user wants this item:"
other: "%{count} users want this item:"
show_more: more
show_less: less
preview:
header: Preview
customize_more: Customize more
@ -373,27 +369,6 @@ 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
last_active:
this_week: This week
not_in_a_list:
offering: Items they own
seeking: Items they want
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!

View file

@ -209,6 +209,7 @@ es:
abbr: Buscado
description: Quieres este objeto
show:
rarity: Rareza
resources:
jn_items: Objetos de JN
shop_wizard: Asistente de Tiendas
@ -223,6 +224,18 @@ es:
occupied_header: Ocupa
restricted_header: Restringe
none: Nada
trading_users:
header:
owned:
zero: No conocemos a nadie que tenga este objeto para intercambiar.
one: "1 usuario tiene este objeto para intercambiar:"
other: "%{count} usuarios tienen este objeto para intercambiar:"
wanted:
zero: "No conocemos a nadie que busque este objeto."
one: "1 usuario busca este objeto:"
other: "%{count} usuarios buscan este objeto:"
show_more: más
show_less: menos
preview:
header: Previsualizar
customize_more: Personalizar más

View file

@ -209,6 +209,7 @@ pt:
abbr: Procura
description: Você procura esse item
show:
rarity: Raridade
resources:
jn_items: JN Itens
shop_wizard: Mágico Pecincheiro
@ -223,6 +224,18 @@ pt:
occupied_header: Ocupações
restricted_header: Restrições
none: Nada
trading_users:
header:
owned:
zero: Ninguém quer trocar esse item
one: "1 usuário quer trocar esse item:"
other: "%{count} usuários possuem, e querem trocar esse item:"
wanted:
zero: "Nós não conhecemos ninguém que procure esse item."
one: "1 usuário procura esse item:"
other: "%{count} usuários procuram esse item:"
show_more: mais
show_less: menos
preview:
header: Pré-Visualizar
customize_more: Personalize mais

View file

@ -18,11 +18,7 @@ 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