diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb
index 7ff867717..949360c32 100644
--- a/ruby/lib/jam_ruby/models/user.rb
+++ b/ruby/lib/jam_ruby/models/user.rb
@@ -102,6 +102,7 @@ module JamRuby
validates :first_name, presence: true, length: {maximum: 50}, no_profanity: true
validates :last_name, presence: true, length: {maximum: 50}, no_profanity: true
+ validates :biography, length: {maximum: 4000}, no_profanity: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}
validates :update_email, presence: true, format: {with: VALID_EMAIL_REGEX}, :if => :updating_email
diff --git a/web/app/assets/javascripts/jamkazam.js b/web/app/assets/javascripts/jamkazam.js
index 0a1771068..2d184efb6 100644
--- a/web/app/assets/javascripts/jamkazam.js
+++ b/web/app/assets/javascripts/jamkazam.js
@@ -232,7 +232,7 @@
}
}
else {
- logger.error("Unexpected ajax error: " + textStatus + ", msg:" + errorMessage);
+
app.notify({title: textStatus, text: errorMessage, detail: jqXHR.responseText});
}
}
@@ -293,6 +293,7 @@
if (jqXHR.status == 422) {
var errors = JSON.parse(jqXHR.responseText);
var $errors = context.JK.format_all_errors(errors);
+ console.log("$errors", $errors)
this.notify({title: title, text: $errors, icon_url: "/assets/content/icon_alert_big.png"})
}
else {
diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js
index 2b5a9d509..8924d9ae5 100644
--- a/web/app/assets/javascripts/profile.js
+++ b/web/app/assets/javascripts/profile.js
@@ -1,645 +1,709 @@
-(function(context,$) {
-
- "use strict";
-
- context.JK = context.JK || {};
- context.JK.ProfileScreen = function(app) {
- var logger = context.JK.logger;
- var userId;
- var user = null;
- var userDefer = null;
- var rest = context.JK.Rest();
- var decrementedFriendCountOnce = false;
- var sentFriendRequest = false;
-
- var instrument_logo_map = context.JK.getInstrumentIconMap24();
-
- var proficiencyDescriptionMap = {
- "1": "BEGINNER",
- "2": "INTERMEDIATE",
- "3": "EXPERT"
- };
-
- var proficiencyCssMap = {
- "1": "proficiency-beginner",
- "2": "proficiency-intermediate",
- "3": "proficiency-expert"
- };
-
- function beforeShow(data) {
- userId = data.id;
- }
-
- function afterShow(data) {
- initUser();
- resetForm();
- }
-
- function resetForm() {
- $('#profile-instruments').empty();
-
- $('#profile-about').show();
- $('#profile-history').hide();
- $('#profile-bands').hide();
- $('#profile-social').hide();
- $('#profile-favorites').hide();
-
- $('.profile-nav a.active').removeClass('active');
- $('.profile-nav a#profile-about-link').addClass('active');
- }
-
- function initUser() {
- user = null;
- decrementedFriendCountOnce = false;
- sentFriendRequest = false;
- userDefer = rest.getUserDetail({id: userId})
- .done(function(response) {
- user = response;
- configureUserType();
- renderActive();
- })
- .fail(function(jqXHR) {
- if(jqXHR.status >= 500) {
- context.JK.fetchUserNetworkOrServerFailure();
- }
- else if(jqXHR.status == 404) {
- context.JK.entityNotFound("User");
- }
- else {
- app.ajaxError(arguments);
- }
- });
- }
-
- function isMusician() {
- return user.musician;
- }
-
- function isCurrentUser() {
- return userId === context.JK.currentUserId;
- }
-
- function configureUserType() {
- if (isMusician()) {
- $('#profile-history-link').show();
- $('#profile-bands-link').show();
- $('#profile-instruments').show();
- $('#profile-session-stats').show();
- $('#profile-recording-stats').show();
- // $('#profile-following-stats').hide();
- // $('#profile-favorites-stats').hide();
- $('.profile-social-left').show();
- $('#profile-type-label').text('musician');
- $('#profile-location-label').text('Location');
- }
- else {
- $('#profile-history-link').hide();
- $('#profile-bands-link').hide();
- $('#profile-instruments').hide();
- $('#profile-session-stats').hide();
- $('#profile-recording-stats').hide();
- // $('#profile-following-stats').show();
- // $('#profile-favorites-stats').show();
- $('.profile-social-left').hide();
- $('#profile-type-label').text('fan');
- $('#profile-location-label').text('Presence');
- }
-
- if (isCurrentUser()) {
- $('#btn-profile-edit').show();
- $('#btn-add-friend').hide();
- $('#btn-follow-user').hide();
- }
- else {
- configureFriendFollowersControls();
-
- $('#btn-profile-edit').hide();
- $('#btn-add-friend').show();
- $('#btn-follow-user').show();
- }
- }
-
- function configureFriendFollowersControls() {
- // wire up Add Friend click
- configureFriendButton();
-
- // wire up Follow click
- configureFollowingButton();
- }
-
- /****************** MAIN PORTION OF SCREEN *****************/
- // events for main screen
- function events() {
- // wire up panel clicks -- these need to check deferred because they can't be hidden when in an invalid state
- $('#profile-about-link').click(function(){ renderTabDeferred(renderAbout)});
- $('#profile-history-link').click(function(){ renderTabDeferred(renderHistory)});
- $('#profile-bands-link').click(function(){ renderTabDeferred(renderBands)});
- $('#profile-social-link').click(function(){ renderTabDeferred(renderSocial)});
- $('#profile-favorites-link').click(function(){ renderTabDeferred(renderFavorites)});
-
- // this doesn't need deferred because it's only shown when valid
- $('#btn-add-friend').click(handleFriendChange);
- $('#btn-follow-user').click(handleFollowingChange);
- }
-
- function handleFriendChange(evt) {
- if(isFriend()) {
- removeFriend(evt);
- }
- else {
- sendFriendRequest(evt);
- }
- }
-
- function handleFollowingChange(evt) {
- if (isFollowing()) {
- removeFollowing(false, userId);
- }
- else {
- addFollowing();
- }
- }
-
- function sendFriendRequest(evt) {
- evt.stopPropagation();
- setFriend(true); // TODO: you aren't a friend yet. just a request to be one really there are 3 states here.
- sentFriendRequest = true;
- rest.sendFriendRequest(app, userId, friendRequestCallback);
- }
-
- function removeFriend(evt) {
- evt.stopPropagation();
-
- rest.removeFriend({friend_id: userId})
- .done(function() {
- updateFriendCount(-1);
- setFriend(false);
- configureFriendButton();
- })
- .fail(app.ajaxError);
- }
-
- function isFriend() {
- return user.is_friend;
- }
-
- function setFriend(isFriend) {
- user.is_friend = isFriend;
- }
-
- function friendRequestCallback() {
- configureFriendButton();
- }
-
- function configureFriendButton() {
- if (isFriend()) {
- $('#btn-add-friend').text('DISCONNECT');
- }
- else {
- $('#btn-add-friend').text('CONNECT');
- }
- }
-
- function addFollowing() {
-
- rest.addFollowing({user_id: userId})
- .done(function() {
- updateFollowingCount(1);
- setFollowing(true);
- configureFollowingButton();
- context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, isMusician() ? context.JK.GA.JKSocialTargets.musician : context.JK.GA.JKSocialTargets.fan);
- })
- .fail(app.ajaxError);
- }
-
- function removeFollowing(isBand, id) {
- rest.removeFollowing(id)
- .done(function() {
- if (!isBand) {
- updateFollowingCount(-1);
- setFollowing(false);
- configureFollowingButton();
- }
- else {
- updateBandFollowingCount(id, -1); // refresh stats
- configureBandFollowingButton(false, id);
- }
- })
- .fail(app.ajaxError);
- }
-
- function isFollowing() {
- return user.is_following;
- }
-
- function setFollowing(isFollowing) {
- user.is_following = isFollowing;
- }
-
- function configureFollowingButton() {
-
- if (isFollowing()) {
- $('#btn-follow-user').text('UNFOLLOW');
- }
- else {
- $('#btn-follow-user').text('FOLLOW');
- }
- }
-
- function configureEditProfileButton() {
- $('#btn-follow-user').click(addFollowing);
- }
-
- // refreshes the currently active tab
- function renderActive() {
- if ($('#profile-about-link').hasClass('active')) {
- renderAbout();
- }
- else if ($('#profile-history-link').hasClass('active')) {
- renderHistory();
- }
- else if ($('#profile-bands-link').hasClass('active')) {
- renderBands();
- }
- else if ($('#profile-social-link').hasClass('active')) {
- renderSocial();
- }
- else if ($('#profile-favorites-link').hasClass('active')) {
- renderFavorites();
- }
- }
-
- function renderTabDeferred(tabRenderer) {
- userDefer
- .done(function() {
- tabRenderer();
- })
- .fail(function() {
- // try again
- initUser();
- })
- }
-
- /****************** ABOUT TAB *****************/
- function renderAbout() {
- $('#profile-instruments').empty();
-
- $('#profile-about').show();
- $('#profile-history').hide();
- $('#profile-bands').hide();
- $('#profile-social').hide();
- $('#profile-favorites').hide();
-
- $('.profile-nav a.active').removeClass('active');
- $('.profile-nav a#profile-about-link').addClass('active');
-
- bindAbout();
- }
-
- function bindAbout() {
- $('#profile-instruments').empty();
-
- // name
- $('#profile-username').html(user.name);
-
- // avatar
- $('#profile-avatar').attr('src', context.JK.resolveAvatarUrl(user.photo_url));
-
- // instruments
- if (user.instruments) {
- for (var i=0; i < user.instruments.length; i++) {
- var instrument = user.instruments[i];
- var description = instrument.instrument_id;
- var proficiency = instrument.proficiency_level;
- var instrument_icon_url = context.JK.getInstrumentIcon45(description);
-
- // add instrument info to layout
- var template = $('#template-profile-instruments').html();
- var instrumentHtml = context.JK.fillTemplate(template, {
- instrument_logo_url: instrument_icon_url,
- instrument_description: description,
- proficiency_level: proficiencyDescriptionMap[proficiency],
- proficiency_level_css: proficiencyCssMap[proficiency]
- });
-
- $('#profile-instruments').append(instrumentHtml);
- }
- }
-
- // location
- $('#profile-location').html(user.location);
-
- // stats
- var text = user.friend_count > 1 || user.friend_count === 0 ? " Friends" : " Friend";
- $('#profile-friend-stats').html('' + user.friend_count + '' + text);
-
- text = user.follower_count > 1 || user.follower_count === 0 ? " Followers" : " Follower";
- $('#profile-follower-stats').html('' + user.follower_count + '' + text);
-
- if (isMusician()) {
- text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session";
- $('#profile-session-stats').html(user.session_count + text);
-
- text = user.recording_count > 1 || user.recording_count === 0 ? " Recordings" : " Recording";
- $('#profile-recording-stats').html(user.recording_count + text);
- } else {
- text = " Following";
- $('#profile-following-stats').html(user.following_count + text);
- text = user.favorite_count > 1 || user.favorite_count === 0 ? " Favorites" : " Favorite";
- $('#profile-favorite-stats').html(user.favorite_count + text);
- }
-
- $('#profile-biography').html(user.biography);
- }
-
- /****************** SOCIAL TAB *****************/
- function renderSocial() {
- $('#profile-social-friends').empty();
- $('#profile-social-followings').empty();
- $('#profile-social-followers').empty();
-
- $('#profile-about').hide();
- $('#profile-history').hide();
- $('#profile-bands').hide();
- $('#profile-social').show();
- $('#profile-favorites').hide();
-
- $('.profile-nav a.active').removeClass('active');
- $('.profile-nav a#profile-social-link').addClass('active');
-
- bindSocial();
- }
-
- function bindSocial() {
- if (isMusician()) {
- // FRIENDS
- rest.getFriends({id:userId})
- .done(function(response) {
- $.each(response, function(index, val) {
- var template = $('#template-profile-social').html();
- var friendHtml = context.JK.fillTemplate(template, {
- userId: val.id,
- hoverAction: val.musician ? "musician" : "fan",
- avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
- userName: val.name,
- location: val.location,
- type: "Friends"
- });
-
- $('#profile-social-friends').append(friendHtml);
- });
- context.JK.bindHoverEvents();
- })
- .fail(app.ajaxError)
- }
-
- rest.getFollowings({id: userId})
- .done(function(response) {
- $.each(response, function(index, val) {
- var template = $('#template-profile-social').html();
- var followingHtml = context.JK.fillTemplate(template, {
- userId: val.id,
- hoverAction: val.musician ? "musician" : "fan",
- avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
- userName: val.name,
- location: val.location
- });
-
- $('#profile-social-followings').append(followingHtml);
- });
- context.JK.bindHoverEvents();
- })
- .fail(app.ajaxError);
-
- rest.getFollowers({id: userId})
- .done(function(response) {
- $.each(response, function(index, val) {
- var template = $('#template-profile-social').html();
- var followerHtml = context.JK.fillTemplate(template, {
- userId: val.id,
- hoverAction: val.musician ? "musician" : "fan",
- avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
- userName: val.name,
- location: val.location
- });
-
- $('#profile-social-followers').append(followerHtml);
- });
- context.JK.bindHoverEvents();
- })
- .fail(app.ajaxError);
- }
-
- /****************** HISTORY TAB *****************/
- function renderHistory() {
- $('#profile-about').hide();
- $('#profile-history').show();
- $('#profile-bands').hide();
- $('#profile-social').hide();
- $('#profile-favorites').hide();
-
- $('.profile-nav a.active').removeClass('active');
- $('.profile-nav a#profile-history-link').addClass('active');
-
- bindHistory();
- }
-
- function bindHistory() {
-
- }
-
- /****************** BANDS TAB *****************/
- function renderBands() {
- $('#profile-bands').empty();
-
- $('#profile-about').hide();
- $('#profile-history').hide();
- $('#profile-bands').show();
- $('#profile-social').hide();
- $('#profile-favorites').hide();
-
- $('.profile-nav a.active').removeClass('active');
- $('.profile-nav a#profile-bands-link').addClass('active');
-
- bindBands();
- }
-
- function bindBands() {
-
- rest.getBands({id:userId})
- .done(function(response) {
- if ( (!response || response.length === 0) && isCurrentUser()) {
- var noBandHtml = $('#template-no-bands').html();
- $("#profile-bands").html(noBandHtml);
- }
- else {
- addMoreBandsLink();
-
- $.each(response, function(index, val) {
-
- // build band member HTML
- var musicianHtml = '';
- if (val.musicians) {
- for (var i=0; i < val.musicians.length; i++) {
- var musician = val.musicians[i];
- var instrumentLogoHtml = '';
- if (musician.instruments) {
- for (var j=0; j < musician.instruments.length; j++) {
- var instrument = musician.instruments[j];
- var inst = '/assets/content/icon_instrument_default24.png';
- if (instrument.instrument_id in instrument_logo_map) {
- inst = instrument_logo_map[instrument.instrument_id];
- }
- instrumentLogoHtml += ' ';
- }
- }
- // this template is in _findSession.html.erb
- var musicianTemplate = $('#template-musician-info').html();
- musicianHtml += context.JK.fillTemplate(musicianTemplate, {
- userId: musician.id,
- avatar_url: context.JK.resolveAvatarUrl(musician.photo_url),
- profile_url: "/client#/profile/" + musician.id,
- musician_name: musician.name,
- instruments: instrumentLogoHtml
- });
- }
- }
- var template = $('#template-profile-bands').html();
- var bandHtml = context.JK.fillTemplate(template, {
- bandId: val.id,
- biography: val.biography,
- band_url: "/client#/bandProfile/" + val.id,
- avatar_url: context.JK.resolveBandAvatarUrl(val.photo_url),
- name: val.name,
- location: val.location,
- genres: formatGenres(val.genres),
- follower_count: val.follower_count,
- recording_count: val.recording_count,
- session_count: val.session_count,
- musicians: musicianHtml
- });
-
- $('#profile-bands').append(bandHtml);
-
- // wire up Band Follow button click handler
- configureBandFollowingButton(val.is_following, val.id);
- });
-
- if(response.length >= 3) {
- addMoreBandsLink();
- }
- }
- context.JK.bindHoverEvents();
- })
- .fail(app.ajaxError);
- }
-
- function addMoreBandsLink() {
- if (isCurrentUser()) {
- var moreBandsHtml = $('#template-more-bands').html();
- $("#profile-bands").append(moreBandsHtml);
- }
- }
-
- function formatGenres(genres) {
- var formattedGenres = '';
- if (genres) {
- for (var i=0; i < genres.length; i++) {
- var genre = genres[i];
- formattedGenres += genre.description;
- if (i < genres.length -1) {
- formattedGenres += ', ';
- }
- }
- }
- return formattedGenres;
- }
-
- function updateFriendCount(value) {
- if(!decrementedFriendCountOnce && !sentFriendRequest) {
- decrementedFriendCountOnce = true;
- var friendCount = $('#profile-friend-stats span.friend-count');
- friendCount.text(value + parseInt(friendCount.text()));
- }
- }
-
- function updateFollowingCount(value) {
- var followingCount = $('#profile-follower-stats span.follower-count');
- followingCount.text(value + parseInt(followingCount.text()));
- }
-
- function updateBandFollowingCount(bandId, value) {
- var bandFollowing = $('div[band-id="' + bandId + '"].profile-bands span.follower-count');
- bandFollowing.text(value + parseInt(bandFollowing.text()));
- }
-
- function addBandFollowing(evt) {
- evt.stopPropagation();
- var bandId = $(this).parent().parent().parent().parent().attr('band-id');
-
- var newFollowing = {};
- newFollowing.band_id = bandId;
-
- rest.addFollowing(newFollowing)
- .done(function(response) {
- logger.debug("following band " + bandId);
- updateBandFollowingCount(bandId, 1); // increase counter
- configureBandFollowingButton(true, bandId);
- context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, context.JK.GA.JKSocialTargets.band);
- })
- .fail(app.ajaxError);
- }
-
- function configureBandFollowingButton(following, bandId) {
- var $btnFollowBand = $('div[band-id=' + bandId + ']', '#profile-bands').find('#btn-follow-band-2');
- $btnFollowBand.unbind("click");
-
- if (following) {
- $btnFollowBand.text('UN-FOLLOW');
- $btnFollowBand.click(function(evt) {
- removeFollowing(true, bandId);
- evt.stopPropagation();
- return false;
- });
- }
- else {
- $btnFollowBand.text('FOLLOW');
- $btnFollowBand.click(addBandFollowing);
- }
- }
-
- /****************** FAVORITES TAB *****************/
- function renderFavorites() {
- $('#profile-about').hide();
- $('#profile-history').hide();
- $('#profile-bands').hide();
- $('#profile-social').hide();
- $('#profile-favorites').show();
-
- $('.profile-nav a.active').removeClass('active');
- $('.profile-nav a#profile-favorites-link').addClass('active');
-
- bindFavorites();
- }
-
-
- function bindFavorites() {
- }
-
- function initialize() {
- var screenBindings = {
- 'beforeShow': beforeShow,
- 'afterShow': afterShow
- };
- app.bindScreen('profile', screenBindings);
-
- events();
- }
-
- this.initialize = initialize;
- this.beforeShow = beforeShow;
- this.afterShow = afterShow;
- return this;
+(function (context, $) {
+
+ "use strict";
+
+ context.JK = context.JK || {};
+ context.JK.ProfileScreen = function (app) {
+ var logger = context.JK.logger;
+ var userId;
+ var user = null;
+ var userDefer = null;
+ var rest = context.JK.Rest();
+ var decrementedFriendCountOnce = false;
+ var sentFriendRequest = false;
+
+ var instrument_logo_map = context.JK.getInstrumentIconMap24();
+
+ var proficiencyDescriptionMap = {
+ "1": "BEGINNER",
+ "2": "INTERMEDIATE",
+ "3": "EXPERT"
};
- })(window,jQuery);
\ No newline at end of file
+ var proficiencyCssMap = {
+ "1": "proficiency-beginner",
+ "2": "proficiency-intermediate",
+ "3": "proficiency-expert"
+ };
+
+ function beforeShow(data) {
+ userId = data.id;
+ }
+
+ function afterShow(data) {
+ initUser();
+ resetForm();
+ }
+
+ function resetForm() {
+ $('#profile-instruments').empty();
+
+ $('#profile-about').show();
+ $('#profile-history').hide();
+ $('#profile-bands').hide();
+ $('#profile-social').hide();
+ $('#profile-favorites').hide();
+
+ $('.profile-nav a.active').removeClass('active');
+ $('.profile-nav a#profile-about-link').addClass('active');
+ }
+
+ function initUser() {
+ user = null;
+ decrementedFriendCountOnce = false;
+ sentFriendRequest = false;
+ userDefer = rest.getUserDetail({id: userId})
+ .done(function (response) {
+ user = response;
+ configureUserType();
+ renderActive();
+ })
+ .fail(function (jqXHR) {
+ if (jqXHR.status >= 500) {
+ context.JK.fetchUserNetworkOrServerFailure();
+ }
+ else if (jqXHR.status == 404) {
+ context.JK.entityNotFound("User");
+ }
+ else {
+ app.ajaxError(arguments);
+ }
+ });
+ }
+
+ function isMusician() {
+ return user.musician;
+ }
+
+ function isCurrentUser() {
+ return userId === context.JK.currentUserId;
+ }
+
+ function configureUserType() {
+ if (isMusician()) {
+ $('#profile-history-link').show();
+ $('#profile-bands-link').show();
+ $('#profile-instruments').show();
+ $('#profile-session-stats').show();
+ $('#profile-recording-stats').show();
+ // $('#profile-following-stats').hide();
+ // $('#profile-favorites-stats').hide();
+ $('.profile-social-left').show();
+ $('#profile-type-label').text('musician');
+ $('#profile-location-label').text('Location');
+ }
+ else {
+ $('#profile-history-link').hide();
+ $('#profile-bands-link').hide();
+ $('#profile-instruments').hide();
+ $('#profile-session-stats').hide();
+ $('#profile-recording-stats').hide();
+ // $('#profile-following-stats').show();
+ // $('#profile-favorites-stats').show();
+ $('.profile-social-left').hide();
+ $('#profile-type-label').text('fan');
+ $('#profile-location-label').text('Presence');
+ }
+
+ if (isCurrentUser()) {
+ $('#btn-profile-edit').show();
+ $('#btn-add-friend').hide();
+ $('#btn-follow-user').hide();
+ }
+ else {
+ configureFriendFollowersControls();
+
+ $('#btn-profile-edit').hide();
+ $('#btn-add-friend').show();
+ $('#btn-follow-user').show();
+ }
+ }
+
+ function configureFriendFollowersControls() {
+ // wire up Add Friend click
+ configureFriendButton();
+
+ // wire up Follow click
+ configureFollowingButton();
+ }
+
+ /****************** MAIN PORTION OF SCREEN *****************/
+ // events for main screen
+ function events() {
+ // wire up panel clicks -- these need to check deferred because they can't be hidden when in an invalid state
+ $('#profile-about-link').click(function () {
+ renderTabDeferred(renderAbout)
+ });
+ $('#profile-history-link').click(function () {
+ renderTabDeferred(renderHistory)
+ });
+ $('#profile-bands-link').click(function () {
+ renderTabDeferred(renderBands)
+ });
+ $('#profile-social-link').click(function () {
+ renderTabDeferred(renderSocial)
+ });
+ $('#profile-favorites-link').click(function () {
+ renderTabDeferred(renderFavorites)
+ });
+
+ // this doesn't need deferred because it's only shown when valid
+ $('#btn-add-friend').click(handleFriendChange);
+ $('#btn-follow-user').click(handleFollowingChange);
+ }
+
+ function handleFriendChange(evt) {
+ if (isFriend()) {
+ removeFriend(evt);
+ }
+ else {
+ sendFriendRequest(evt);
+ }
+ }
+
+ function handleFollowingChange(evt) {
+ if (isFollowing()) {
+ removeFollowing(false, userId);
+ }
+ else {
+ addFollowing();
+ }
+ }
+
+ function sendFriendRequest(evt) {
+ evt.stopPropagation();
+ setFriend(true); // TODO: you aren't a friend yet. just a request to be one really there are 3 states here.
+ sentFriendRequest = true;
+ rest.sendFriendRequest(app, userId, friendRequestCallback);
+ }
+
+ function removeFriend(evt) {
+ evt.stopPropagation();
+
+ rest.removeFriend({friend_id: userId})
+ .done(function () {
+ updateFriendCount(-1);
+ setFriend(false);
+ configureFriendButton();
+ })
+ .fail(app.ajaxError);
+ }
+
+ function isFriend() {
+ return user.is_friend;
+ }
+
+ function setFriend(isFriend) {
+ user.is_friend = isFriend;
+ }
+
+ function friendRequestCallback() {
+ configureFriendButton();
+ }
+
+ function configureFriendButton() {
+ if (isFriend()) {
+ $('#btn-add-friend').text('DISCONNECT');
+ }
+ else {
+ $('#btn-add-friend').text('CONNECT');
+ }
+ }
+
+ function addFollowing() {
+
+ rest.addFollowing({user_id: userId})
+ .done(function () {
+ updateFollowingCount(1);
+ setFollowing(true);
+ configureFollowingButton();
+ context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, isMusician() ? context.JK.GA.JKSocialTargets.musician : context.JK.GA.JKSocialTargets.fan);
+ })
+ .fail(app.ajaxError);
+ }
+
+ function removeFollowing(isBand, id) {
+ rest.removeFollowing(id)
+ .done(function () {
+ if (!isBand) {
+ updateFollowingCount(-1);
+ setFollowing(false);
+ configureFollowingButton();
+ }
+ else {
+ updateBandFollowingCount(id, -1); // refresh stats
+ configureBandFollowingButton(false, id);
+ }
+ })
+ .fail(app.ajaxError);
+ }
+
+ function isFollowing() {
+ return user.is_following;
+ }
+
+ function setFollowing(isFollowing) {
+ user.is_following = isFollowing;
+ }
+
+ function configureFollowingButton() {
+
+ if (isFollowing()) {
+ $('#btn-follow-user').text('UNFOLLOW');
+ }
+ else {
+ $('#btn-follow-user').text('FOLLOW');
+ }
+ }
+
+ function configureEditProfileButton() {
+ $('#btn-follow-user').click(addFollowing);
+ }
+
+ // refreshes the currently active tab
+ function renderActive() {
+ if ($('#profile-about-link').hasClass('active')) {
+ renderAbout();
+ }
+ else if ($('#profile-history-link').hasClass('active')) {
+ renderHistory();
+ }
+ else if ($('#profile-bands-link').hasClass('active')) {
+ renderBands();
+ }
+ else if ($('#profile-social-link').hasClass('active')) {
+ renderSocial();
+ }
+ else if ($('#profile-favorites-link').hasClass('active')) {
+ renderFavorites();
+ }
+ }
+
+ function renderTabDeferred(tabRenderer) {
+ userDefer
+ .done(function () {
+ tabRenderer();
+ })
+ .fail(function () {
+ // try again
+ initUser();
+ })
+ }
+
+ /****************** ABOUT TAB *****************/
+ function renderAbout() {
+ $('#profile-instruments').empty();
+
+ $('#profile-about').show();
+ $('#profile-history').hide();
+ $('#profile-bands').hide();
+ $('#profile-social').hide();
+ $('#profile-favorites').hide();
+
+ $('.profile-nav a.active').removeClass('active');
+ $('.profile-nav a#profile-about-link').addClass('active');
+
+ bindAbout();
+ }
+
+ function bindAbout() {
+ $('#profile-instruments').empty();
+
+ // name
+ $('#profile-username').html(user.name);
+
+ // avatar
+ $('#profile-avatar').attr('src', context.JK.resolveAvatarUrl(user.photo_url));
+
+ // instruments
+ if (user.instruments) {
+ for (var i = 0; i < user.instruments.length; i++) {
+ var instrument = user.instruments[i];
+ var description = instrument.instrument_id;
+ var proficiency = instrument.proficiency_level;
+ var instrument_icon_url = context.JK.getInstrumentIcon45(description);
+
+ // add instrument info to layout
+ var template = $('#template-profile-instruments').html();
+ var instrumentHtml = context.JK.fillTemplate(template, {
+ instrument_logo_url: instrument_icon_url,
+ instrument_description: description,
+ proficiency_level: proficiencyDescriptionMap[proficiency],
+ proficiency_level_css: proficiencyCssMap[proficiency]
+ });
+
+ $('#profile-instruments').append(instrumentHtml);
+ }
+ }
+
+ // location
+ $('#profile-location').html(user.location);
+
+ // stats
+ var text = user.friend_count > 1 || user.friend_count === 0 ? " Friends" : " Friend";
+ $('#profile-friend-stats').html('' + user.friend_count + '' + text);
+
+ text = user.follower_count > 1 || user.follower_count === 0 ? " Followers" : " Follower";
+ $('#profile-follower-stats').html('' + user.follower_count + '' + text);
+
+ if (isMusician()) {
+ text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session";
+ $('#profile-session-stats').html(user.session_count + text);
+
+ text = user.recording_count > 1 || user.recording_count === 0 ? " Recordings" : " Recording";
+ $('#profile-recording-stats').html(user.recording_count + text);
+ } else {
+ text = " Following";
+ $('#profile-following-stats').html(user.following_count + text);
+ text = user.favorite_count > 1 || user.favorite_count === 0 ? " Favorites" : " Favorite";
+ $('#profile-favorite-stats').html(user.favorite_count + text);
+ }
+
+ if(isCurrentUser) {
+ if(user.biography) {
+ $('#profile-biography').text(user.biography);
+ }
+ else {
+ var createBio = $(context._.template($('#template-add-user-profile').html(), {}, { variable: 'data' }));
+ $('a.enter-bio', createBio).click(function() {
+ $('.update-biography').show();
+ return false;
+ });
+
+ $('#btn-update-user-biography', createBio).click(function() {
+ var $bio = $('#profile-biography .user-biography');
+ var bio = $bio.val();
+ $bio.closest('div.field').removeClass('error');
+ $('.error-text', $bio.closest('div.field')).remove();
+ rest.updateUser({
+ biography: bio
+ })
+ .done(function(response) {
+ if(response.biography){
+ $('#profile-biography').text(response.biography);
+ } else {
+ $('.update-biography').hide();
+ }
+ })
+ .fail(function(jqXHR) {
+ if(jqXHR.status == 422) {
+ var errors = JSON.parse(jqXHR.responseText)
+ var biography = context.JK.format_errors("biography", errors);
+ if(biography != null) {
+ $bio.closest('div.field').addClass('error').end().after(biography);
+ }
+ else {
+ app.notifyServerError(jqXHR, "Unable to update biography")
+ }
+ }
+ else {
+ app.notifyServerError(jqXHR, "Unable to update biography")
+ }
+ })
+ return false;
+ });
+
+ $('#btn-cancel-user-biography', createBio).click(function() {
+ $('.update-biography').hide();
+ return false;
+ });
+ $('#profile-biography').html(createBio);
+ }
+ }
+ else {
+ $('#profile-biography').text(user.biography);
+ }
+
+ }
+
+ /****************** SOCIAL TAB *****************/
+ function renderSocial() {
+ $('#profile-social-friends').empty();
+ $('#profile-social-followings').empty();
+ $('#profile-social-followers').empty();
+
+ $('#profile-about').hide();
+ $('#profile-history').hide();
+ $('#profile-bands').hide();
+ $('#profile-social').show();
+ $('#profile-favorites').hide();
+
+ $('.profile-nav a.active').removeClass('active');
+ $('.profile-nav a#profile-social-link').addClass('active');
+
+ bindSocial();
+ }
+
+ function bindSocial() {
+ if (isMusician()) {
+ // FRIENDS
+ rest.getFriends({id: userId})
+ .done(function (response) {
+ $.each(response, function (index, val) {
+ var template = $('#template-profile-social').html();
+ var friendHtml = context.JK.fillTemplate(template, {
+ userId: val.id,
+ hoverAction: val.musician ? "musician" : "fan",
+ avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
+ userName: val.name,
+ location: val.location,
+ type: "Friends"
+ });
+
+ $('#profile-social-friends').append(friendHtml);
+ });
+ context.JK.bindHoverEvents();
+ })
+ .fail(app.ajaxError)
+ }
+
+ rest.getFollowings({id: userId})
+ .done(function (response) {
+ $.each(response, function (index, val) {
+ var template = $('#template-profile-social').html();
+ var followingHtml = context.JK.fillTemplate(template, {
+ userId: val.id,
+ hoverAction: val.musician ? "musician" : "fan",
+ avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
+ userName: val.name,
+ location: val.location
+ });
+
+ $('#profile-social-followings').append(followingHtml);
+ });
+ context.JK.bindHoverEvents();
+ })
+ .fail(app.ajaxError);
+
+ rest.getFollowers({id: userId})
+ .done(function (response) {
+ $.each(response, function (index, val) {
+ var template = $('#template-profile-social').html();
+ var followerHtml = context.JK.fillTemplate(template, {
+ userId: val.id,
+ hoverAction: val.musician ? "musician" : "fan",
+ avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
+ userName: val.name,
+ location: val.location
+ });
+
+ $('#profile-social-followers').append(followerHtml);
+ });
+ context.JK.bindHoverEvents();
+ })
+ .fail(app.ajaxError);
+ }
+
+ /****************** HISTORY TAB *****************/
+ function renderHistory() {
+ $('#profile-about').hide();
+ $('#profile-history').show();
+ $('#profile-bands').hide();
+ $('#profile-social').hide();
+ $('#profile-favorites').hide();
+
+ $('.profile-nav a.active').removeClass('active');
+ $('.profile-nav a#profile-history-link').addClass('active');
+
+ bindHistory();
+ }
+
+ function bindHistory() {
+
+ }
+
+ /****************** BANDS TAB *****************/
+ function renderBands() {
+ $('#profile-bands').empty();
+
+ $('#profile-about').hide();
+ $('#profile-history').hide();
+ $('#profile-bands').show();
+ $('#profile-social').hide();
+ $('#profile-favorites').hide();
+
+ $('.profile-nav a.active').removeClass('active');
+ $('.profile-nav a#profile-bands-link').addClass('active');
+
+ bindBands();
+ }
+
+ function bindBands() {
+
+ rest.getBands({id: userId})
+ .done(function (response) {
+ if ((!response || response.length === 0) && isCurrentUser()) {
+ var noBandHtml = $('#template-no-bands').html();
+ $("#profile-bands").html(noBandHtml);
+ }
+ else {
+ addMoreBandsLink();
+
+ $.each(response, function (index, val) {
+
+ // build band member HTML
+ var musicianHtml = '';
+ if (val.musicians) {
+ for (var i = 0; i < val.musicians.length; i++) {
+ var musician = val.musicians[i];
+ var instrumentLogoHtml = '';
+ if (musician.instruments) {
+ for (var j = 0; j < musician.instruments.length; j++) {
+ var instrument = musician.instruments[j];
+ var inst = '/assets/content/icon_instrument_default24.png';
+ if (instrument.instrument_id in instrument_logo_map) {
+ inst = instrument_logo_map[instrument.instrument_id];
+ }
+ instrumentLogoHtml += '
';
+ }
+ }
+ // this template is in _findSession.html.erb
+ var musicianTemplate = $('#template-musician-info').html();
+ musicianHtml += context.JK.fillTemplate(musicianTemplate, {
+ userId: musician.id,
+ avatar_url: context.JK.resolveAvatarUrl(musician.photo_url),
+ profile_url: "/client#/profile/" + musician.id,
+ musician_name: musician.name,
+ instruments: instrumentLogoHtml
+ });
+ }
+ }
+ var template = $('#template-profile-bands').html();
+ var bandHtml = context.JK.fillTemplate(template, {
+ bandId: val.id,
+ biography: val.biography,
+ band_url: "/client#/bandProfile/" + val.id,
+ avatar_url: context.JK.resolveBandAvatarUrl(val.photo_url),
+ name: val.name,
+ location: val.location,
+ genres: formatGenres(val.genres),
+ follower_count: val.follower_count,
+ recording_count: val.recording_count,
+ session_count: val.session_count,
+ musicians: musicianHtml
+ });
+
+ $('#profile-bands').append(bandHtml);
+
+ // wire up Band Follow button click handler
+ configureBandFollowingButton(val.is_following, val.id);
+ });
+
+ if (response.length >= 3) {
+ addMoreBandsLink();
+ }
+ }
+ context.JK.bindHoverEvents();
+ })
+ .fail(app.ajaxError);
+ }
+
+ function addMoreBandsLink() {
+ if (isCurrentUser()) {
+ var moreBandsHtml = $('#template-more-bands').html();
+ $("#profile-bands").append(moreBandsHtml);
+ }
+ }
+
+ function formatGenres(genres) {
+ var formattedGenres = '';
+ if (genres) {
+ for (var i = 0; i < genres.length; i++) {
+ var genre = genres[i];
+ formattedGenres += genre.description;
+ if (i < genres.length - 1) {
+ formattedGenres += ', ';
+ }
+ }
+ }
+ return formattedGenres;
+ }
+
+ function updateFriendCount(value) {
+ if (!decrementedFriendCountOnce && !sentFriendRequest) {
+ decrementedFriendCountOnce = true;
+ var friendCount = $('#profile-friend-stats span.friend-count');
+ friendCount.text(value + parseInt(friendCount.text()));
+ }
+ }
+
+ function updateFollowingCount(value) {
+ var followingCount = $('#profile-follower-stats span.follower-count');
+ followingCount.text(value + parseInt(followingCount.text()));
+ }
+
+ function updateBandFollowingCount(bandId, value) {
+ var bandFollowing = $('div[band-id="' + bandId + '"].profile-bands span.follower-count');
+ bandFollowing.text(value + parseInt(bandFollowing.text()));
+ }
+
+ function addBandFollowing(evt) {
+ evt.stopPropagation();
+ var bandId = $(this).parent().parent().parent().parent().attr('band-id');
+
+ var newFollowing = {};
+ newFollowing.band_id = bandId;
+
+ rest.addFollowing(newFollowing)
+ .done(function (response) {
+ logger.debug("following band " + bandId);
+ updateBandFollowingCount(bandId, 1); // increase counter
+ configureBandFollowingButton(true, bandId);
+ context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, context.JK.GA.JKSocialTargets.band);
+ })
+ .fail(app.ajaxError);
+ }
+
+ function configureBandFollowingButton(following, bandId) {
+ var $btnFollowBand = $('div[band-id=' + bandId + ']', '#profile-bands').find('#btn-follow-band-2');
+ $btnFollowBand.unbind("click");
+
+ if (following) {
+ $btnFollowBand.text('UN-FOLLOW');
+ $btnFollowBand.click(function (evt) {
+ removeFollowing(true, bandId);
+ evt.stopPropagation();
+ return false;
+ });
+ }
+ else {
+ $btnFollowBand.text('FOLLOW');
+ $btnFollowBand.click(addBandFollowing);
+ }
+ }
+
+ /****************** FAVORITES TAB *****************/
+ function renderFavorites() {
+ $('#profile-about').hide();
+ $('#profile-history').hide();
+ $('#profile-bands').hide();
+ $('#profile-social').hide();
+ $('#profile-favorites').show();
+
+ $('.profile-nav a.active').removeClass('active');
+ $('.profile-nav a#profile-favorites-link').addClass('active');
+
+ bindFavorites();
+ }
+
+
+ function bindFavorites() {
+ }
+
+ function initialize() {
+ var screenBindings = {
+ 'beforeShow': beforeShow,
+ 'afterShow': afterShow
+ };
+ app.bindScreen('profile', screenBindings);
+
+ events();
+ }
+
+ this.initialize = initialize;
+ this.beforeShow = beforeShow;
+ this.afterShow = afterShow;
+ return this;
+ };
+
+})(window, jQuery);
\ No newline at end of file
diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js
index 8af730244..e0cd22df3 100644
--- a/web/app/assets/javascripts/utils.js
+++ b/web/app/assets/javascripts/utils.js
@@ -239,11 +239,14 @@
});
}
+
// Uber-simple templating
// var template = "Hey {name}";
// var vals = { name: "Jon" };
// _fillTemplate(template, vals);
// --> "Hey Jon"
+ //
+ // use context._.template for something more powerful
context.JK.fillTemplate = function(template, vals) {
for(var val in vals)
template=template.replace(new RegExp('{'+val+'}','g'), vals[val]);
diff --git a/web/app/assets/stylesheets/client/profile.css.scss b/web/app/assets/stylesheets/client/profile.css.scss
index 7ea0f6f47..8a93e1872 100644
--- a/web/app/assets/stylesheets/client/profile.css.scss
+++ b/web/app/assets/stylesheets/client/profile.css.scss
@@ -1,5 +1,23 @@
@import "client/common.css.scss";
+#user-profile {
+ #profile-biography {
+ a.enter-bio {
+
+ }
+
+ textarea {
+ width:100%;
+ height:150px;
+ padding:0;
+ }
+
+ .update-biography {
+ display:none;
+ }
+ }
+}
+
.profile-head {
}
diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb
index 697bc2c95..031fe0eeb 100644
--- a/web/app/controllers/api_users_controller.rb
+++ b/web/app/controllers/api_users_controller.rb
@@ -43,7 +43,7 @@ class ApiUsersController < ApiController
@user.update_instruments(params[:instruments].nil? ? [] : params[:instruments]) if params.has_key?(:instruments)
@user.show_whats_next = params[:show_whats_next] if params.has_key?(:show_whats_next)
@user.subscribe_email = params[:subscribe_email] if params.has_key?(:subscribe_email)
-
+ @user.biography = params[:biography] if params.has_key?(:biography)
@user.save
if @user.errors.any?
diff --git a/web/app/views/clients/_profile.html.erb b/web/app/views/clients/_profile.html.erb
index ae2fba720..908b44667 100644
--- a/web/app/views/clients/_profile.html.erb
+++ b/web/app/views/clients/_profile.html.erb
@@ -1,5 +1,5 @@
-