diff --git a/app/assets/javascripts/modeling.js.jsx b/app/assets/javascripts/modeling.js.jsx index 267f1e47..c8b0770d 100644 --- a/app/assets/javascripts/modeling.js.jsx +++ b/app/assets/javascripts/modeling.js.jsx @@ -54,11 +54,40 @@ } }; + var ImpressUser = (function() { + var userSignedIn = ($('meta[name=user-signed-in]').attr('content') === 'true'); + if (userSignedIn) { + return { + // TODO + }; + } else { + return { + _key: "guestNeopetsUsernames", + _setNeopetsUsernames: function(usernames) { + localStorage.setItem(this._key, JSON.stringify(usernames)); + }, + addNeopetsUsername: function(username) { + this._setNeopetsUsernames(this.getNeopetsUsernames().concat([username])); + }, + removeNeopetsUsername: function(username) { + this._setNeopetsUsernames(this.getNeopetsUsernames().filter(function(u) { + return u !== username; + })); + }, + getNeopetsUsernames: function() { + return JSON.parse(localStorage.getItem(this._key)) || []; + } + }; + } + })(); + var Modeling = { _customizationsByPetId: {}, _customizations: [], _itemsById: {}, _items: [], + _usersComponent: {setState: function() {}}, + _neopetsUsernamesPresenceMap: {}, _addCustomization: function(customization) { // Set all equipped, interesting items' statuses as success and cross // them off the list. @@ -78,7 +107,7 @@ }); this._customizationsByPetId[customization.custom_pet.name] = customization; this._customizations = this._buildCustomizations(); - this._update(); + this._updateCustomizations(); }, _addNewCustomization: function(customization) { customization.loadingForItemId = null; @@ -127,37 +156,42 @@ console.error("couldn't load user %s's customizations", neopiaUserId); }); }, - _loadManyUsersCustomizations: function(neopiaUserIds) { - return neopiaUserIds.map(this._loadUserCustomizations.bind(this)); - }, _startLoading: function(neopiaPetId, itemId) { var customization = this._customizationsByPetId[neopiaPetId]; customization.loadingForItemId = itemId; customization.statusByItemId[itemId] = "loading"; - this._update(); + this._updateCustomizations(); }, _stopLoading: function(neopiaPetId, itemId, status) { var customization = this._customizationsByPetId[neopiaPetId]; customization.loadingForItemId = null; customization.statusByItemId[itemId] = status; - this._update(); + this._updateCustomizations(); }, - _update: function() { - var customizations = this._customizations; + _updateCustomizations: function() { + var neopetsUsernamesPresenceMap = this._neopetsUsernamesPresenceMap; + var liveCustomizations = this._customizations.filter(function(c) { + return neopetsUsernamesPresenceMap[c.custom_pet.owner]; + }); this._items.forEach(function(item) { - var filteredCustomizations = customizations.filter(function(c) { + var filteredCustomizations = liveCustomizations.filter(function(c) { return item.missingBodyIdsPresenceMap[c.custom_pet.body_id]; }); item.component.setState({customizations: filteredCustomizations}); }); }, + _updateUsernames: function() { + var usernames = Object.keys(this._neopetsUsernamesPresenceMap); + this._usersComponent.setState({usernames: usernames}); + }, init: function($) { Neopia.init(); this._createItems($); - // TODO: use user prefs, silly! - var search = document.location.search; - var users = search.indexOf('=') >= 0 ? search.split('=')[1].split(',') : ''; - this._loadManyUsersCustomizations(users); + var usersEl = $('#modeling-neopets-users'); + this._usersComponent = React.renderComponent(, + usersEl.get(0)); + var usernames = ImpressUser.getNeopetsUsernames(); + usernames.forEach(this.addUsername.bind(this)); }, model: function(neopiaPetId, itemId) { var oldCustomization = this._customizationsByPetId[neopiaPetId]; @@ -181,6 +215,22 @@ .fail(function() { Modeling._stopLoading(neopiaPetId, itemId, "error"); }); + }, + addUsername: function(username) { + if (typeof this._neopetsUsernamesPresenceMap[username] === 'undefined') { + this._neopetsUsernamesPresenceMap[username] = true; + ImpressUser.addNeopetsUsername(username); + this._loadUserCustomizations(username); + this._updateUsernames(); + } + }, + removeUsername: function(username) { + if (this._neopetsUsernamesPresenceMap[username]) { + delete this._neopetsUsernamesPresenceMap[username]; + ImpressUser.removeNeopetsUsername(username); + this._updateCustomizations(); + this._updateUsernames(); + } } }; @@ -195,7 +245,7 @@ item={item} key={customization.custom_pet.name} />; } - var sortedCustomizations = this.state.customizations.sort(function(a, b) { + var sortedCustomizations = this.state.customizations.slice(0).sort(function(a, b) { var aName = a.custom_pet.name.toLowerCase(); var bName = b.custom_pet.name.toLowerCase(); if (aName < bName) return -1; @@ -243,5 +293,43 @@ } }); + var NeopetsUsernamesForm = React.createClass({ + getInitialState: function() { + return {usernames: [], newUsername: ""}; + }, + render: function() { + function buildUsernameItem(username) { + return ; + } + return
+
    {this.state.usernames.slice(0).sort().map(buildUsernameItem)}
+
+ +
; + }, + handleChange: function(e) { + this.setState({newUsername: e.target.value}); + }, + handleSubmit: function(e) { + e.preventDefault(); + this.state.newUsername = $.trim(this.state.newUsername); + if (this.state.newUsername.length) { + Modeling.addUsername(this.state.newUsername); + this.setState({newUsername: ""}); + } + } + }); + + var NeopetsUsernameItem = React.createClass({ + render: function() { + return
  • {this.props.username}
  • + }, + handleClick: function(e) { + Modeling.removeUsername(this.props.username); + } + }); + Modeling.init($); })(jQuery); diff --git a/app/assets/stylesheets/outfits/_new.sass b/app/assets/stylesheets/outfits/_new.sass index 5574a83a..9a4b7879 100644 --- a/app/assets/stylesheets/outfits/_new.sass +++ b/app/assets/stylesheets/outfits/_new.sass @@ -144,24 +144,29 @@ body.outfits-new font-style: italic margin-bottom: .5em - #newest-modeled-items - text-align: center + #modeling-neopets-users + float: right + font-size: 85% + margin-top: -5px + max-width: 55% + text-align: right - .object - margin: 2px - padding: 0 - width: 80px + ul, li, form + display: inline-block - .name - display: none + li + +border-radius(6px) + border: 1px solid $soft-border-color + line-height: 1 + margin: 0 4px + padding: 2px 4px 2px 8px - img - margin: 0 + button + +reset-awesome-button + margin-left: 6px - .nc-icon - right: 0 - #newest-unmodeled-items + clear: both list-style: none > li @@ -264,7 +269,24 @@ body.outfits-new .message font-style: italic font-size: 85% - + + #newest-modeled-items + text-align: center + + .object + margin: 2px + padding: 0 + width: 80px + + .name + display: none + + img + margin: 0 + + .nc-icon + right: 0 + #latest-contribution +subtle-banner diff --git a/app/controllers/outfits_controller.rb b/app/controllers/outfits_controller.rb index 359d5bca..a397e24d 100644 --- a/app/controllers/outfits_controller.rb +++ b/app/controllers/outfits_controller.rb @@ -75,6 +75,8 @@ class OutfitsController < ApplicationController @latest_contribution = Contribution.recent.first Contribution.preload_contributeds_and_parents([@latest_contribution]) end + + @neopets_usernames = user_signed_in? ? current_user.neopets_usernames : [] end def show diff --git a/app/models/user.rb b/app/models/user.rb index b6bd3707..4775a828 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -89,6 +89,10 @@ class User < ActiveRecord::Base owned ? ClosetList::NullOwned.new(self) : ClosetList::NullWanted.new(self) end + def neopets_usernames + [neopets_username] + end + def self.find_or_create_from_remote_auth_data(user_data) user = find_or_initialize_by_remote_id_and_auth_server_id( user_data['id'], diff --git a/app/views/outfits/new.html.haml b/app/views/outfits/new.html.haml index 7ed53a58..e7feb3a6 100644 --- a/app/views/outfits/new.html.haml +++ b/app/views/outfits/new.html.haml @@ -76,6 +76,7 @@ -# TODO: i18n all the things -# TODO: cache this entire block? or just request newest items every time? - if @newest_unmodeled_items.present? + #modeling-neopets-users{'data-usernames' => @neopets_usernames.to_json} %h3= t '.newest_items.unmodeled.header' %ul#newest-unmodeled-items - @newest_unmodeled_items.each do |item|